From aa60862bbd3e70e6cd0338d66ced3bf1adf10c40 Mon Sep 17 00:00:00 2001 From: wave2way <35788676+wave2way@users.noreply.github.com> Date: Thu, 26 Oct 2023 11:19:45 +0800 Subject: [PATCH] feature: add Mysql&Postgres Json Like (#225) --- json.go | 40 ++++++++++++++++++++++++++++++++++++++++ json_test.go | 6 ++++++ 2 files changed, 46 insertions(+) diff --git a/json.go b/json.go index 40f6430..a8119db 100644 --- a/json.go +++ b/json.go @@ -110,6 +110,7 @@ type JSONQueryExpression struct { keys []string hasKeys bool equals bool + likes bool equalsValue interface{} extract bool path string @@ -142,6 +143,14 @@ func (jsonQuery *JSONQueryExpression) Equals(value interface{}, keys ...string) return jsonQuery } +// Likes return clause.Expression +func (jsonQuery *JSONQueryExpression) Likes(value interface{}, keys ...string) *JSONQueryExpression { + jsonQuery.keys = keys + jsonQuery.likes = true + jsonQuery.equalsValue = value + return jsonQuery +} + // Build implements clause.Expression func (jsonQuery *JSONQueryExpression) Build(builder clause.Builder) { if stmt, ok := builder.(*gorm.Statement); ok { @@ -175,6 +184,19 @@ func (jsonQuery *JSONQueryExpression) Build(builder clause.Builder) { stmt.AddVar(builder, jsonQuery.equalsValue) } } + case jsonQuery.likes: + if len(jsonQuery.keys) > 0 { + builder.WriteString("JSON_EXTRACT(") + builder.WriteQuoted(jsonQuery.column) + builder.WriteByte(',') + builder.AddVar(stmt, jsonQueryJoin(jsonQuery.keys)) + builder.WriteString(") LIKE ") + if value, ok := jsonQuery.equalsValue.(bool); ok { + builder.WriteString(strconv.FormatBool(value)) + } else { + stmt.AddVar(builder, jsonQuery.equalsValue) + } + } } case "postgres": switch { @@ -206,6 +228,24 @@ func (jsonQuery *JSONQueryExpression) Build(builder clause.Builder) { } builder.WriteString(") = ") + if _, ok := jsonQuery.equalsValue.(string); ok { + stmt.AddVar(builder, jsonQuery.equalsValue) + } else { + stmt.AddVar(builder, fmt.Sprint(jsonQuery.equalsValue)) + } + } + case jsonQuery.likes: + if len(jsonQuery.keys) > 0 { + builder.WriteString(fmt.Sprintf("json_extract_path_text(%v::json,", stmt.Quote(jsonQuery.column))) + + for idx, key := range jsonQuery.keys { + if idx > 0 { + builder.WriteByte(',') + } + stmt.AddVar(builder, key) + } + builder.WriteString(") LIKE ") + if _, ok := jsonQuery.equalsValue.(string); ok { stmt.AddVar(builder, jsonQuery.equalsValue) } else { diff --git a/json_test.go b/json_test.go index cdd0470..4011088 100644 --- a/json_test.go +++ b/json_test.go @@ -124,6 +124,12 @@ func TestJSON(t *testing.T) { } AssertEqual(t, results9[0].Name, users[1].Name) + var result10 UserWithJSON + if err := DB.First(&result10, datatypes.JSONQuery("attributes").Likes("%dmi%", "role")).Error; err != nil { + t.Fatalf("failed to find user with json value, got error %v", err) + } + AssertEqual(t, result10.Name, users[1].Name) + // not support for sqlite // JSONOverlaps //var result9 UserWithJSON