From da6f1322059874454c7e6996f7b7971bd3c20339 Mon Sep 17 00:00:00 2001 From: "zhouyuhan.888" Date: Wed, 7 May 2025 16:59:43 +0800 Subject: [PATCH 1/4] Add a new field to indicate whether to perform a length comparison --- json.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/json.go b/json.go index 5f22956..ba20a7e 100644 --- a/json.go +++ b/json.go @@ -457,6 +457,10 @@ type JSONArrayExpression struct { column string keys []string equalsValue interface{} + // Add a new field to indicate whether to perform a length comparison + length bool + // Add a new field to store the expected length value + lengthValue int } // Contains checks if column[keys] contains the value given. The keys parameter is only supported for MySQL and SQLite. @@ -475,6 +479,13 @@ func (json *JSONArrayExpression) In(value interface{}, keys ...string) *JSONArra return json } +// Length checks if the length of the JSON array matches the given value. +func (json *JSONArrayExpression) Length(value int) *JSONArrayExpression { + json.length = true + json.lengthValue = value + return json +} + // Build implements clause.Expression func (json *JSONArrayExpression) Build(builder clause.Builder) { if stmt, ok := builder.(*gorm.Statement); ok { @@ -504,6 +515,10 @@ func (json *JSONArrayExpression) Build(builder clause.Builder) { builder.WriteByte(')') } builder.WriteByte(')') + // Add new logic to handle length comparison + case json.length: + builder.WriteString("JSON_LENGTH(" + stmt.Quote(json.column) + ") = ") + builder.AddVar(stmt, json.lengthValue) } case "sqlite": switch { @@ -551,6 +566,9 @@ func (json *JSONArrayExpression) Build(builder clause.Builder) { builder.WriteString(" IN ") builder.AddVar(stmt, json.equalsValue) builder.WriteString(" END") + case json.length: + builder.WriteString("json_array_length(" + stmt.Quote(json.column) + ") = ") + builder.AddVar(stmt, json.lengthValue) } case "postgres": switch { @@ -558,6 +576,9 @@ func (json *JSONArrayExpression) Build(builder clause.Builder) { builder.WriteString(stmt.Quote(json.column)) builder.WriteString(" ? ") builder.AddVar(stmt, json.equalsValue) + case json.length: + builder.WriteString("array_length(" + stmt.Quote(json.column) + "::jsonb::text[], 1) = ") + builder.AddVar(stmt, json.lengthValue) } } } From 8f86e54764242b71dea82886b3ea864d26f4ed80 Mon Sep 17 00:00:00 2001 From: "zhouyuhan.888" Date: Tue, 27 May 2025 11:18:44 +0800 Subject: [PATCH 2/4] add test --- json_test.go | 41 ++++++++++++----------------------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/json_test.go b/json_test.go index a5badb1..0a8569e 100644 --- a/json_test.go +++ b/json_test.go @@ -489,39 +489,22 @@ func TestJSONArrayQuery(t *testing.T) { t.Errorf("Failed to create param %v", err) } - var retSingle1 Param - if err := DB.Where("id = ?", cmp2.ID).First(&retSingle1).Error; err != nil { - t.Errorf("Failed to find param %v", err) - } - - var retSingle2 Param - if err := DB.Where("id = ?", cmp2.ID).First(&retSingle2).Error; err != nil { - t.Errorf("Failed to find param %v", err) - } - - AssertEqual(t, retSingle1, cmp2) - AssertEqual(t, retSingle2, cmp2) - - var retMultiple []Param - - if err := DB.Where(datatypes.JSONArrayQuery("config").Contains("c")).Find(&retMultiple).Error; err != nil { - t.Fatalf("failed to find params with json value, got error %v", err) - } - AssertEqual(t, len(retMultiple), 1) - - if err := DB.Where(datatypes.JSONArrayQuery("config").Contains("a", "test")).Find(&retMultiple).Error; err != nil { - t.Fatalf("failed to find params with json value and keys, got error %v", err) + // 新增的长度测试用例 + var results []Param + if err := DB.Where(datatypes.JSONArrayQuery("config").Length(2)).Find(&results).Error; err != nil { + t.Fatalf("failed to find params with json array length, got error %v", err) } - AssertEqual(t, len(retMultiple), 1) + AssertEqual(t, len(results), 2) // cmp1和cmp2的数组长度都是2 - if err := DB.Where(datatypes.JSONArrayQuery("config").In([]string{"c", "a"})).Find(&retMultiple).Error; err != nil { - t.Fatalf("failed to find params with json value, got error %v", err) + if err := DB.Where(datatypes.JSONArrayQuery("config").Length(1)).Find(&results).Error; err != nil { + t.Fatalf("failed to find params with json array length, got error %v", err) } - AssertEqual(t, len(retMultiple), 1) + AssertEqual(t, len(results), 0) // 没有长度为1的数组 - if err := DB.Where(datatypes.JSONArrayQuery("config").In([]string{"c", "d"}, "test")).Find(&retMultiple).Error; err != nil { - t.Fatalf("failed to find params with json value and keys, got error %v", err) + // 测试带key路径的长度查询 + if err := DB.Where(datatypes.JSONArrayQuery("config").Length(2).Contains("a", "test")).Find(&results).Error; err != nil { + t.Fatalf("failed to find params with json array length and keys, got error %v", err) } - AssertEqual(t, len(retMultiple), 1) + AssertEqual(t, len(results), 1) // 只有cmp3的test数组长度是2 } } From 68db25c4a4a551e2e332c2bd7238c3a2f88e167a Mon Sep 17 00:00:00 2001 From: "zhouyuhan.888" Date: Tue, 27 May 2025 11:26:50 +0800 Subject: [PATCH 3/4] fix --- json_test.go | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/json_test.go b/json_test.go index 0a8569e..7ebcb24 100644 --- a/json_test.go +++ b/json_test.go @@ -489,6 +489,41 @@ func TestJSONArrayQuery(t *testing.T) { t.Errorf("Failed to create param %v", err) } + var retSingle1 Param + if err := DB.Where("id = ?", cmp2.ID).First(&retSingle1).Error; err != nil { + t.Errorf("Failed to find param %v", err) + } + + var retSingle2 Param + if err := DB.Where("id = ?", cmp2.ID).First(&retSingle2).Error; err != nil { + t.Errorf("Failed to find param %v", err) + } + + AssertEqual(t, retSingle1, cmp2) + AssertEqual(t, retSingle2, cmp2) + + var retMultiple []Param + + if err := DB.Where(datatypes.JSONArrayQuery("config").Contains("c")).Find(&retMultiple).Error; err != nil { + t.Fatalf("failed to find params with json value, got error %v", err) + } + AssertEqual(t, len(retMultiple), 1) + + if err := DB.Where(datatypes.JSONArrayQuery("config").Contains("a", "test")).Find(&retMultiple).Error; err != nil { + t.Fatalf("failed to find params with json value and keys, got error %v", err) + } + AssertEqual(t, len(retMultiple), 1) + + if err := DB.Where(datatypes.JSONArrayQuery("config").In([]string{"c", "a"})).Find(&retMultiple).Error; err != nil { + t.Fatalf("failed to find params with json value, got error %v", err) + } + AssertEqual(t, len(retMultiple), 1) + + if err := DB.Where(datatypes.JSONArrayQuery("config").In([]string{"c", "d"}, "test")).Find(&retMultiple).Error; err != nil { + t.Fatalf("failed to find params with json value and keys, got error %v", err) + } + AssertEqual(t, len(retMultiple), 1) + // 新增的长度测试用例 var results []Param if err := DB.Where(datatypes.JSONArrayQuery("config").Length(2)).Find(&results).Error; err != nil { From 6ff482fccbab3f5772ccfc546cf49edde0dc29b0 Mon Sep 17 00:00:00 2001 From: "zhouyuhan.888" Date: Tue, 3 Jun 2025 15:36:16 +0800 Subject: [PATCH 4/4] fix test --- json_test.go | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/json_test.go b/json_test.go index 7ebcb24..1a190e4 100644 --- a/json_test.go +++ b/json_test.go @@ -525,21 +525,18 @@ func TestJSONArrayQuery(t *testing.T) { AssertEqual(t, len(retMultiple), 1) // 新增的长度测试用例 - var results []Param - if err := DB.Where(datatypes.JSONArrayQuery("config").Length(2)).Find(&results).Error; err != nil { + var retLength []Param + if err := DB.Where(datatypes.JSONArrayQuery("config").Length(2)).Find(&retLength).Error; err != nil { t.Fatalf("failed to find params with json array length, got error %v", err) } - AssertEqual(t, len(results), 2) // cmp1和cmp2的数组长度都是2 + AssertEqual(t, len(retLength), 1) + AssertEqual(t, retLength[0].DisplayName, cmp1.DisplayName) - if err := DB.Where(datatypes.JSONArrayQuery("config").Length(1)).Find(&results).Error; err != nil { - t.Fatalf("failed to find params with json array length, got error %v", err) - } - AssertEqual(t, len(results), 0) // 没有长度为1的数组 - - // 测试带key路径的长度查询 - if err := DB.Where(datatypes.JSONArrayQuery("config").Length(2).Contains("a", "test")).Find(&results).Error; err != nil { - t.Fatalf("failed to find params with json array length and keys, got error %v", err) + // 测试嵌套数组的长度 + if err := DB.Where(datatypes.JSONArrayQuery("config").Length(2).Contains("a", "test")).Find(&retLength).Error; err != nil { + t.Fatalf("failed to find params with json array length and contains, got error %v", err) } - AssertEqual(t, len(results), 1) // 只有cmp3的test数组长度是2 + AssertEqual(t, len(retLength), 1) + AssertEqual(t, retLength[0].DisplayName, cmp3.DisplayName) } }