diff --git a/pkg/ql/flavours.go b/pkg/ql/flavours.go new file mode 100644 index 000000000..c645170bd --- /dev/null +++ b/pkg/ql/flavours.go @@ -0,0 +1,21 @@ +package ql + +type ( + Encoder interface { + // CaseInsensitiveLike translates "like" or "not like" op to case-insensitive version + // supported by the db + CaseInsensitiveLike(neg bool) string + } +) + +var ( + // QueryEncoder + // This is a temp solution to enable multi-db support in the ql package + // that is not aware of the SQL flavour + // + // We can get away with this kind of solution right now because we are currently + // only supporting one single db at the time. + // + // This will change in the future and so will the pkg/ql logic + QueryEncoder Encoder +) diff --git a/pkg/ql/squirrel.go b/pkg/ql/squirrel.go index f20e49c71..8a09fdf5d 100644 --- a/pkg/ql/squirrel.go +++ b/pkg/ql/squirrel.go @@ -103,7 +103,7 @@ func (n Operator) ToSql() (string, []interface{}, error) { switch n.Kind { case "LIKE", "NOT LIKE": // Make sure we are doing case insensitive search - op = "COLLATE utf8_general_ci " + n.Kind + op = QueryEncoder.CaseInsensitiveLike(n.Kind == "NOT LIKE") } return " " + op + " ", nil, nil diff --git a/store/mysql/encoder.go b/store/mysql/encoder.go new file mode 100644 index 000000000..562ae0c35 --- /dev/null +++ b/store/mysql/encoder.go @@ -0,0 +1,19 @@ +package mysql + +import "github.com/cortezaproject/corteza-server/pkg/ql" + +type ( + // QueryEncoder provides query parts encoding rules for MySQL + // see ql.QueryEncoder for mor info + QueryEncoder struct{} +) + +var _ ql.Encoder = &QueryEncoder{} + +func (QueryEncoder) CaseInsensitiveLike(neg bool) string { + if neg { + return "COLLATE utf8_unicode_ci NOT LIKE" + } else { + return "COLLATE utf8_unicode_ci LIKE" + } +} diff --git a/store/mysql/mysql.go b/store/mysql/mysql.go index f617bef18..2100d1e6a 100644 --- a/store/mysql/mysql.go +++ b/store/mysql/mysql.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "github.com/Masterminds/squirrel" + "github.com/cortezaproject/corteza-server/pkg/ql" "github.com/cortezaproject/corteza-server/store" "github.com/cortezaproject/corteza-server/store/rdbms" "github.com/cortezaproject/corteza-server/store/rdbms/instrumentation" @@ -53,6 +54,8 @@ func Connect(ctx context.Context, dsn string) (store.Storer, error) { // for details s.DB().ExecContext(ctx, "SET SESSION sql_mode = 'ANSI'") + ql.QueryEncoder = &QueryEncoder{} + return s, nil } diff --git a/store/postgres/encoder.go b/store/postgres/encoder.go new file mode 100644 index 000000000..b3d37c346 --- /dev/null +++ b/store/postgres/encoder.go @@ -0,0 +1,19 @@ +package postgres + +import "github.com/cortezaproject/corteza-server/pkg/ql" + +type ( + // QueryEncoder provides query parts encoding rules for Postgres + // see ql.QueryEncoder for mor info + QueryEncoder struct{} +) + +var _ ql.Encoder = &QueryEncoder{} + +func (QueryEncoder) CaseInsensitiveLike(neg bool) string { + if neg { + return "NOT ILIKE" + } else { + return "ILIKE" + } +} diff --git a/store/postgres/postgres.go b/store/postgres/postgres.go index b29d1082c..09e585fe9 100644 --- a/store/postgres/postgres.go +++ b/store/postgres/postgres.go @@ -5,6 +5,7 @@ import ( "database/sql" "fmt" "github.com/Masterminds/squirrel" + "github.com/cortezaproject/corteza-server/pkg/ql" "github.com/cortezaproject/corteza-server/store" "github.com/cortezaproject/corteza-server/store/rdbms" "github.com/cortezaproject/corteza-server/store/rdbms/instrumentation" @@ -47,6 +48,8 @@ func Connect(ctx context.Context, dsn string) (store.Storer, error) { return nil, err } + ql.QueryEncoder = &QueryEncoder{} + return s, nil } diff --git a/store/sqlite3/encoder.go b/store/sqlite3/encoder.go new file mode 100644 index 000000000..46228e68a --- /dev/null +++ b/store/sqlite3/encoder.go @@ -0,0 +1,19 @@ +package sqlite3 + +import "github.com/cortezaproject/corteza-server/pkg/ql" + +type ( + // QueryEncoder provides query parts encoding rules for SQLite + // see ql.QueryEncoder for mor info + QueryEncoder struct{} +) + +var _ ql.Encoder = &QueryEncoder{} + +func (QueryEncoder) CaseInsensitiveLike(neg bool) string { + if neg { + return "COLLATE utf8_unicode_ci NOT LIKE" + } else { + return "COLLATE utf8_unicode_ci LIKE" + } +} diff --git a/store/sqlite3/sqlite3.go b/store/sqlite3/sqlite3.go index 96eda8fc3..275ee50f5 100644 --- a/store/sqlite3/sqlite3.go +++ b/store/sqlite3/sqlite3.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "github.com/Masterminds/squirrel" + "github.com/cortezaproject/corteza-server/pkg/ql" "github.com/cortezaproject/corteza-server/store" "github.com/cortezaproject/corteza-server/store/rdbms" "github.com/cortezaproject/corteza-server/store/rdbms/instrumentation" @@ -51,6 +52,8 @@ func Connect(ctx context.Context, dsn string) (store.Storer, error) { return nil, err } + ql.QueryEncoder = &QueryEncoder{} + return s, nil } diff --git a/store/tests/compose_records_test.go b/store/tests/compose_records_test.go index 6f5479bf6..186a12c94 100644 --- a/store/tests/compose_records_test.go +++ b/store/tests/compose_records_test.go @@ -340,6 +340,16 @@ func testComposeRecords(t *testing.T, s store.ComposeRecords) { req.NoError(err) req.Len(set, 1) }) + + t.Run("with like op", func(t *testing.T) { + var ( + req = require.New(t) + f = types.RecordFilter{Query: `str3 LIKE '%“2020%'`} + + _, _, err = s.SearchComposeRecords(ctx, mod, f) + ) + req.NoError(err) + }) }) t.Run("paging and sorting", func(t *testing.T) {