[wip] working on filters interface

This commit is contained in:
Anton Nesterov 2024-08-08 19:26:29 +02:00
parent 8e45c45624
commit 4198ec4c75
No known key found for this signature in database
GPG key ID: 59121E8AE2851FB5
24 changed files with 127 additions and 52 deletions

View file

@ -1,7 +1,21 @@
package dal package dal
type FindObject map[string]interface{} import (
"fmt"
"strings"
func CovertFind(findobj FindObject) string { filters "l12.xyz/dal/filters"
return "" )
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 ")
} }

View file

@ -1 +1,24 @@
package dal 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)
}
}

View file

@ -2,6 +2,12 @@ module l12.xyz/dal
go 1.22.6 go 1.22.6
require l12.xyz/dal/utils v0.0.0 // indirect
replace l12.xyz/dal/utils v0.0.0 => ../utils 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 replace l12.xyz/dal/filters v0.0.0 => ../filters

2
pkg/dal/go.sum Normal file
View file

@ -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=

View file

@ -17,6 +17,6 @@ func (f And) ToSQLPart(ctx Context) string {
return fmt.Sprintf("(%s)", value) return fmt.Sprintf("(%s)", value)
} }
func (a And) FromJSON(data interface{}) Filter { func (a And) FromJSON(data interface{}) IFilter {
return FromJson[And](data) return FromJson[And](data)
} }

View file

@ -10,7 +10,7 @@ type Between struct {
Between []interface{} `json:"$between"` Between []interface{} `json:"$between"`
} }
func (f Between) FromJSON(data interface{}) Filter { func (f Between) FromJSON(data interface{}) IFilter {
return FromJson[Between](data) return FromJson[Between](data)
} }

View file

@ -8,7 +8,7 @@ type Eq struct {
Eq interface{} `json:"$eq"` Eq interface{} `json:"$eq"`
} }
func (f Eq) FromJSON(data interface{}) Filter { func (f Eq) FromJSON(data interface{}) IFilter {
return FromJson[Eq](data) return FromJson[Eq](data)
} }

View file

@ -6,7 +6,7 @@ type Glob struct {
Glob interface{} `json:"$glob"` Glob interface{} `json:"$glob"`
} }
func (f Glob) FromJSON(data interface{}) Filter { func (f Glob) FromJSON(data interface{}) IFilter {
return FromJson[Glob](data) return FromJson[Glob](data)
} }

View file

@ -8,7 +8,7 @@ type Gt struct {
Gt interface{} `json:"$gt"` Gt interface{} `json:"$gt"`
} }
func (f Gt) FromJSON(data interface{}) Filter { func (f Gt) FromJSON(data interface{}) IFilter {
return FromJson[Gt](data) return FromJson[Gt](data)
} }

View file

@ -8,7 +8,7 @@ type Gte struct {
Gte interface{} `json:"$gte"` Gte interface{} `json:"$gte"`
} }
func (f Gte) FromJSON(data interface{}) Filter { func (f Gte) FromJSON(data interface{}) IFilter {
return FromJson[Gte](data) return FromJson[Gte](data)
} }

View file

@ -11,7 +11,7 @@ type In struct {
In []interface{} `json:"$in"` In []interface{} `json:"$in"`
} }
func (f In) FromJSON(data interface{}) Filter { func (f In) FromJSON(data interface{}) IFilter {
return FromJson[In](data) return FromJson[In](data)
} }

View file

@ -6,7 +6,7 @@ type Like struct {
Like interface{} `json:"$like"` Like interface{} `json:"$like"`
} }
func (f Like) FromJSON(data interface{}) Filter { func (f Like) FromJSON(data interface{}) IFilter {
return FromJson[Like](data) return FromJson[Like](data)
} }

View file

@ -8,7 +8,7 @@ type Lt struct {
Lt interface{} `json:"$lt"` Lt interface{} `json:"$lt"`
} }
func (f Lt) FromJSON(data interface{}) Filter { func (f Lt) FromJSON(data interface{}) IFilter {
return FromJson[Lt](data) return FromJson[Lt](data)
} }

View file

@ -8,7 +8,7 @@ type Lte struct {
Lte interface{} `json:"$lte"` Lte interface{} `json:"$lte"`
} }
func (f Lte) FromJSON(data interface{}) Filter { func (f Lte) FromJSON(data interface{}) IFilter {
return FromJson[Lte](data) return FromJson[Lte](data)
} }

View file

@ -6,7 +6,7 @@ type Ne struct {
Ne interface{} `json:"$ne"` Ne interface{} `json:"$ne"`
} }
func (f Ne) FromJSON(data interface{}) Filter { func (f Ne) FromJSON(data interface{}) IFilter {
return FromJson[Ne](data) return FromJson[Ne](data)
} }

View file

@ -10,7 +10,7 @@ type NotBetween struct {
NotBetween []interface{} `json:"$nbetween"` NotBetween []interface{} `json:"$nbetween"`
} }
func (f NotBetween) FromJSON(data interface{}) Filter { func (f NotBetween) FromJSON(data interface{}) IFilter {
return FromJson[NotBetween](data) return FromJson[NotBetween](data)
} }

View file

@ -11,7 +11,7 @@ type NotIn struct {
NotIn []interface{} `json:"$nin"` NotIn []interface{} `json:"$nin"`
} }
func (f NotIn) FromJSON(data interface{}) Filter { func (f NotIn) FromJSON(data interface{}) IFilter {
return FromJson[NotIn](data) return FromJson[NotIn](data)
} }

View file

@ -6,7 +6,7 @@ type NotLike struct {
NotLike interface{} `json:"$nlike"` NotLike interface{} `json:"$nlike"`
} }
func (f NotLike) FromJSON(data interface{}) Filter { func (f NotLike) FromJSON(data interface{}) IFilter {
return FromJson[NotLike](data) return FromJson[NotLike](data)
} }

View file

@ -17,6 +17,6 @@ func (f Or) ToSQLPart(ctx Context) string {
return fmt.Sprintf("(%s)", value) return fmt.Sprintf("(%s)", value)
} }
func (a Or) FromJSON(data interface{}) Filter { func (a Or) FromJSON(data interface{}) IFilter {
return FromJson[Or](data) return FromJson[Or](data)
} }

View file

@ -14,6 +14,21 @@ type SQLiteContext struct {
FieldName string 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 { func (c SQLiteContext) GetFieldName() string {
if strings.Contains(c.FieldName, ".") { if strings.Contains(c.FieldName, ".") {
return c.FieldName return c.FieldName

View file

@ -1,6 +1,10 @@
package filters package filters
var FilterRegistry = map[string]Filter{ import (
"reflect"
)
var FilterRegistry = map[string]IFilter{
"And": &And{}, "And": &And{},
"Or": &Or{}, "Or": &Or{},
"Eq": &Eq{}, "Eq": &Eq{},
@ -18,12 +22,17 @@ var FilterRegistry = map[string]Filter{
"NotLike": &NotLike{}, "NotLike": &NotLike{},
} }
func Convert(ctx Context, json interface{}) string { func Convert(ctx Context, data interface{}) (string, error) {
for _, t := range FilterRegistry { 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 != "" { if value != "" {
return value return value, nil
} }
} }
return "" value := Eq{Eq: data}.ToSQLPart(ctx)
return value, nil
} }

View file

@ -1,11 +1,17 @@
package filters package filters
type Context interface { type Context interface {
New(opts map[string]string) Context
GetFieldName() string GetFieldName() string
NormalizeValue(interface{}) interface{} NormalizeValue(interface{}) interface{}
} }
type Filter interface { type IFilter interface {
ToSQLPart(ctx Context) string ToSQLPart(ctx Context) string
FromJSON(interface{}) Filter FromJSON(interface{}) IFilter
} }
type Find map[string]interface{}
// Filter{ "$eq": 1 }
type Filter map[string]interface{}

View file

@ -9,8 +9,8 @@ func TestEq(t *testing.T) {
TableAlias: "t", TableAlias: "t",
FieldName: "test", FieldName: "test",
} }
result := Convert(ctx, `{"$eq": "NULL"}`) result, _ := Convert(ctx, `{"$eq": "NULL"}`)
resultMap := Convert(ctx, map[string]any{"$eq": "NULL"}) resultMap, _ := Convert(ctx, Filter{"$eq": "NULL"})
if result != `t.test IS NULL` { if result != `t.test IS NULL` {
t.Errorf("Expected t.test IS NULL, got %s", result) t.Errorf("Expected t.test IS NULL, got %s", result)
} }
@ -25,8 +25,8 @@ func TestGte(t *testing.T) {
TableAlias: "t", TableAlias: "t",
FieldName: "test", FieldName: "test",
} }
result := Convert(ctx, `{"$gte": 1}`) result, _ := Convert(ctx, `{"$gte": 1}`)
resultMap := Convert(ctx, map[string]any{"$gte": 1}) resultMap, _ := Convert(ctx, Filter{"$gte": 1})
if result != `t.test >= 1` { if result != `t.test >= 1` {
t.Errorf("Expected t.test >= 1, got %s", result) t.Errorf("Expected t.test >= 1, got %s", result)
} }
@ -40,8 +40,8 @@ func TestNe(t *testing.T) {
ctx := SQLiteContext{ ctx := SQLiteContext{
FieldName: "test", FieldName: "test",
} }
result := Convert(ctx, `{"$ne": "1"}`) result, _ := Convert(ctx, `{"$ne": "1"}`)
resultMap := Convert(ctx, map[string]any{"$ne": "1"}) resultMap, _ := Convert(ctx, Filter{"$ne": "1"})
if result != `test != '1'` { if result != `test != '1'` {
t.Errorf("Expected test != '1', got %s", result) t.Errorf("Expected test != '1', got %s", result)
} }
@ -55,8 +55,8 @@ func TestBetween(t *testing.T) {
ctx := SQLiteContext{ ctx := SQLiteContext{
FieldName: "test", FieldName: "test",
} }
result := Convert(ctx, `{"$between": ["1", "5"]}`) result, _ := Convert(ctx, `{"$between": ["1", "5"]}`)
resultMap := Convert(ctx, map[string]any{"$between": []string{"1", "5"}}) resultMap, _ := Convert(ctx, Filter{"$between": []string{"1", "5"}})
if result != `test BETWEEN '1' AND '5'` { if result != `test BETWEEN '1' AND '5'` {
t.Errorf("Expected test BETWEEN '1' AND '5', got %s", result) t.Errorf("Expected test BETWEEN '1' AND '5', got %s", result)
} }
@ -70,8 +70,8 @@ func TestNotBetween(t *testing.T) {
ctx := SQLiteContext{ ctx := SQLiteContext{
FieldName: "test", FieldName: "test",
} }
result := Convert(ctx, `{"$nbetween": ["1", "5"]}`) result, _ := Convert(ctx, `{"$nbetween": ["1", "5"]}`)
resultMap := Convert(ctx, map[string]any{"$nbetween": []string{"1", "5"}}) resultMap, _ := Convert(ctx, Filter{"$nbetween": []string{"1", "5"}})
if result != `test NOT BETWEEN '1' AND '5'` { if result != `test NOT BETWEEN '1' AND '5'` {
t.Errorf("Expected test BETWEEN '1' AND '5', got %s", result) t.Errorf("Expected test BETWEEN '1' AND '5', got %s", result)
} }
@ -86,8 +86,8 @@ func TestGlob(t *testing.T) {
TableAlias: "t", TableAlias: "t",
FieldName: "test", FieldName: "test",
} }
result := Convert(ctx, `{"$glob": "*son"}`) result, _ := Convert(ctx, `{"$glob": "*son"}`)
resultMap := Convert(ctx, map[string]any{"$glob": "*son"}) resultMap, _ := Convert(ctx, Filter{"$glob": "*son"})
if result != `t.test GLOB '*son'` { if result != `t.test GLOB '*son'` {
t.Errorf("Expected t.test GLOB '*son', got %s", result) t.Errorf("Expected t.test GLOB '*son', got %s", result)
} }
@ -102,8 +102,8 @@ func TestIn(t *testing.T) {
TableAlias: "t", TableAlias: "t",
FieldName: "test", FieldName: "test",
} }
result := Convert(ctx, `{"$in": [1, 2, 3]}`) result, _ := Convert(ctx, `{"$in": [1, 2, 3]}`)
resultMap := Convert(ctx, map[string]any{"$in": []int{1, 2, 3}}) resultMap, _ := Convert(ctx, Filter{"$in": []int{1, 2, 3}})
if result != `t.test IN (1, 2, 3)` { if result != `t.test IN (1, 2, 3)` {
t.Errorf("Expected t.test IN (1, 2, 3), got %s", result) t.Errorf("Expected t.test IN (1, 2, 3), got %s", result)
} }
@ -118,8 +118,8 @@ func TestNotIn(t *testing.T) {
TableAlias: "t", TableAlias: "t",
FieldName: "test", FieldName: "test",
} }
result := Convert(ctx, `{"$nin": [1, 2, 3]}`) result, _ := Convert(ctx, `{"$nin": [1, 2, 3]}`)
resultMap := Convert(ctx, map[string]any{"$nin": []int{1, 2, 3}}) resultMap, _ := Convert(ctx, Filter{"$nin": []int{1, 2, 3}})
if result != `t.test NOT IN (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) t.Errorf("Expected t.test NOT IN (1, 2, 3), got %s", result)
} }
@ -134,8 +134,8 @@ func TestLike(t *testing.T) {
TableAlias: "t", TableAlias: "t",
FieldName: "test", FieldName: "test",
} }
result := Convert(ctx, `{"$like": "199_"}`) result, _ := Convert(ctx, `{"$like": "199_"}`)
resultMap := Convert(ctx, map[string]any{"$like": "199_"}) resultMap, _ := Convert(ctx, Filter{"$like": "199_"})
if result != `t.test LIKE '199_' ESCAPE '\'` { if result != `t.test LIKE '199_' ESCAPE '\'` {
t.Errorf("Expected t.test LIKE '199_' ESCAPE '\\', got %s", result) t.Errorf("Expected t.test LIKE '199_' ESCAPE '\\', got %s", result)
} }
@ -150,8 +150,8 @@ func TestAnd(t *testing.T) {
TableAlias: "t", TableAlias: "t",
FieldName: "test", FieldName: "test",
} }
result := Convert(ctx, `{"$and": ["a > 0", "b < 10"]}`) result, _ := Convert(ctx, `{"$and": ["a > 0", "b < 10"]}`)
resultMap := Convert(ctx, map[string]any{"$and": []string{"a > 0", "b < 10"}}) resultMap, _ := Convert(ctx, Filter{"$and": []string{"a > 0", "b < 10"}})
if result != `(a > 0 AND b < 10)` { if result != `(a > 0 AND b < 10)` {
t.Errorf("Expected (a > 0 AND b < 10), got %s", result) t.Errorf("Expected (a > 0 AND b < 10), got %s", result)
} }
@ -166,8 +166,8 @@ func TestOr(t *testing.T) {
TableAlias: "t", TableAlias: "t",
FieldName: "test", FieldName: "test",
} }
result := Convert(ctx, `{"$or": ["a = 0", "b < 10"]}`) result, _ := Convert(ctx, `{"$or": ["a = 0", "b < 10"]}`)
resultMap := Convert(ctx, map[string]any{"$or": []string{"a = 0", "b < 10"}}) resultMap, _ := Convert(ctx, Filter{"$or": []string{"a = 0", "b < 10"}})
if result != `(a = 0 OR b < 10)` { if result != `(a = 0 OR b < 10)` {
t.Errorf("Expected (a > 0 OR b < 10), got %s", result) t.Errorf("Expected (a > 0 OR b < 10), got %s", result)
} }

View file

@ -4,25 +4,25 @@ import (
"encoding/json" "encoding/json"
) )
func FromJson[T Filter](data interface{}) *T { func FromJson[T IFilter](data interface{}) *T {
var t T var t T
str, ok := data.(string) str, ok := data.(string)
if ok { if ok {
err := json.Unmarshal([]byte(str), &t) err := json.Unmarshal([]byte(str), &t)
if err != nil { if err != nil {
return nil return &t
} }
} }
m, ok := data.(map[string]interface{}) m, ok := data.(Filter)
if ok { if ok {
s, err := json.Marshal(m) s, err := json.Marshal(m)
if err != nil { if err != nil {
return nil return &t
} }
e := json.Unmarshal(s, &t) e := json.Unmarshal(s, &t)
if e != nil { if e != nil {
return nil return &t
} }
} }
return &t return &t