3
0

Fix query interval definitions for date add/sub

This commit is contained in:
Tomaž Jerman
2022-09-27 22:32:02 +02:00
parent 2d07357a75
commit 7360b72dbf
4 changed files with 72 additions and 11 deletions

View File

@@ -236,7 +236,10 @@ func (n interval) ToAST() (out *ASTNode) {
return &ASTNode{
Ref: "interval",
Args: ASTNodeSet{
{Symbol: n.unit},
// @todo consider introducing a new concept on the ASTNode to cover
// system defined symbols/keywords. This is a temporary solutions
// to fix reporting interval definitions; it should eventually be reworked
{Value: MakeValueOf("String", n.unit)},
{Value: MakeValueOf("Number", n.value)},
},
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"database/sql"
"fmt"
"github.com/cortezaproject/corteza-server/pkg/errors"
"github.com/cortezaproject/corteza-server/pkg/dal"

View File

@@ -63,17 +63,41 @@ var (
},
},
"interval": {
Handler: func(args ...exp.Expression) exp.Expression {
// The problem here is that PGSQL, to my findings, doesn't have functions to add/sub dates
// like MySQL for example.
//
// We need to construct an expression in the lines of `INTERVAL 'N UNIT'` which
// then becomes, for example, d + INTERVAL 'N UNIT'.
//
// The problem #2 is that we can't just use value placeholders in string literals
// nor is there a 2 arg function to make an interval. There is a make_interval function
// but that one won't do.
//
// So...
// (? || 'S') makes the interval label a plural because MySQL uses singular and that
// is what QL supports. PgSQL uses plural, such as years, months, and days.
//
// The rest of the expression is just to construct the string which can then be casted to INTERVAL
// which can then be used in date math, which is done with regular math operators.
return exp.NewLiteralExpression("(?::INTEGER || ' ' || (? || 'S'))::INTERVAL", args[1], args[0])
},
},
"date_add": {
Handler: func(args ...exp.Expression) exp.Expression {
return exp.NewLiteralExpression("(? + ?)", args[0], args[1])
},
},
"date_sub": {
Handler: func(args ...exp.Expression) exp.Expression {
return exp.NewLiteralExpression("(? - ?)", args[0], args[1])
},
},
// functions currently unsupported in PostgreSQL store backend
//"DATE_ADD": {
// Handler: func(args ...exp.Expression) exp.Expression {
// return exp.NewLiteralExpression("")
// },
//},
//"DATE_SUB": {
// Handler: func(args ...exp.Expression) exp.Expression {
// return exp.NewLiteralExpression("")
// },
//},
//"STD": {
// Handler: func(args ...exp.Expression) exp.Expression {
// return exp.NewLiteralExpression("")

View File

@@ -5,6 +5,7 @@ import (
"strings"
"github.com/cortezaproject/corteza-server/pkg/ql"
"github.com/doug-martin/goqu/v9"
"github.com/doug-martin/goqu/v9/exp"
)
@@ -117,6 +118,38 @@ var (
},
},
"interval": {
Handler: func(args ...exp.Expression) exp.Expression {
// The problem here is similar to the one with PgSQL... but more complicated...
// The interval duration identifiers are keywords and can't be bound via value placeholders.
// This forces us to interpolate the thing when building the literal expression below.
//
// Since goqu doesn't let me get the raw value of the expression... I was forced
// to do this calamity
_, aa, err := goqu.Select(args[0]).ToSQL()
if err != nil {
// This error should never occur
panic(err)
}
intv := aa[0].(string)
return exp.NewLiteralExpression(fmt.Sprintf("INTERVAL ? %s", intv), args[1])
},
},
"date_add": {
Handler: func(args ...exp.Expression) exp.Expression {
return exp.NewSQLFunctionExpression("DATE_ADD", args[0], args[1])
},
},
"date_sub": {
Handler: func(args ...exp.Expression) exp.Expression {
return exp.NewSQLFunctionExpression("DATE_SUB", args[0], args[1])
},
},
// @todo better negation?
"like": {
Handler: func(args ...exp.Expression) exp.Expression {