340 lines
14 KiB
Go
340 lines
14 KiB
Go
package sqlgen_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"git.fsdpf.net/go/db/v2/exp"
|
|
"git.fsdpf.net/go/db/v2/internal/sb"
|
|
"git.fsdpf.net/go/db/v2/sqlgen"
|
|
"github.com/stretchr/testify/suite"
|
|
)
|
|
|
|
type (
|
|
commonSQLTestCase struct {
|
|
gen func(builder sb.SQLBuilder)
|
|
sql string
|
|
isPrepared bool
|
|
err string
|
|
args []interface{}
|
|
}
|
|
commonSQLGeneratorSuite struct {
|
|
baseSQLGeneratorSuite
|
|
}
|
|
)
|
|
|
|
func (csgs *commonSQLGeneratorSuite) assertCases(testCases ...commonSQLTestCase) {
|
|
for _, tc := range testCases {
|
|
b := sb.NewSQLBuilder(tc.isPrepared)
|
|
tc.gen(b)
|
|
switch {
|
|
case len(tc.err) > 0:
|
|
csgs.assertErrorSQL(b, tc.err)
|
|
case tc.isPrepared:
|
|
csgs.assertPreparedSQL(b, tc.sql, tc.args)
|
|
default:
|
|
csgs.assertNotPreparedSQL(b, tc.sql)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (csgs *commonSQLGeneratorSuite) TestReturningSQL() {
|
|
returningGen := func(csgs sqlgen.CommonSQLGenerator) func(sb.SQLBuilder) {
|
|
return func(sb sb.SQLBuilder) {
|
|
csgs.ReturningSQL(sb, exp.NewColumnListExpression("a", "b"))
|
|
}
|
|
}
|
|
|
|
returningNoColsGen := func(csgs sqlgen.CommonSQLGenerator) func(sb.SQLBuilder) {
|
|
return func(sb sb.SQLBuilder) {
|
|
csgs.ReturningSQL(sb, exp.NewColumnListExpression())
|
|
}
|
|
}
|
|
|
|
returningNilExpGen := func(csgs sqlgen.CommonSQLGenerator) func(sb.SQLBuilder) {
|
|
return func(sb sb.SQLBuilder) {
|
|
csgs.ReturningSQL(sb, nil)
|
|
}
|
|
}
|
|
|
|
opts := sqlgen.DefaultDialectOptions()
|
|
opts.SupportsReturn = true
|
|
csgs1 := sqlgen.NewCommonSQLGenerator("test", opts)
|
|
|
|
opts2 := sqlgen.DefaultDialectOptions()
|
|
opts2.SupportsReturn = false
|
|
csgs2 := sqlgen.NewCommonSQLGenerator("test", opts2)
|
|
|
|
csgs.assertCases(
|
|
commonSQLTestCase{gen: returningGen(csgs1), sql: ` RETURNING "a", "b"`},
|
|
commonSQLTestCase{gen: returningGen(csgs1), sql: ` RETURNING "a", "b"`, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: returningNoColsGen(csgs1), sql: ``},
|
|
commonSQLTestCase{gen: returningNoColsGen(csgs1), sql: ``, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: returningNilExpGen(csgs1), sql: ``},
|
|
commonSQLTestCase{gen: returningNilExpGen(csgs1), sql: ``, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: returningGen(csgs2), err: `db: dialect does not support RETURNING clause [dialect=test]`},
|
|
commonSQLTestCase{gen: returningGen(csgs2), err: `db: dialect does not support RETURNING clause [dialect=test]`},
|
|
)
|
|
}
|
|
|
|
func (csgs *commonSQLGeneratorSuite) TestFromSQL() {
|
|
fromGen := func(csgs sqlgen.CommonSQLGenerator) func(sb.SQLBuilder) {
|
|
return func(sb sb.SQLBuilder) {
|
|
csgs.FromSQL(sb, exp.NewColumnListExpression("a", "b"))
|
|
}
|
|
}
|
|
|
|
fromNoColsGen := func(csgs sqlgen.CommonSQLGenerator) func(sb.SQLBuilder) {
|
|
return func(sb sb.SQLBuilder) {
|
|
csgs.FromSQL(sb, exp.NewColumnListExpression())
|
|
}
|
|
}
|
|
|
|
fromNilExpGen := func(csgs sqlgen.CommonSQLGenerator) func(sb.SQLBuilder) {
|
|
return func(sb sb.SQLBuilder) {
|
|
csgs.FromSQL(sb, nil)
|
|
}
|
|
}
|
|
|
|
csg := sqlgen.NewCommonSQLGenerator("test", sqlgen.DefaultDialectOptions())
|
|
|
|
opts := sqlgen.DefaultDialectOptions()
|
|
opts.FromFragment = []byte(" from")
|
|
csgFromFrag := sqlgen.NewCommonSQLGenerator("test", opts)
|
|
|
|
csgs.assertCases(
|
|
commonSQLTestCase{gen: fromGen(csg), sql: ` FROM "a", "b"`},
|
|
commonSQLTestCase{gen: fromGen(csg), sql: ` FROM "a", "b"`, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: fromNoColsGen(csg), sql: ``},
|
|
commonSQLTestCase{gen: fromNoColsGen(csg), sql: ``, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: fromNilExpGen(csg), sql: ``},
|
|
commonSQLTestCase{gen: fromNilExpGen(csg), sql: ``, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: fromGen(csgFromFrag), sql: ` from "a", "b"`},
|
|
commonSQLTestCase{gen: fromGen(csgFromFrag), sql: ` from "a", "b"`, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: fromNoColsGen(csgFromFrag), sql: ``},
|
|
commonSQLTestCase{gen: fromNoColsGen(csgFromFrag), sql: ``, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: fromNilExpGen(csgFromFrag), sql: ``},
|
|
commonSQLTestCase{gen: fromNilExpGen(csgFromFrag), sql: ``, isPrepared: true, args: emptyArgs},
|
|
)
|
|
}
|
|
|
|
func (csgs *commonSQLGeneratorSuite) TestWhereSQL() {
|
|
whereAndGen := func(csgs sqlgen.CommonSQLGenerator, exps ...exp.Expression) func(sb.SQLBuilder) {
|
|
return func(sb sb.SQLBuilder) {
|
|
csgs.WhereSQL(sb, exp.NewExpressionList(exp.AndType, exps...))
|
|
}
|
|
}
|
|
|
|
whereOrGen := func(csgs sqlgen.CommonSQLGenerator, exps ...exp.Expression) func(sb.SQLBuilder) {
|
|
return func(sb sb.SQLBuilder) {
|
|
csgs.WhereSQL(sb, exp.NewExpressionList(exp.OrType, exps...))
|
|
}
|
|
}
|
|
|
|
csg := sqlgen.NewCommonSQLGenerator("test", sqlgen.DefaultDialectOptions())
|
|
|
|
opts := sqlgen.DefaultDialectOptions()
|
|
opts.WhereFragment = []byte(" where ")
|
|
csgWhereFrag := sqlgen.NewCommonSQLGenerator("test", opts)
|
|
|
|
w := exp.Ex{"a": "b"}
|
|
w2 := exp.Ex{"b": "c"}
|
|
|
|
csgs.assertCases(
|
|
commonSQLTestCase{gen: whereAndGen(csg), sql: ``},
|
|
commonSQLTestCase{gen: whereAndGen(csg), sql: ``, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: whereAndGen(csg, w), sql: ` WHERE ("a" = 'b')`},
|
|
commonSQLTestCase{gen: whereAndGen(csg, w), sql: ` WHERE ("a" = ?)`, isPrepared: true, args: []interface{}{"b"}},
|
|
|
|
commonSQLTestCase{gen: whereAndGen(csg, w, w2), sql: ` WHERE (("a" = 'b') AND ("b" = 'c'))`},
|
|
commonSQLTestCase{gen: whereAndGen(csg, w, w2), sql: ` WHERE (("a" = ?) AND ("b" = ?))`, isPrepared: true, args: []interface{}{"b", "c"}},
|
|
|
|
commonSQLTestCase{gen: whereOrGen(csg), sql: ``},
|
|
commonSQLTestCase{gen: whereOrGen(csg), sql: ``, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: whereOrGen(csg, w), sql: ` WHERE ("a" = 'b')`},
|
|
commonSQLTestCase{gen: whereOrGen(csg, w), sql: ` WHERE ("a" = ?)`, isPrepared: true, args: []interface{}{"b"}},
|
|
|
|
commonSQLTestCase{gen: whereOrGen(csg, w, w2), sql: ` WHERE (("a" = 'b') OR ("b" = 'c'))`},
|
|
commonSQLTestCase{gen: whereOrGen(csg, w, w2), sql: ` WHERE (("a" = ?) OR ("b" = ?))`, isPrepared: true, args: []interface{}{"b", "c"}},
|
|
|
|
commonSQLTestCase{gen: whereAndGen(csgWhereFrag), sql: ``},
|
|
commonSQLTestCase{gen: whereAndGen(csgWhereFrag), sql: ``, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: whereAndGen(csgWhereFrag, w), sql: ` where ("a" = 'b')`},
|
|
commonSQLTestCase{gen: whereAndGen(csgWhereFrag, w), sql: ` where ("a" = ?)`, isPrepared: true, args: []interface{}{"b"}},
|
|
|
|
commonSQLTestCase{gen: whereAndGen(csgWhereFrag, w, w2), sql: ` where (("a" = 'b') AND ("b" = 'c'))`},
|
|
commonSQLTestCase{
|
|
gen: whereAndGen(csgWhereFrag, w, w2),
|
|
sql: ` where (("a" = ?) AND ("b" = ?))`,
|
|
isPrepared: true,
|
|
args: []interface{}{"b", "c"},
|
|
},
|
|
|
|
commonSQLTestCase{gen: whereOrGen(csgWhereFrag), sql: ``},
|
|
commonSQLTestCase{gen: whereOrGen(csgWhereFrag), sql: ``, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: whereOrGen(csgWhereFrag, w), sql: ` where ("a" = 'b')`},
|
|
commonSQLTestCase{gen: whereOrGen(csgWhereFrag, w), sql: ` where ("a" = ?)`, isPrepared: true, args: []interface{}{"b"}},
|
|
|
|
commonSQLTestCase{gen: whereOrGen(csgWhereFrag, w, w2), sql: ` where (("a" = 'b') OR ("b" = 'c'))`},
|
|
commonSQLTestCase{
|
|
gen: whereOrGen(csgWhereFrag, w, w2),
|
|
sql: ` where (("a" = ?) OR ("b" = ?))`,
|
|
isPrepared: true,
|
|
args: []interface{}{"b", "c"},
|
|
},
|
|
)
|
|
}
|
|
|
|
func (csgs *commonSQLGeneratorSuite) TestOrderSQL() {
|
|
orderGen := func(csgs sqlgen.CommonSQLGenerator, o ...exp.OrderedExpression) func(sb.SQLBuilder) {
|
|
return func(sb sb.SQLBuilder) {
|
|
csgs.OrderSQL(sb, exp.NewOrderedColumnList(o...))
|
|
}
|
|
}
|
|
|
|
csg := sqlgen.NewCommonSQLGenerator("test", sqlgen.DefaultDialectOptions())
|
|
|
|
opts := sqlgen.DefaultDialectOptions()
|
|
// override fragments to ensure they are used
|
|
opts.OrderByFragment = []byte(" order by ")
|
|
opts.AscFragment = []byte(" asc")
|
|
opts.DescFragment = []byte(" desc")
|
|
opts.NullsFirstFragment = []byte(" nulls first")
|
|
opts.NullsLastFragment = []byte(" nulls last")
|
|
csgCustom := sqlgen.NewCommonSQLGenerator("test", opts)
|
|
|
|
ident := exp.NewIdentifierExpression("", "", "a")
|
|
oa := ident.Asc()
|
|
oanf := ident.Asc().NullsFirst()
|
|
oanl := ident.Asc().NullsLast()
|
|
|
|
od := ident.Desc()
|
|
odnf := ident.Desc().NullsFirst()
|
|
odnl := ident.Desc().NullsLast()
|
|
|
|
csgs.assertCases(
|
|
commonSQLTestCase{gen: orderGen(csg), sql: ``},
|
|
commonSQLTestCase{gen: orderGen(csg), sql: ``, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: orderGen(csg, oa), sql: ` ORDER BY "a" ASC`},
|
|
commonSQLTestCase{gen: orderGen(csg, oa), sql: ` ORDER BY "a" ASC`, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: orderGen(csg, oanf), sql: ` ORDER BY "a" ASC NULLS FIRST`},
|
|
commonSQLTestCase{gen: orderGen(csg, oanf), sql: ` ORDER BY "a" ASC NULLS FIRST`, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: orderGen(csg, oanl), sql: ` ORDER BY "a" ASC NULLS LAST`},
|
|
commonSQLTestCase{gen: orderGen(csg, oanl), sql: ` ORDER BY "a" ASC NULLS LAST`, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: orderGen(csg, od), sql: ` ORDER BY "a" DESC`},
|
|
commonSQLTestCase{gen: orderGen(csg, od), sql: ` ORDER BY "a" DESC`, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: orderGen(csg, odnf), sql: ` ORDER BY "a" DESC NULLS FIRST`},
|
|
commonSQLTestCase{gen: orderGen(csg, odnf), sql: ` ORDER BY "a" DESC NULLS FIRST`, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: orderGen(csg, odnl), sql: ` ORDER BY "a" DESC NULLS LAST`},
|
|
commonSQLTestCase{gen: orderGen(csg, odnl), sql: ` ORDER BY "a" DESC NULLS LAST`, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: orderGen(csg, oa, od), sql: ` ORDER BY "a" ASC, "a" DESC`},
|
|
commonSQLTestCase{gen: orderGen(csg, oa, od), sql: ` ORDER BY "a" ASC, "a" DESC`, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: orderGen(csgCustom), sql: ``},
|
|
commonSQLTestCase{gen: orderGen(csgCustom), sql: ``, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: orderGen(csgCustom, oa), sql: ` order by "a" asc`},
|
|
commonSQLTestCase{gen: orderGen(csgCustom, oa), sql: ` order by "a" asc`, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: orderGen(csgCustom, oanf), sql: ` order by "a" asc nulls first`},
|
|
commonSQLTestCase{gen: orderGen(csgCustom, oanf), sql: ` order by "a" asc nulls first`, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: orderGen(csgCustom, oanl), sql: ` order by "a" asc nulls last`},
|
|
commonSQLTestCase{gen: orderGen(csgCustom, oanl), sql: ` order by "a" asc nulls last`, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: orderGen(csgCustom, od), sql: ` order by "a" desc`},
|
|
commonSQLTestCase{gen: orderGen(csgCustom, od), sql: ` order by "a" desc`, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: orderGen(csgCustom, odnf), sql: ` order by "a" desc nulls first`},
|
|
commonSQLTestCase{gen: orderGen(csgCustom, odnf), sql: ` order by "a" desc nulls first`, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: orderGen(csgCustom, odnl), sql: ` order by "a" desc nulls last`},
|
|
commonSQLTestCase{gen: orderGen(csgCustom, odnl), sql: ` order by "a" desc nulls last`, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: orderGen(csgCustom, oa, od), sql: ` order by "a" asc, "a" desc`},
|
|
commonSQLTestCase{gen: orderGen(csgCustom, oa, od), sql: ` order by "a" asc, "a" desc`, isPrepared: true, args: emptyArgs},
|
|
)
|
|
}
|
|
|
|
func (csgs *commonSQLGeneratorSuite) TestLimitSQL() {
|
|
limitGen := func(csgs sqlgen.CommonSQLGenerator, l interface{}) func(sb.SQLBuilder) {
|
|
return func(sb sb.SQLBuilder) {
|
|
csgs.LimitSQL(sb, l)
|
|
}
|
|
}
|
|
|
|
csg := sqlgen.NewCommonSQLGenerator("test", sqlgen.DefaultDialectOptions())
|
|
|
|
opts := sqlgen.DefaultDialectOptions()
|
|
opts.LimitFragment = []byte(" limit ")
|
|
csgCustom := sqlgen.NewCommonSQLGenerator("test", opts)
|
|
|
|
l := int64(10)
|
|
la := exp.NewLiteralExpression("ALL")
|
|
|
|
csgs.assertCases(
|
|
commonSQLTestCase{gen: limitGen(csg, nil), sql: ``},
|
|
commonSQLTestCase{gen: limitGen(csg, nil), sql: ``, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: limitGen(csg, l), sql: ` LIMIT 10`},
|
|
commonSQLTestCase{gen: limitGen(csg, l), sql: ` LIMIT ?`, isPrepared: true, args: []interface{}{l}},
|
|
|
|
commonSQLTestCase{gen: limitGen(csg, la), sql: ` LIMIT ALL`},
|
|
commonSQLTestCase{gen: limitGen(csg, la), sql: ` LIMIT ALL`, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: limitGen(csgCustom, nil), sql: ``},
|
|
commonSQLTestCase{gen: limitGen(csgCustom, nil), sql: ``, isPrepared: true, args: emptyArgs},
|
|
|
|
commonSQLTestCase{gen: limitGen(csgCustom, l), sql: ` limit 10`},
|
|
commonSQLTestCase{gen: limitGen(csgCustom, l), sql: ` limit ?`, isPrepared: true, args: []interface{}{l}},
|
|
|
|
commonSQLTestCase{gen: limitGen(csgCustom, la), sql: ` limit ALL`},
|
|
commonSQLTestCase{gen: limitGen(csgCustom, la), sql: ` limit ALL`, isPrepared: true, args: emptyArgs},
|
|
)
|
|
}
|
|
|
|
func (csgs *commonSQLGeneratorSuite) TestUpdateExpressionSQL() {
|
|
updateGen := func(csgs sqlgen.CommonSQLGenerator, ues ...exp.UpdateExpression) func(sb.SQLBuilder) {
|
|
return func(sb sb.SQLBuilder) {
|
|
csgs.UpdateExpressionSQL(sb, ues...)
|
|
}
|
|
}
|
|
|
|
csg := sqlgen.NewCommonSQLGenerator("test", sqlgen.DefaultDialectOptions())
|
|
ue := exp.NewIdentifierExpression("", "", "col").Set("a")
|
|
ue2 := exp.NewIdentifierExpression("", "", "col2").Set("b")
|
|
|
|
csgs.assertCases(
|
|
commonSQLTestCase{gen: updateGen(csg), err: sqlgen.ErrNoUpdatedValuesProvided.Error()},
|
|
commonSQLTestCase{gen: updateGen(csg), err: sqlgen.ErrNoUpdatedValuesProvided.Error()},
|
|
|
|
commonSQLTestCase{gen: updateGen(csg, ue), sql: `"col"='a'`},
|
|
commonSQLTestCase{gen: updateGen(csg, ue), sql: `"col"=?`, isPrepared: true, args: []interface{}{"a"}},
|
|
|
|
commonSQLTestCase{gen: updateGen(csg, ue, ue2), sql: `"col"='a',"col2"='b'`},
|
|
commonSQLTestCase{gen: updateGen(csg, ue, ue2), sql: `"col"=?,"col2"=?`, isPrepared: true, args: []interface{}{"a", "b"}},
|
|
)
|
|
}
|
|
|
|
func TestCommonSQLGenerator(t *testing.T) {
|
|
suite.Run(t, new(commonSQLGeneratorSuite))
|
|
}
|