[wip] add missing filters
Signed-off-by: Anton Nesterov <anton@demiurg.io>
This commit is contained in:
parent
d28d976b8e
commit
8e45c45624
1
pkg/dal/convert_test.go
Normal file
1
pkg/dal/convert_test.go
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package dal
|
7
pkg/dal/go.mod
Normal file
7
pkg/dal/go.mod
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
module l12.xyz/dal
|
||||||
|
|
||||||
|
go 1.22.6
|
||||||
|
|
||||||
|
replace l12.xyz/dal/utils v0.0.0 => ../utils
|
||||||
|
|
||||||
|
replace l12.xyz/dal/filters v0.0.0 => ../filters
|
|
@ -2,16 +2,19 @@ package filters
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type And struct {
|
type And struct {
|
||||||
And []interface{} `json:"$and"`
|
And []string `json:"$and"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a And) ToSQLPart(ctx Context) string {
|
func (f And) ToSQLPart(ctx Context) string {
|
||||||
|
if f.And == nil {
|
||||||
fmt.Println(ctx, a)
|
|
||||||
return ""
|
return ""
|
||||||
|
}
|
||||||
|
value := strings.Join(f.And, " AND ")
|
||||||
|
return fmt.Sprintf("(%s)", value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a And) FromJSON(data interface{}) Filter {
|
func (a And) FromJSON(data interface{}) Filter {
|
||||||
|
|
20
pkg/filters/Like.go
Normal file
20
pkg/filters/Like.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package filters
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type Like struct {
|
||||||
|
Like interface{} `json:"$like"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Like) FromJSON(data interface{}) Filter {
|
||||||
|
return FromJson[Like](data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Like) ToSQLPart(ctx Context) string {
|
||||||
|
if f.Like == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
name := ctx.GetFieldName()
|
||||||
|
value := ctx.NormalizeValue(f.Like)
|
||||||
|
return fmt.Sprintf("%s LIKE %v ESCAPE '\\'", name, value)
|
||||||
|
}
|
31
pkg/filters/NotIn.go
Normal file
31
pkg/filters/NotIn.go
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
package filters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"l12.xyz/dal/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NotIn struct {
|
||||||
|
NotIn []interface{} `json:"$nin"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f NotIn) FromJSON(data interface{}) Filter {
|
||||||
|
return FromJson[NotIn](data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f NotIn) ToSQLPart(ctx Context) string {
|
||||||
|
if f.NotIn == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
name := ctx.GetFieldName()
|
||||||
|
values := utils.Map(f.NotIn, ctx.NormalizeValue)
|
||||||
|
data := make([]string, len(values))
|
||||||
|
for i, v := range values {
|
||||||
|
data[i] = fmt.Sprintf("%v", v)
|
||||||
|
}
|
||||||
|
value := strings.Join(data, ", ")
|
||||||
|
return fmt.Sprintf("%s NOT IN (%v)", name, value)
|
||||||
|
}
|
20
pkg/filters/NotLike.go
Normal file
20
pkg/filters/NotLike.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package filters
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type NotLike struct {
|
||||||
|
NotLike interface{} `json:"$nlike"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f NotLike) FromJSON(data interface{}) Filter {
|
||||||
|
return FromJson[NotLike](data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f NotLike) ToSQLPart(ctx Context) string {
|
||||||
|
if f.NotLike == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
name := ctx.GetFieldName()
|
||||||
|
value := ctx.NormalizeValue(f.NotLike)
|
||||||
|
return fmt.Sprintf("%s NOT LIKE %v ESCAPE '\\'", name, value)
|
||||||
|
}
|
22
pkg/filters/Or.go
Normal file
22
pkg/filters/Or.go
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package filters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Or struct {
|
||||||
|
Or []string `json:"$or"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Or) ToSQLPart(ctx Context) string {
|
||||||
|
if f.Or == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
value := strings.Join(f.Or, " OR ")
|
||||||
|
return fmt.Sprintf("(%s)", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a Or) FromJSON(data interface{}) Filter {
|
||||||
|
return FromJson[Or](data)
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
package filters
|
package filters
|
||||||
|
|
||||||
var FilterRegistry = map[string]Filter{
|
var FilterRegistry = map[string]Filter{
|
||||||
|
"And": &And{},
|
||||||
|
"Or": &Or{},
|
||||||
"Eq": &Eq{},
|
"Eq": &Eq{},
|
||||||
"Ne": &Ne{},
|
"Ne": &Ne{},
|
||||||
"Gt": &Gt{},
|
"Gt": &Gt{},
|
||||||
|
@ -8,9 +10,12 @@ var FilterRegistry = map[string]Filter{
|
||||||
"Lt": &Lt{},
|
"Lt": &Lt{},
|
||||||
"Lte": &Lte{},
|
"Lte": &Lte{},
|
||||||
"In": &In{},
|
"In": &In{},
|
||||||
|
"Nin": &NotIn{},
|
||||||
"Between": &Between{},
|
"Between": &Between{},
|
||||||
"NotBetween": &NotBetween{},
|
"NotBetween": &NotBetween{},
|
||||||
"Glob": &Glob{},
|
"Glob": &Glob{},
|
||||||
|
"Like": &Like{},
|
||||||
|
"NotLike": &NotLike{},
|
||||||
}
|
}
|
||||||
|
|
||||||
func Convert(ctx Context, json interface{}) string {
|
func Convert(ctx Context, json interface{}) string {
|
||||||
|
|
|
@ -20,6 +20,22 @@ func TestEq(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGte(t *testing.T) {
|
||||||
|
ctx := SQLiteContext{
|
||||||
|
TableAlias: "t",
|
||||||
|
FieldName: "test",
|
||||||
|
}
|
||||||
|
result := Convert(ctx, `{"$gte": 1}`)
|
||||||
|
resultMap := Convert(ctx, map[string]any{"$gte": 1})
|
||||||
|
if result != `t.test >= 1` {
|
||||||
|
t.Errorf("Expected t.test >= 1, got %s", result)
|
||||||
|
}
|
||||||
|
if resultMap != result {
|
||||||
|
t.Log(resultMap)
|
||||||
|
t.Errorf("Expected resultMap to be equal to result")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestNe(t *testing.T) {
|
func TestNe(t *testing.T) {
|
||||||
ctx := SQLiteContext{
|
ctx := SQLiteContext{
|
||||||
FieldName: "test",
|
FieldName: "test",
|
||||||
|
@ -50,6 +66,21 @@ func TestBetween(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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"}})
|
||||||
|
if result != `test NOT BETWEEN '1' AND '5'` {
|
||||||
|
t.Errorf("Expected test BETWEEN '1' AND '5', got %s", result)
|
||||||
|
}
|
||||||
|
if resultMap != result {
|
||||||
|
t.Log(resultMap)
|
||||||
|
t.Errorf("Expected resultMap to be equal to result")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGlob(t *testing.T) {
|
func TestGlob(t *testing.T) {
|
||||||
ctx := SQLiteContext{
|
ctx := SQLiteContext{
|
||||||
TableAlias: "t",
|
TableAlias: "t",
|
||||||
|
@ -81,3 +112,67 @@ func TestIn(t *testing.T) {
|
||||||
t.Errorf("Expected resultMap to be equal to result")
|
t.Errorf("Expected resultMap to be equal to result")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNotIn(t *testing.T) {
|
||||||
|
ctx := SQLiteContext{
|
||||||
|
TableAlias: "t",
|
||||||
|
FieldName: "test",
|
||||||
|
}
|
||||||
|
result := Convert(ctx, `{"$nin": [1, 2, 3]}`)
|
||||||
|
resultMap := Convert(ctx, map[string]any{"$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)
|
||||||
|
}
|
||||||
|
if resultMap != result {
|
||||||
|
t.Log(resultMap)
|
||||||
|
t.Errorf("Expected resultMap to be equal to result")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLike(t *testing.T) {
|
||||||
|
ctx := SQLiteContext{
|
||||||
|
TableAlias: "t",
|
||||||
|
FieldName: "test",
|
||||||
|
}
|
||||||
|
result := Convert(ctx, `{"$like": "199_"}`)
|
||||||
|
resultMap := Convert(ctx, map[string]any{"$like": "199_"})
|
||||||
|
if result != `t.test LIKE '199_' ESCAPE '\'` {
|
||||||
|
t.Errorf("Expected t.test LIKE '199_' ESCAPE '\\', got %s", result)
|
||||||
|
}
|
||||||
|
if resultMap != result {
|
||||||
|
t.Log(resultMap)
|
||||||
|
t.Errorf("Expected resultMap to be equal to result")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAnd(t *testing.T) {
|
||||||
|
ctx := SQLiteContext{
|
||||||
|
TableAlias: "t",
|
||||||
|
FieldName: "test",
|
||||||
|
}
|
||||||
|
result := Convert(ctx, `{"$and": ["a > 0", "b < 10"]}`)
|
||||||
|
resultMap := Convert(ctx, map[string]any{"$and": []string{"a > 0", "b < 10"}})
|
||||||
|
if result != `(a > 0 AND b < 10)` {
|
||||||
|
t.Errorf("Expected (a > 0 AND b < 10), got %s", result)
|
||||||
|
}
|
||||||
|
if resultMap != result {
|
||||||
|
t.Log(resultMap)
|
||||||
|
t.Errorf("Expected resultMap to be equal to result")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOr(t *testing.T) {
|
||||||
|
ctx := SQLiteContext{
|
||||||
|
TableAlias: "t",
|
||||||
|
FieldName: "test",
|
||||||
|
}
|
||||||
|
result := Convert(ctx, `{"$or": ["a = 0", "b < 10"]}`)
|
||||||
|
resultMap := Convert(ctx, map[string]any{"$or": []string{"a = 0", "b < 10"}})
|
||||||
|
if result != `(a = 0 OR b < 10)` {
|
||||||
|
t.Errorf("Expected (a > 0 OR b < 10), got %s", result)
|
||||||
|
}
|
||||||
|
if resultMap != result {
|
||||||
|
t.Log(resultMap)
|
||||||
|
t.Errorf("Expected resultMap to be equal to result")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue