From 4198ec4c75aae9b6b2053f2de5137949c84e634b Mon Sep 17 00:00:00 2001 From: Anton Nesterov Date: Thu, 8 Aug 2024 19:26:29 +0200 Subject: [PATCH] [wip] working on filters interface --- pkg/dal/convert.go | 20 +++++++++++++++--- pkg/dal/convert_test.go | 23 ++++++++++++++++++++ pkg/dal/go.mod | 6 ++++++ pkg/dal/go.sum | 2 ++ pkg/filters/And.go | 2 +- pkg/filters/Between.go | 2 +- pkg/filters/Eq.go | 2 +- pkg/filters/Glob.go | 2 +- pkg/filters/Gt.go | 2 +- pkg/filters/Gte.go | 2 +- pkg/filters/In.go | 2 +- pkg/filters/Like.go | 2 +- pkg/filters/Lt.go | 2 +- pkg/filters/Lte.go | 2 +- pkg/filters/Ne.go | 2 +- pkg/filters/NotBetween.go | 2 +- pkg/filters/NotIn.go | 2 +- pkg/filters/NotLike.go | 2 +- pkg/filters/Or.go | 2 +- pkg/filters/context.go | 15 +++++++++++++ pkg/filters/registry.go | 19 ++++++++++++----- pkg/filters/types.go | 10 +++++++-- pkg/filters/unit_test.go | 44 +++++++++++++++++++-------------------- pkg/filters/utils.go | 10 ++++----- 24 files changed, 127 insertions(+), 52 deletions(-) create mode 100644 pkg/dal/go.sum diff --git a/pkg/dal/convert.go b/pkg/dal/convert.go index 69794f1..f38b7b5 100644 --- a/pkg/dal/convert.go +++ b/pkg/dal/convert.go @@ -1,7 +1,21 @@ package dal -type FindObject map[string]interface{} +import ( + "fmt" + "strings" -func CovertFind(findobj FindObject) string { - return "" + filters "l12.xyz/dal/filters" +) + +func CovertFind(find filters.Find, ctx filters.Context) string { + expressions := []string{} + for key, value := range find { + values, err := filters.Convert(ctx.New(map[string]string{ + "FieldName": key, + }), value) + expressions = append(expressions, values) + fmt.Println(err) + + } + return strings.Join(expressions, " AND ") } diff --git a/pkg/dal/convert_test.go b/pkg/dal/convert_test.go index 34f5247..3dff398 100644 --- a/pkg/dal/convert_test.go +++ b/pkg/dal/convert_test.go @@ -1 +1,24 @@ package dal + +import ( + "testing" + + f "l12.xyz/dal/filters" +) + +func TestConvertFind(t *testing.T) { + find := f.Find{ + "test": "1", + "test2": "2", + "test3": f.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/go.mod b/pkg/dal/go.mod index d9fc006..8c2c383 100644 --- a/pkg/dal/go.mod +++ b/pkg/dal/go.mod @@ -2,6 +2,12 @@ module l12.xyz/dal go 1.22.6 +require l12.xyz/dal/utils v0.0.0 // indirect + replace l12.xyz/dal/utils v0.0.0 => ../utils +require l12.xyz/dal/filters v0.0.0 + +require github.com/pkg/errors v0.9.1 // indirect + replace l12.xyz/dal/filters v0.0.0 => ../filters diff --git a/pkg/dal/go.sum b/pkg/dal/go.sum new file mode 100644 index 0000000..7c401c3 --- /dev/null +++ b/pkg/dal/go.sum @@ -0,0 +1,2 @@ +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/pkg/filters/And.go b/pkg/filters/And.go index 65345c5..e5dfdb2 100644 --- a/pkg/filters/And.go +++ b/pkg/filters/And.go @@ -17,6 +17,6 @@ func (f And) ToSQLPart(ctx Context) string { return fmt.Sprintf("(%s)", value) } -func (a And) FromJSON(data interface{}) Filter { +func (a And) FromJSON(data interface{}) IFilter { return FromJson[And](data) } diff --git a/pkg/filters/Between.go b/pkg/filters/Between.go index 6b53be0..d1c8d11 100644 --- a/pkg/filters/Between.go +++ b/pkg/filters/Between.go @@ -10,7 +10,7 @@ type Between struct { Between []interface{} `json:"$between"` } -func (f Between) FromJSON(data interface{}) Filter { +func (f Between) FromJSON(data interface{}) IFilter { return FromJson[Between](data) } diff --git a/pkg/filters/Eq.go b/pkg/filters/Eq.go index 57436b4..3a2ae90 100644 --- a/pkg/filters/Eq.go +++ b/pkg/filters/Eq.go @@ -8,7 +8,7 @@ type Eq struct { Eq interface{} `json:"$eq"` } -func (f Eq) FromJSON(data interface{}) Filter { +func (f Eq) FromJSON(data interface{}) IFilter { return FromJson[Eq](data) } diff --git a/pkg/filters/Glob.go b/pkg/filters/Glob.go index fdca1da..c3a61c7 100644 --- a/pkg/filters/Glob.go +++ b/pkg/filters/Glob.go @@ -6,7 +6,7 @@ type Glob struct { Glob interface{} `json:"$glob"` } -func (f Glob) FromJSON(data interface{}) Filter { +func (f Glob) FromJSON(data interface{}) IFilter { return FromJson[Glob](data) } diff --git a/pkg/filters/Gt.go b/pkg/filters/Gt.go index eb003d9..8042404 100644 --- a/pkg/filters/Gt.go +++ b/pkg/filters/Gt.go @@ -8,7 +8,7 @@ type Gt struct { Gt interface{} `json:"$gt"` } -func (f Gt) FromJSON(data interface{}) Filter { +func (f Gt) FromJSON(data interface{}) IFilter { return FromJson[Gt](data) } diff --git a/pkg/filters/Gte.go b/pkg/filters/Gte.go index 11a8ff2..07c7cc1 100644 --- a/pkg/filters/Gte.go +++ b/pkg/filters/Gte.go @@ -8,7 +8,7 @@ type Gte struct { Gte interface{} `json:"$gte"` } -func (f Gte) FromJSON(data interface{}) Filter { +func (f Gte) FromJSON(data interface{}) IFilter { return FromJson[Gte](data) } diff --git a/pkg/filters/In.go b/pkg/filters/In.go index 139ac08..36c5df1 100644 --- a/pkg/filters/In.go +++ b/pkg/filters/In.go @@ -11,7 +11,7 @@ type In struct { In []interface{} `json:"$in"` } -func (f In) FromJSON(data interface{}) Filter { +func (f In) FromJSON(data interface{}) IFilter { return FromJson[In](data) } diff --git a/pkg/filters/Like.go b/pkg/filters/Like.go index ca799be..08fd5b9 100644 --- a/pkg/filters/Like.go +++ b/pkg/filters/Like.go @@ -6,7 +6,7 @@ type Like struct { Like interface{} `json:"$like"` } -func (f Like) FromJSON(data interface{}) Filter { +func (f Like) FromJSON(data interface{}) IFilter { return FromJson[Like](data) } diff --git a/pkg/filters/Lt.go b/pkg/filters/Lt.go index 71b8503..c38aa9a 100644 --- a/pkg/filters/Lt.go +++ b/pkg/filters/Lt.go @@ -8,7 +8,7 @@ type Lt struct { Lt interface{} `json:"$lt"` } -func (f Lt) FromJSON(data interface{}) Filter { +func (f Lt) FromJSON(data interface{}) IFilter { return FromJson[Lt](data) } diff --git a/pkg/filters/Lte.go b/pkg/filters/Lte.go index 62557a6..cb9879d 100644 --- a/pkg/filters/Lte.go +++ b/pkg/filters/Lte.go @@ -8,7 +8,7 @@ type Lte struct { Lte interface{} `json:"$lte"` } -func (f Lte) FromJSON(data interface{}) Filter { +func (f Lte) FromJSON(data interface{}) IFilter { return FromJson[Lte](data) } diff --git a/pkg/filters/Ne.go b/pkg/filters/Ne.go index b32a6c2..fabc4bc 100644 --- a/pkg/filters/Ne.go +++ b/pkg/filters/Ne.go @@ -6,7 +6,7 @@ type Ne struct { Ne interface{} `json:"$ne"` } -func (f Ne) FromJSON(data interface{}) Filter { +func (f Ne) FromJSON(data interface{}) IFilter { return FromJson[Ne](data) } diff --git a/pkg/filters/NotBetween.go b/pkg/filters/NotBetween.go index 2a2eb7b..9f9e7b8 100644 --- a/pkg/filters/NotBetween.go +++ b/pkg/filters/NotBetween.go @@ -10,7 +10,7 @@ type NotBetween struct { NotBetween []interface{} `json:"$nbetween"` } -func (f NotBetween) FromJSON(data interface{}) Filter { +func (f NotBetween) FromJSON(data interface{}) IFilter { return FromJson[NotBetween](data) } diff --git a/pkg/filters/NotIn.go b/pkg/filters/NotIn.go index 29b76e3..6c219d0 100644 --- a/pkg/filters/NotIn.go +++ b/pkg/filters/NotIn.go @@ -11,7 +11,7 @@ type NotIn struct { NotIn []interface{} `json:"$nin"` } -func (f NotIn) FromJSON(data interface{}) Filter { +func (f NotIn) FromJSON(data interface{}) IFilter { return FromJson[NotIn](data) } diff --git a/pkg/filters/NotLike.go b/pkg/filters/NotLike.go index 1e2564a..3a5792d 100644 --- a/pkg/filters/NotLike.go +++ b/pkg/filters/NotLike.go @@ -6,7 +6,7 @@ type NotLike struct { NotLike interface{} `json:"$nlike"` } -func (f NotLike) FromJSON(data interface{}) Filter { +func (f NotLike) FromJSON(data interface{}) IFilter { return FromJson[NotLike](data) } diff --git a/pkg/filters/Or.go b/pkg/filters/Or.go index e66ded1..d2704bf 100644 --- a/pkg/filters/Or.go +++ b/pkg/filters/Or.go @@ -17,6 +17,6 @@ func (f Or) ToSQLPart(ctx Context) string { return fmt.Sprintf("(%s)", value) } -func (a Or) FromJSON(data interface{}) Filter { +func (a Or) FromJSON(data interface{}) IFilter { return FromJson[Or](data) } diff --git a/pkg/filters/context.go b/pkg/filters/context.go index cc1db54..0903363 100644 --- a/pkg/filters/context.go +++ b/pkg/filters/context.go @@ -14,6 +14,21 @@ type SQLiteContext struct { FieldName string } +func (c SQLiteContext) New(opts map[string]string) Context { + ta := opts["TableAlias"] + if ta == "" { + ta = c.TableAlias + } + fn := opts["FieldName"] + if fn == "" { + fn = c.FieldName + } + return SQLiteContext{ + TableAlias: ta, + FieldName: fn, + } +} + func (c SQLiteContext) GetFieldName() string { if strings.Contains(c.FieldName, ".") { return c.FieldName diff --git a/pkg/filters/registry.go b/pkg/filters/registry.go index cb4098d..1269122 100644 --- a/pkg/filters/registry.go +++ b/pkg/filters/registry.go @@ -1,6 +1,10 @@ package filters -var FilterRegistry = map[string]Filter{ +import ( + "reflect" +) + +var FilterRegistry = map[string]IFilter{ "And": &And{}, "Or": &Or{}, "Eq": &Eq{}, @@ -18,12 +22,17 @@ var FilterRegistry = map[string]Filter{ "NotLike": &NotLike{}, } -func Convert(ctx Context, json interface{}) string { +func Convert(ctx Context, data interface{}) (string, error) { for _, t := range FilterRegistry { - value := t.FromJSON(json).ToSQLPart(ctx) + filter := t.FromJSON(data) + if reflect.DeepEqual(t, filter) { + continue + } + value := filter.ToSQLPart(ctx) if value != "" { - return value + return value, nil } } - return "" + value := Eq{Eq: data}.ToSQLPart(ctx) + return value, nil } diff --git a/pkg/filters/types.go b/pkg/filters/types.go index c20fae2..f61f73b 100644 --- a/pkg/filters/types.go +++ b/pkg/filters/types.go @@ -1,11 +1,17 @@ package filters type Context interface { + New(opts map[string]string) Context GetFieldName() string NormalizeValue(interface{}) interface{} } -type Filter interface { +type IFilter interface { ToSQLPart(ctx Context) string - FromJSON(interface{}) Filter + FromJSON(interface{}) IFilter } + +type Find map[string]interface{} + +// Filter{ "$eq": 1 } +type Filter map[string]interface{} diff --git a/pkg/filters/unit_test.go b/pkg/filters/unit_test.go index 0a5b1ce..c0ed4e1 100644 --- a/pkg/filters/unit_test.go +++ b/pkg/filters/unit_test.go @@ -9,8 +9,8 @@ func TestEq(t *testing.T) { TableAlias: "t", FieldName: "test", } - result := Convert(ctx, `{"$eq": "NULL"}`) - resultMap := Convert(ctx, map[string]any{"$eq": "NULL"}) + result, _ := Convert(ctx, `{"$eq": "NULL"}`) + resultMap, _ := Convert(ctx, Filter{"$eq": "NULL"}) if result != `t.test IS NULL` { t.Errorf("Expected t.test IS NULL, got %s", result) } @@ -25,8 +25,8 @@ func TestGte(t *testing.T) { TableAlias: "t", FieldName: "test", } - result := Convert(ctx, `{"$gte": 1}`) - resultMap := Convert(ctx, map[string]any{"$gte": 1}) + result, _ := Convert(ctx, `{"$gte": 1}`) + resultMap, _ := Convert(ctx, Filter{"$gte": 1}) if result != `t.test >= 1` { t.Errorf("Expected t.test >= 1, got %s", result) } @@ -40,8 +40,8 @@ func TestNe(t *testing.T) { ctx := SQLiteContext{ FieldName: "test", } - result := Convert(ctx, `{"$ne": "1"}`) - resultMap := Convert(ctx, map[string]any{"$ne": "1"}) + result, _ := Convert(ctx, `{"$ne": "1"}`) + resultMap, _ := Convert(ctx, Filter{"$ne": "1"}) if result != `test != '1'` { t.Errorf("Expected test != '1', got %s", result) } @@ -55,8 +55,8 @@ func TestBetween(t *testing.T) { ctx := SQLiteContext{ FieldName: "test", } - result := Convert(ctx, `{"$between": ["1", "5"]}`) - resultMap := Convert(ctx, map[string]any{"$between": []string{"1", "5"}}) + result, _ := Convert(ctx, `{"$between": ["1", "5"]}`) + resultMap, _ := Convert(ctx, Filter{"$between": []string{"1", "5"}}) if result != `test BETWEEN '1' AND '5'` { t.Errorf("Expected test BETWEEN '1' AND '5', got %s", result) } @@ -70,8 +70,8 @@ func TestNotBetween(t *testing.T) { ctx := SQLiteContext{ FieldName: "test", } - result := Convert(ctx, `{"$nbetween": ["1", "5"]}`) - resultMap := Convert(ctx, map[string]any{"$nbetween": []string{"1", "5"}}) + result, _ := Convert(ctx, `{"$nbetween": ["1", "5"]}`) + resultMap, _ := Convert(ctx, Filter{"$nbetween": []string{"1", "5"}}) if result != `test NOT BETWEEN '1' AND '5'` { t.Errorf("Expected test BETWEEN '1' AND '5', got %s", result) } @@ -86,8 +86,8 @@ func TestGlob(t *testing.T) { TableAlias: "t", FieldName: "test", } - result := Convert(ctx, `{"$glob": "*son"}`) - resultMap := Convert(ctx, map[string]any{"$glob": "*son"}) + result, _ := Convert(ctx, `{"$glob": "*son"}`) + resultMap, _ := Convert(ctx, Filter{"$glob": "*son"}) if result != `t.test GLOB '*son'` { t.Errorf("Expected t.test GLOB '*son', got %s", result) } @@ -102,8 +102,8 @@ func TestIn(t *testing.T) { TableAlias: "t", FieldName: "test", } - result := Convert(ctx, `{"$in": [1, 2, 3]}`) - resultMap := Convert(ctx, map[string]any{"$in": []int{1, 2, 3}}) + result, _ := Convert(ctx, `{"$in": [1, 2, 3]}`) + resultMap, _ := Convert(ctx, Filter{"$in": []int{1, 2, 3}}) if result != `t.test IN (1, 2, 3)` { t.Errorf("Expected t.test IN (1, 2, 3), got %s", result) } @@ -118,8 +118,8 @@ func TestNotIn(t *testing.T) { TableAlias: "t", FieldName: "test", } - result := Convert(ctx, `{"$nin": [1, 2, 3]}`) - resultMap := Convert(ctx, map[string]any{"$nin": []int{1, 2, 3}}) + result, _ := Convert(ctx, `{"$nin": [1, 2, 3]}`) + resultMap, _ := Convert(ctx, Filter{"$nin": []int{1, 2, 3}}) if result != `t.test NOT IN (1, 2, 3)` { t.Errorf("Expected t.test NOT IN (1, 2, 3), got %s", result) } @@ -134,8 +134,8 @@ func TestLike(t *testing.T) { TableAlias: "t", FieldName: "test", } - result := Convert(ctx, `{"$like": "199_"}`) - resultMap := Convert(ctx, map[string]any{"$like": "199_"}) + result, _ := Convert(ctx, `{"$like": "199_"}`) + resultMap, _ := Convert(ctx, Filter{"$like": "199_"}) if result != `t.test LIKE '199_' ESCAPE '\'` { t.Errorf("Expected t.test LIKE '199_' ESCAPE '\\', got %s", result) } @@ -150,8 +150,8 @@ func TestAnd(t *testing.T) { TableAlias: "t", FieldName: "test", } - result := Convert(ctx, `{"$and": ["a > 0", "b < 10"]}`) - resultMap := Convert(ctx, map[string]any{"$and": []string{"a > 0", "b < 10"}}) + result, _ := Convert(ctx, `{"$and": ["a > 0", "b < 10"]}`) + resultMap, _ := Convert(ctx, Filter{"$and": []string{"a > 0", "b < 10"}}) if result != `(a > 0 AND b < 10)` { t.Errorf("Expected (a > 0 AND b < 10), got %s", result) } @@ -166,8 +166,8 @@ func TestOr(t *testing.T) { TableAlias: "t", FieldName: "test", } - result := Convert(ctx, `{"$or": ["a = 0", "b < 10"]}`) - resultMap := Convert(ctx, map[string]any{"$or": []string{"a = 0", "b < 10"}}) + result, _ := Convert(ctx, `{"$or": ["a = 0", "b < 10"]}`) + resultMap, _ := Convert(ctx, Filter{"$or": []string{"a = 0", "b < 10"}}) if result != `(a = 0 OR b < 10)` { t.Errorf("Expected (a > 0 OR b < 10), got %s", result) } diff --git a/pkg/filters/utils.go b/pkg/filters/utils.go index add3835..a2e58a8 100644 --- a/pkg/filters/utils.go +++ b/pkg/filters/utils.go @@ -4,25 +4,25 @@ import ( "encoding/json" ) -func FromJson[T Filter](data interface{}) *T { +func FromJson[T IFilter](data interface{}) *T { var t T str, ok := data.(string) if ok { err := json.Unmarshal([]byte(str), &t) if err != nil { - return nil + return &t } } - m, ok := data.(map[string]interface{}) + m, ok := data.(Filter) if ok { s, err := json.Marshal(m) if err != nil { - return nil + return &t } e := json.Unmarshal(s, &t) if e != nil { - return nil + return &t } } return &t