From 758eab65205c9d8179b8bcd9e61299433d8673a9 Mon Sep 17 00:00:00 2001 From: Anton Nesterov Date: Thu, 8 Aug 2024 23:44:51 +0200 Subject: [PATCH] [wip] joins Signed-off-by: Anton Nesterov --- pkg/dal/convert.go | 19 --------- pkg/dal/convert_find.go | 37 ++++++++++++++++++ pkg/dal/convert_find_test.go | 75 ++++++++++++++++++++++++++++++++++++ pkg/dal/convert_join.go | 17 ++++++++ pkg/dal/convert_join_test.go | 25 ++++++++++++ pkg/dal/convert_test.go | 24 ------------ pkg/dal/types.go | 2 + pkg/filters/registry.go | 6 +-- 8 files changed, 159 insertions(+), 46 deletions(-) delete mode 100644 pkg/dal/convert.go create mode 100644 pkg/dal/convert_find.go create mode 100644 pkg/dal/convert_find_test.go create mode 100644 pkg/dal/convert_join.go create mode 100644 pkg/dal/convert_join_test.go delete mode 100644 pkg/dal/convert_test.go diff --git a/pkg/dal/convert.go b/pkg/dal/convert.go deleted file mode 100644 index 9aa2d1b..0000000 --- a/pkg/dal/convert.go +++ /dev/null @@ -1,19 +0,0 @@ -package dal - -import ( - "strings" - - filters "l12.xyz/dal/filters" -) - -func CovertFind(find Find, ctx Context) string { - expressions := []string{} - for key, value := range find { - context := ctx.New(CtxOpts{ - "FieldName": key, - }) - values, _ := filters.Convert(context, value) - expressions = append(expressions, values) - } - return strings.Join(expressions, " AND ") -} diff --git a/pkg/dal/convert_find.go b/pkg/dal/convert_find.go new file mode 100644 index 0000000..a5fd2b9 --- /dev/null +++ b/pkg/dal/convert_find.go @@ -0,0 +1,37 @@ +package dal + +import ( + "fmt" + "strings" + + filters "l12.xyz/dal/filters" +) + +func CovertFind(find Find, ctx Context) string { + return covert_find(find, ctx, "") +} + +func covert_find(find Find, ctx Context, join string) string { + if join == "" { + join = " AND " + } + expressions := []string{} + for key, value := range find { + if strings.Contains(key, "$and") { + v := covert_find(value.(Find), ctx, "") + expressions = append(expressions, fmt.Sprintf("(%s)", v)) + continue + } + if strings.Contains(key, "$or") { + v := covert_find(value.(Find), ctx, " OR ") + expressions = append(expressions, fmt.Sprintf("(%s)", v)) + continue + } + context := ctx.New(CtxOpts{ + "FieldName": key, + }) + values, _ := filters.Convert(context, value) + expressions = append(expressions, values) + } + return strings.Join(expressions, join) +} diff --git a/pkg/dal/convert_find_test.go b/pkg/dal/convert_find_test.go new file mode 100644 index 0000000..c6bb5d2 --- /dev/null +++ b/pkg/dal/convert_find_test.go @@ -0,0 +1,75 @@ +package dal + +import ( + "testing" + + f "l12.xyz/dal/filters" +) + +func TestConvertFind(t *testing.T) { + find := Find{ + "impl": "1", + "exp": Is{ + "$gt": 1, + }, + } + ctx := f.SQLiteContext{ + TableAlias: "t", + } + result := CovertFind(find, ctx) + if result == `t.exp > 1 AND t.impl = '1'` { + return + } + if result == `t.impl = '1' AND t.exp > 1` { + return + } + t.Errorf(`Expected "t.impl = '1' AND t.exp = 1", got %s`, result) +} + +func TestConvertFindAnd(t *testing.T) { + find := Find{ + "$and": Find{ + "a": Is{ + "$gt": 1, + }, + "b": Is{ + "$lt": 10, + }, + }, + } + ctx := f.SQLiteContext{ + TableAlias: "t", + } + result := CovertFind(find, ctx) + if result == `(t.a > 1 AND t.b < 10)` { + return + } + if result == `(t.b < 10 AND t.a > 1)` { + return + } + t.Errorf(`Expected "(t.b < 10 AND t.a > 1)", got %s`, result) +} + +func TestConvertFindOr(t *testing.T) { + find := Query{ + "$or": Query{ + "a": Is{ + "$gt": 1, + }, + "b": Is{ + "$lt": 10, + }, + }, + } + ctx := f.SQLiteContext{ + TableAlias: "t", + } + result := CovertFind(find, ctx) + if result == `(t.a > 1 OR t.b < 10)` { + return + } + if result == `(t.b < 10 OR t.a > 1)` { + return + } + t.Errorf(`Expected "(t.b < 10 OR t.a > 1)", got %s`, result) +} diff --git a/pkg/dal/convert_join.go b/pkg/dal/convert_join.go new file mode 100644 index 0000000..49e1494 --- /dev/null +++ b/pkg/dal/convert_join.go @@ -0,0 +1,17 @@ +package dal + +import "fmt" + +type Join struct { + For string `json:"$for"` + Do Find `json:"$do"` + As string `json:"$as"` +} + +func (j Join) Convert(ctx Context) string { + if j.For == "" { + return "" + } + filter := CovertFind(j.Do, ctx) + return fmt.Sprintf("%s JOIN %s ON %s", j.As, j.For, filter) +} diff --git a/pkg/dal/convert_join_test.go b/pkg/dal/convert_join_test.go new file mode 100644 index 0000000..6fd4d65 --- /dev/null +++ b/pkg/dal/convert_join_test.go @@ -0,0 +1,25 @@ +package dal + +import ( + "testing" + + f "l12.xyz/dal/filters" +) + +func TestJoin(t *testing.T) { + j := Join{ + For: "artist a", + Do: Find{ + "a.impl": "t.impl", + }, + As: "LEFT", + } + ctx := f.SQLiteContext{ + TableAlias: "t", + } + result := j.Convert(ctx) + if result == `LEFT JOIN artist a ON a.impl = t.impl` { + return + } + t.Errorf(`Expected "LEFT JOIN artist a ON a.impl = t.impl", got %s`, result) +} diff --git a/pkg/dal/convert_test.go b/pkg/dal/convert_test.go deleted file mode 100644 index ca0d2b2..0000000 --- a/pkg/dal/convert_test.go +++ /dev/null @@ -1,24 +0,0 @@ -package dal - -import ( - "testing" - - f "l12.xyz/dal/filters" -) - -func TestConvertFind(t *testing.T) { - find := Find{ - "test": "1", - "test2": "2", - "test3": Filter{ - "$ne": 1, - }, - } - ctx := f.SQLiteContext{ - TableAlias: "t", - } - result := CovertFind(find, ctx) - if result != `t.test = '1'` { - t.Errorf("Expected t.test = '1', got %s", result) - } -} diff --git a/pkg/dal/types.go b/pkg/dal/types.go index 92cde6f..f290e14 100644 --- a/pkg/dal/types.go +++ b/pkg/dal/types.go @@ -5,6 +5,8 @@ import ( ) type Find = filters.Find +type Query = filters.Find type Filter = filters.Filter +type Is = filters.Filter type Context = filters.Context type CtxOpts = filters.CtxOpts diff --git a/pkg/filters/registry.go b/pkg/filters/registry.go index 1269122..ba606e2 100644 --- a/pkg/filters/registry.go +++ b/pkg/filters/registry.go @@ -23,9 +23,9 @@ var FilterRegistry = map[string]IFilter{ } func Convert(ctx Context, data interface{}) (string, error) { - for _, t := range FilterRegistry { - filter := t.FromJSON(data) - if reflect.DeepEqual(t, filter) { + for _, impl := range FilterRegistry { + filter := impl.FromJSON(data) + if reflect.DeepEqual(impl, filter) { continue } value := filter.ToSQLPart(ctx)