Skip to content

GORM JSONArrayQuery.Contains isn't compatible #1855

@ns-kliu

Description

@ns-kliu

Hello, I found a weird issue when using GROM datatypes.JSONArrayQuery.Contains to access in-memory go-mysql-server, please see the below example or check my repo
I test 3 statements, their SQL query is the same, but only 1 works as expected.

I also test

  • Connect to a real MySQL or MariaDB instance, and all 3 statements can work
  • Use MySQL CLI to connect in-memory go-mysql-server and run the same query, that can work.
package main

import (
	"fmt"
	sqle "github.com/dolthub/go-mysql-server"
	"github.com/dolthub/go-mysql-server/memory"
	"github.com/dolthub/go-mysql-server/server"
	"gorm.io/datatypes"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"time"
)

var (
	_dbName    = "mydb"
	_dbUser    = "root"
	_dbAddress = "localhost"
	_dbPort    = 3306

	_dbConn *gorm.DB
)

type User struct {
	ID        uint
	Name      string
	Languages datatypes.JSONSlice[string]
}

func main() {
	var err error

	initMemoryMySQL()
	dsn := fmt.Sprintf("%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", _dbUser, _dbAddress, _dbPort, _dbName)
	if _dbConn, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
		Logger: logger.Default.LogMode(logger.Info),
	}); err != nil {
		panic(err)
	}

	if err = _dbConn.AutoMigrate(&User{}); err != nil {
		panic(err)
	}

	_dbConn.Create(&User{Name: "Tom", Languages: []string{"ZH", "EN"}})

	result := _dbConn.Where(datatypes.JSONArrayQuery("languages").Contains("ZH")).First(&User{})
	// MySQL:
	// SELECT * FROM `users` WHERE JSON_CONTAINS (`languages`, JSON_ARRAY('ZH')) ORDER BY `users`.`id` LIMIT 1
	fmt.Println(result.RowsAffected) // 0: record not found

	result = _dbConn.Raw("SELECT * FROM `users` WHERE JSON_CONTAINS (`languages`, JSON_ARRAY(?)) ORDER BY `users`.`id` LIMIT 1", "ZH").First(&User{})
	// MySQL:
	// SELECT * FROM `users` WHERE JSON_CONTAINS (`languages`, JSON_ARRAY('ZH')) ORDER BY `users`.`id` LIMIT 1
	fmt.Println(result.RowsAffected) // 0: record not found

	result = _dbConn.Where(fmt.Sprintf("JSON_CONTAINS (`languages`, JSON_ARRAY('%v'))", "ZH")).First(&User{})
	// MySQL:
	// SELECT * FROM `users` WHERE JSON_CONTAINS (`languages`, JSON_ARRAY('ZH')) ORDER BY `users`.`id` LIMIT 1
	fmt.Println(result.RowsAffected) // 1

	time.Sleep(10000000 * time.Second)
}

func initMemoryMySQL() {
	db := memory.NewDatabase(_dbName)
	db.EnablePrimaryKeyIndexes()
	engine := sqle.NewDefault(
		memory.NewDBProvider(db))
	engine.Analyzer.Catalog.MySQLDb.AddRootAccount()

	config := server.Config{
		Protocol: "tcp",
		Address:  fmt.Sprintf("%s:%d", _dbAddress, _dbPort),
	}

	s, err := server.NewDefaultServer(config, engine)
	if err != nil {
		panic(err)
	}

	go func() {
		if err = s.Start(); err != nil {
			panic(err)
		}
	}()
	time.Sleep(1 * time.Second)
}

Result:

2023/07/11 14:57:45 /Users/raymond_liu/Projects/go-mysql-issue/main.go:47 record not found
[1.108ms] [rows:0] SELECT * FROM `users` WHERE JSON_CONTAINS (`languages`, JSON_ARRAY('ZH')) ORDER BY `users`.`id` LIMIT 1
0

2023/07/11 14:57:45 /Users/raymond_liu/Projects/go-mysql-issue/main.go:52 record not found
[1.735ms] [rows:0] SELECT * FROM `users` WHERE JSON_CONTAINS (`languages`, JSON_ARRAY('ZH')) ORDER BY `users`.`id` LIMIT 1
0

2023/07/11 14:57:45 /Users/raymond_liu/Projects/go-mysql-issue/main.go:57
[0.560ms] [rows:1] SELECT * FROM `users` WHERE JSON_CONTAINS (`languages`, JSON_ARRAY('ZH')) ORDER BY `users`.`id` LIMIT 1
1

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions