Add explicit type cast to JSONB for PSQL
Explicit type casting was needed for timezone to cast into jsonb.
This commit is contained in:
@@ -287,7 +287,7 @@ func (i *iterator) collectCursorValues(r dal.ValueGetter) (_ *filter.PagingCurso
|
||||
}
|
||||
|
||||
if len(pKeys) == 0 {
|
||||
//return nil, fmt.Errorf("can not construct cursor without primary key attributes")
|
||||
// return nil, fmt.Errorf("can not construct cursor without primary key attributes")
|
||||
}
|
||||
|
||||
for _, c := range i.sorting {
|
||||
|
||||
@@ -45,7 +45,7 @@ type (
|
||||
// Literal values need to be JSON docs!
|
||||
//
|
||||
// @todo recheck if we really need JsonArrayContains on Dialect interface
|
||||
JsonArrayContains(needle, haystack exp.Expression) (exp.Expression, error)
|
||||
JsonArrayContains(needle, haystack exp.Expression, nodeRef string) (exp.Expression, error)
|
||||
|
||||
// AttributeCast prepares complex SQL expression that verifies
|
||||
// arbitrary string value in the db and casts it to b used in
|
||||
@@ -110,7 +110,9 @@ func OpHandlerNotIn(d Dialect, n *ql.ASTNode, args ...exp.Expression) (expr exp.
|
||||
}
|
||||
|
||||
func opHandlerIn(d Dialect, n *ql.ASTNode, negate bool, args ...exp.Expression) (expr exp.Expression, err error) {
|
||||
if len(n.Args) == 2 && n.Args[1] != nil && n.Args[1].Meta["dal.Attribute"] != nil && n.Args[1].Meta["dal.Attribute"].(*dal.Attribute).MultiValue {
|
||||
// @todo: this needs to be refactor to handle json extraction for different types depending on the node layers
|
||||
if len(n.Args) == 2 && n.Args[1] != nil && (n.Args[1].Meta["dal.Attribute"] != nil && n.Args[1].Meta["dal.Attribute"].(*dal.Attribute).MultiValue) || n.Args[1].Ref == "TIMESTAMP" {
|
||||
nodeRef := n.Args[1].Ref
|
||||
// if right-side argument is multi-value attribute,
|
||||
// then we need to adjust the arguments a bit:
|
||||
// 1) left side, if it is a value, is encoded as JSON
|
||||
@@ -118,9 +120,6 @@ func opHandlerIn(d Dialect, n *ql.ASTNode, negate bool, args ...exp.Expression)
|
||||
//
|
||||
// right side, access JSON encoded array of values.
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
for a := range n.Args {
|
||||
left := a == 0
|
||||
|
||||
@@ -180,7 +179,7 @@ func opHandlerIn(d Dialect, n *ql.ASTNode, negate bool, args ...exp.Expression)
|
||||
}
|
||||
}
|
||||
|
||||
expr, err = d.JsonArrayContains(args[0], args[1])
|
||||
expr, err = d.JsonArrayContains(args[0], args[1], nodeRef)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ func (d mysqlDialect) JsonExtractUnquote(jsonDoc exp.Expression, pp ...any) (_ e
|
||||
// JSON_CONTAINS(v, '"needle"', '$.f2')
|
||||
//
|
||||
// This approach is not optimal, but it is the only way to make it work
|
||||
func (d mysqlDialect) JsonArrayContains(needle, haystack exp.Expression) (_ exp.Expression, err error) {
|
||||
func (d mysqlDialect) JsonArrayContains(needle, haystack exp.Expression, _ string) (_ exp.Expression, err error) {
|
||||
return exp.NewSQLFunctionExpression("JSON_CONTAINS", haystack, needle), nil
|
||||
}
|
||||
|
||||
|
||||
@@ -64,8 +64,16 @@ func (d postgresDialect) JsonExtractUnquote(ident exp.Expression, pp ...any) (ex
|
||||
//
|
||||
// single-value field = multi-value field / plain
|
||||
// v->'f1'->0 <@ (v->'f0')::JSONB
|
||||
func (d postgresDialect) JsonArrayContains(needle, haystack exp.Expression) (exp.Expression, error) {
|
||||
return exp.NewLiteralExpression("(?)::JSONB <@ (?)::JSONB", needle, haystack), nil
|
||||
//
|
||||
// Timestamp field must to cast into text
|
||||
// TO_JSONB('value') <@ TO_JSONB(v->'f0')
|
||||
func (d postgresDialect) JsonArrayContains(needle, haystack exp.Expression, nodeRef string) (exp.Expression, error) {
|
||||
switch nodeRef {
|
||||
case "TIMESTAMP":
|
||||
return exp.NewLiteralExpression("TO_JSONB(?) <@ TO_JSONB(?)", needle, haystack), nil
|
||||
default:
|
||||
return exp.NewLiteralExpression("(?)::jsonb <@ TO_JSONB(?)::jsonb", needle, haystack), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (d postgresDialect) TableCodec(m *dal.Model) drivers.TableCodec {
|
||||
|
||||
@@ -79,7 +79,7 @@ func (sqliteDialect) JsonExtractUnquote(ident exp.Expression, pp ...any) (exp.Ex
|
||||
//
|
||||
// Unfortunately SQLite converts boolean values into 0 and 1 when decoding from
|
||||
// JSON and we need a special handler for that.
|
||||
func (sqliteDialect) JsonArrayContains(needle, haystack exp.Expression) (exp.Expression, error) {
|
||||
func (sqliteDialect) JsonArrayContains(needle, haystack exp.Expression, _ string) (exp.Expression, error) {
|
||||
// @todo should be implemented using native SQLite capabilties and
|
||||
// not through custom JSON_ARRAY_CONTAINS function
|
||||
return exp.NewLiteralExpression("JSON_ARRAY_CONTAINS(?, ?)", needle, haystack), nil
|
||||
|
||||
@@ -69,6 +69,7 @@ func TestJSONOp(t *testing.T) {
|
||||
contains, err := conn.dialect.JsonArrayContains(
|
||||
exp.NewLiteralExpression("?", val),
|
||||
a2e(attr),
|
||||
"",
|
||||
)
|
||||
req.NoError(err)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user