Add SQLBuilder support for SQLite databases.
This commit is contained in:
parent
d197956271
commit
e8f4c2b31b
50 changed files with 5851 additions and 75 deletions
912
tests/sqlite/alltypes_test.go
Normal file
912
tests/sqlite/alltypes_test.go
Normal file
|
|
@ -0,0 +1,912 @@
|
|||
package sqlite
|
||||
|
||||
import (
|
||||
"github.com/go-jet/jet/v2/internal/testutils"
|
||||
. "github.com/go-jet/jet/v2/sqlite"
|
||||
"github.com/go-jet/jet/v2/tests/.gentestdata/sqlite/test_sample/model"
|
||||
. "github.com/go-jet/jet/v2/tests/.gentestdata/sqlite/test_sample/table"
|
||||
"github.com/go-jet/jet/v2/tests/.gentestdata/sqlite/test_sample/view"
|
||||
"github.com/go-jet/jet/v2/tests/testdata/results/common"
|
||||
"github.com/google/uuid"
|
||||
"github.com/shopspring/decimal"
|
||||
"github.com/stretchr/testify/require"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestAllTypes(t *testing.T) {
|
||||
|
||||
dest := []model.AllTypes{}
|
||||
|
||||
err := SELECT(AllTypes.AllColumns).
|
||||
FROM(AllTypes).
|
||||
Query(sampleDB, &dest)
|
||||
|
||||
require.NoError(t, err)
|
||||
testutils.AssertJSON(t, dest, allTypesJSON)
|
||||
}
|
||||
|
||||
var allTypesJSON = `
|
||||
[
|
||||
{
|
||||
"Boolean": false,
|
||||
"BooleanPtr": true,
|
||||
"TinyInt": -3,
|
||||
"TinyIntPtr": 3,
|
||||
"SmallInt": 14,
|
||||
"SmallIntPtr": 14,
|
||||
"MediumInt": -150,
|
||||
"MediumIntPtr": 150,
|
||||
"Integer": -1600,
|
||||
"IntegerPtr": 1600,
|
||||
"BigInt": 5000,
|
||||
"BigIntPtr": 50000,
|
||||
"Decimal": 1.11,
|
||||
"DecimalPtr": 1.01,
|
||||
"Numeric": 2.22,
|
||||
"NumericPtr": 2.02,
|
||||
"Float": 3.33,
|
||||
"FloatPtr": 3.03,
|
||||
"Double": 4.44,
|
||||
"DoublePtr": 4.04,
|
||||
"Real": 5.55,
|
||||
"RealPtr": 5.05,
|
||||
"Time": "0000-01-01T10:11:12.33Z",
|
||||
"TimePtr": "0000-01-01T10:11:12.123456Z",
|
||||
"Date": "2008-07-04T00:00:00Z",
|
||||
"DatePtr": "2008-07-04T00:00:00Z",
|
||||
"DateTime": "2011-12-18T13:17:17Z",
|
||||
"DateTimePtr": "2011-12-18T13:17:17Z",
|
||||
"Timestamp": "2007-12-31T23:00:01Z",
|
||||
"TimestampPtr": "2007-12-31T23:00:01Z",
|
||||
"Char": "char1",
|
||||
"CharPtr": "char-ptr",
|
||||
"VarChar": "varchar",
|
||||
"VarCharPtr": "varchar-ptr",
|
||||
"Text": "text",
|
||||
"TextPtr": "text-ptr",
|
||||
"Blob": "YmxvYjE=",
|
||||
"BlobPtr": "YmxvYi1wdHI="
|
||||
},
|
||||
{
|
||||
"Boolean": false,
|
||||
"BooleanPtr": null,
|
||||
"TinyInt": -3,
|
||||
"TinyIntPtr": null,
|
||||
"SmallInt": 14,
|
||||
"SmallIntPtr": null,
|
||||
"MediumInt": -150,
|
||||
"MediumIntPtr": null,
|
||||
"Integer": -1600,
|
||||
"IntegerPtr": null,
|
||||
"BigInt": 5000,
|
||||
"BigIntPtr": null,
|
||||
"Decimal": 1.11,
|
||||
"DecimalPtr": null,
|
||||
"Numeric": 2.22,
|
||||
"NumericPtr": null,
|
||||
"Float": 3.33,
|
||||
"FloatPtr": null,
|
||||
"Double": 4.44,
|
||||
"DoublePtr": null,
|
||||
"Real": 5.55,
|
||||
"RealPtr": null,
|
||||
"Time": "0000-01-01T10:11:12.33Z",
|
||||
"TimePtr": null,
|
||||
"Date": "2008-07-04T00:00:00Z",
|
||||
"DatePtr": null,
|
||||
"DateTime": "2011-12-18T13:17:17Z",
|
||||
"DateTimePtr": null,
|
||||
"Timestamp": "2007-12-31T23:00:01Z",
|
||||
"TimestampPtr": null,
|
||||
"Char": "char2",
|
||||
"CharPtr": null,
|
||||
"VarChar": "varchar",
|
||||
"VarCharPtr": null,
|
||||
"Text": "text",
|
||||
"TextPtr": null,
|
||||
"Blob": "YmxvYjI=",
|
||||
"BlobPtr": null
|
||||
}
|
||||
]
|
||||
`
|
||||
|
||||
func TestAllTypesViewSelect(t *testing.T) {
|
||||
var dest []model.AllTypesView
|
||||
|
||||
stmt := SELECT(view.AllTypesView.AllColumns).
|
||||
FROM(view.AllTypesView)
|
||||
|
||||
err := stmt.Query(sampleDB, &dest)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(dest), 2)
|
||||
|
||||
testutils.AssertJSON(t, dest, allTypesJSON)
|
||||
}
|
||||
|
||||
func TestAllTypesInsert(t *testing.T) {
|
||||
tx := beginSampleDBTx(t)
|
||||
|
||||
stmt := AllTypes.INSERT(AllTypes.AllColumns).
|
||||
MODEL(toInsert).
|
||||
RETURNING(AllTypes.AllColumns)
|
||||
|
||||
var inserted model.AllTypes
|
||||
err := stmt.Query(tx, &inserted)
|
||||
|
||||
require.NoError(t, err)
|
||||
testutils.AssertDeepEqual(t, toInsert, inserted, testutils.UnixTimeComparer)
|
||||
|
||||
var dest model.AllTypes
|
||||
err = AllTypes.SELECT(AllTypes.AllColumns).
|
||||
WHERE(AllTypes.BigInt.EQ(Int(toInsert.BigInt))).
|
||||
Query(tx, &dest)
|
||||
|
||||
require.NoError(t, err)
|
||||
testutils.AssertDeepEqual(t, dest, toInsert, testutils.UnixTimeComparer)
|
||||
|
||||
err = tx.Rollback()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
var toInsert = model.AllTypes{
|
||||
Boolean: false,
|
||||
BooleanPtr: testutils.BoolPtr(true),
|
||||
TinyInt: 1,
|
||||
SmallInt: 3,
|
||||
MediumInt: 5,
|
||||
Integer: 7,
|
||||
BigInt: 9,
|
||||
TinyIntPtr: testutils.Int8Ptr(11),
|
||||
SmallIntPtr: testutils.Int16Ptr(33),
|
||||
MediumIntPtr: testutils.Int32Ptr(55),
|
||||
IntegerPtr: testutils.Int32Ptr(77),
|
||||
BigIntPtr: testutils.Int64Ptr(99),
|
||||
Decimal: 11.22,
|
||||
DecimalPtr: testutils.Float64Ptr(33.44),
|
||||
Numeric: 55.66,
|
||||
NumericPtr: testutils.Float64Ptr(77.88),
|
||||
Float: 99.00,
|
||||
FloatPtr: testutils.Float64Ptr(11.22),
|
||||
Double: 33.44,
|
||||
DoublePtr: testutils.Float64Ptr(55.66),
|
||||
Real: 77.88,
|
||||
RealPtr: testutils.Float32Ptr(99.00),
|
||||
Time: time.Date(1, 1, 1, 1, 1, 1, 10, time.UTC),
|
||||
TimePtr: testutils.TimePtr(time.Date(2, 2, 2, 2, 2, 2, 200, time.UTC)),
|
||||
Date: time.Now(),
|
||||
DatePtr: testutils.TimePtr(time.Now()),
|
||||
DateTime: time.Now(),
|
||||
DateTimePtr: testutils.TimePtr(time.Now()),
|
||||
Timestamp: time.Now(),
|
||||
TimestampPtr: testutils.TimePtr(time.Now()),
|
||||
Char: "abcd",
|
||||
CharPtr: testutils.StringPtr("absd"),
|
||||
VarChar: "abcd",
|
||||
VarCharPtr: testutils.StringPtr("absd"),
|
||||
Blob: []byte("large file"),
|
||||
BlobPtr: testutils.ByteArrayPtr([]byte("very large file")),
|
||||
Text: "some text",
|
||||
TextPtr: testutils.StringPtr("text"),
|
||||
}
|
||||
|
||||
func TestUUID(t *testing.T) {
|
||||
query := SELECT(
|
||||
//Raw("uuid()").AS("uuid"),
|
||||
String("dc8daae3-b83b-11e9-8eb4-98ded00c39c6").AS("str_uuid"),
|
||||
)
|
||||
|
||||
var dest struct {
|
||||
UUID uuid.UUID
|
||||
StrUUID *uuid.UUID
|
||||
}
|
||||
|
||||
err := query.Query(sampleDB, &dest)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, dest.StrUUID.String(), "dc8daae3-b83b-11e9-8eb4-98ded00c39c6")
|
||||
requireLogged(t, query)
|
||||
}
|
||||
|
||||
func TestExpressionOperators(t *testing.T) {
|
||||
query := SELECT(
|
||||
AllTypes.Integer.IS_NULL().AS("result.is_null"),
|
||||
AllTypes.DatePtr.IS_NOT_NULL().AS("result.is_not_null"),
|
||||
AllTypes.SmallIntPtr.IN(Int(11), Int(22)).AS("result.in"),
|
||||
AllTypes.SmallIntPtr.IN(AllTypes.SELECT(AllTypes.Integer)).AS("result.in_select"),
|
||||
|
||||
Raw("length(121232459)").AS("result.raw"),
|
||||
Raw(":first + COALESCE(all_types.small_int_ptr, 0) + :second", RawArgs{":first": 78, ":second": 56}).
|
||||
AS("result.raw_arg"),
|
||||
Raw("#1 + all_types.integer + #2 + #1 + #3 + #4", RawArgs{"#1": 11, "#2": 22, "#3": 33, "#4": 44}).
|
||||
AS("result.raw_arg2"),
|
||||
|
||||
AllTypes.SmallIntPtr.NOT_IN(Int(11), Int(22), NULL).AS("result.not_in"),
|
||||
AllTypes.SmallIntPtr.NOT_IN(AllTypes.SELECT(AllTypes.Integer)).AS("result.not_in_select"),
|
||||
).FROM(
|
||||
AllTypes,
|
||||
).LIMIT(2)
|
||||
|
||||
testutils.AssertStatementSql(t, query, strings.Replace(`
|
||||
SELECT all_types.integer IS NULL AS "result.is_null",
|
||||
all_types.date_ptr IS NOT NULL AS "result.is_not_null",
|
||||
(all_types.small_int_ptr IN (?, ?)) AS "result.in",
|
||||
(all_types.small_int_ptr IN (
|
||||
SELECT all_types.integer AS "all_types.integer"
|
||||
FROM all_types
|
||||
)) AS "result.in_select",
|
||||
(length(121232459)) AS "result.raw",
|
||||
(? + COALESCE(all_types.small_int_ptr, 0) + ?) AS "result.raw_arg",
|
||||
(? + all_types.integer + ? + ? + ? + ?) AS "result.raw_arg2",
|
||||
(all_types.small_int_ptr NOT IN (?, ?, NULL)) AS "result.not_in",
|
||||
(all_types.small_int_ptr NOT IN (
|
||||
SELECT all_types.integer AS "all_types.integer"
|
||||
FROM all_types
|
||||
)) AS "result.not_in_select"
|
||||
FROM all_types
|
||||
LIMIT ?;
|
||||
`, "'", "`", -1), int64(11), int64(22), 78, 56, 11, 22, 11, 33, 44, int64(11), int64(22), int64(2))
|
||||
|
||||
var dest []struct {
|
||||
common.ExpressionTestResult `alias:"result.*"`
|
||||
}
|
||||
|
||||
err := query.Query(sampleDB, &dest)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, *dest[0].IsNull, false)
|
||||
require.Equal(t, *dest[0].IsNotNull, true)
|
||||
require.Equal(t, *dest[0].In, false)
|
||||
require.Equal(t, *dest[0].InSelect, false)
|
||||
require.Equal(t, *dest[0].Raw, "9")
|
||||
require.Equal(t, *dest[0].RawArg, int32(148))
|
||||
require.Equal(t, *dest[0].RawArg2, int32(-1479))
|
||||
require.Nil(t, dest[0].NotIn)
|
||||
require.Equal(t, *dest[0].NotInSelect, true)
|
||||
}
|
||||
|
||||
func TestBoolOperators(t *testing.T) {
|
||||
query := AllTypes.SELECT(
|
||||
AllTypes.Boolean.EQ(AllTypes.BooleanPtr).AS("EQ1"),
|
||||
AllTypes.Boolean.EQ(Bool(true)).AS("EQ2"),
|
||||
AllTypes.Boolean.NOT_EQ(AllTypes.BooleanPtr).AS("NEq1"),
|
||||
AllTypes.Boolean.NOT_EQ(Bool(false)).AS("NEq2"),
|
||||
AllTypes.Boolean.IS_DISTINCT_FROM(AllTypes.BooleanPtr).AS("distinct1"),
|
||||
AllTypes.Boolean.IS_DISTINCT_FROM(Bool(true)).AS("distinct2"),
|
||||
AllTypes.Boolean.IS_NOT_DISTINCT_FROM(AllTypes.BooleanPtr).AS("not_distinct_1"),
|
||||
AllTypes.Boolean.IS_NOT_DISTINCT_FROM(Bool(true)).AS("NOTDISTINCT2"),
|
||||
AllTypes.Boolean.IS_TRUE().AS("ISTRUE"),
|
||||
AllTypes.Boolean.IS_NOT_TRUE().AS("isnottrue"),
|
||||
AllTypes.Boolean.IS_FALSE().AS("is_False"),
|
||||
AllTypes.Boolean.IS_NOT_FALSE().AS("is not false"),
|
||||
AllTypes.Boolean.IS_NULL().AS("is unknown"),
|
||||
AllTypes.Boolean.IS_NOT_NULL().AS("is_not_unknown"),
|
||||
|
||||
AllTypes.Boolean.AND(AllTypes.Boolean).EQ(AllTypes.Boolean.AND(AllTypes.Boolean)).AS("complex1"),
|
||||
AllTypes.Boolean.OR(AllTypes.Boolean).EQ(AllTypes.Boolean.AND(AllTypes.Boolean)).AS("complex2"),
|
||||
)
|
||||
|
||||
testutils.AssertStatementSql(t, query, `
|
||||
SELECT (all_types.boolean = all_types.boolean_ptr) AS "EQ1",
|
||||
(all_types.boolean = ?) AS "EQ2",
|
||||
(all_types.boolean != all_types.boolean_ptr) AS "NEq1",
|
||||
(all_types.boolean != ?) AS "NEq2",
|
||||
(all_types.boolean IS NOT all_types.boolean_ptr) AS "distinct1",
|
||||
(all_types.boolean IS NOT ?) AS "distinct2",
|
||||
(all_types.boolean IS all_types.boolean_ptr) AS "not_distinct_1",
|
||||
(all_types.boolean IS ?) AS "NOTDISTINCT2",
|
||||
all_types.boolean IS TRUE AS "ISTRUE",
|
||||
all_types.boolean IS NOT TRUE AS "isnottrue",
|
||||
all_types.boolean IS FALSE AS "is_False",
|
||||
all_types.boolean IS NOT FALSE AS "is not false",
|
||||
all_types.boolean IS NULL AS "is unknown",
|
||||
all_types.boolean IS NOT NULL AS "is_not_unknown",
|
||||
((all_types.boolean AND all_types.boolean) = (all_types.boolean AND all_types.boolean)) AS "complex1",
|
||||
((all_types.boolean OR all_types.boolean) = (all_types.boolean AND all_types.boolean)) AS "complex2"
|
||||
FROM all_types;
|
||||
`, true, false, true, true)
|
||||
|
||||
var dest []struct {
|
||||
Eq1 *bool
|
||||
Eq2 *bool
|
||||
NEq1 *bool
|
||||
NEq2 *bool
|
||||
Distinct1 *bool
|
||||
Distinct2 *bool
|
||||
NotDistinct1 *bool
|
||||
NotDistinct2 *bool
|
||||
IsTrue *bool
|
||||
IsNotTrue *bool
|
||||
IsFalse *bool
|
||||
IsNotFalse *bool
|
||||
IsUnknown *bool
|
||||
IsNotUnknown *bool
|
||||
|
||||
Complex1 *bool
|
||||
Complex2 *bool
|
||||
}
|
||||
|
||||
err := query.Query(sampleDB, &dest)
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
testutils.AssertJSONFile(t, dest, "./testdata/results/common/bool_operators.json")
|
||||
}
|
||||
|
||||
func TestFloatOperators(t *testing.T) {
|
||||
|
||||
query := AllTypes.SELECT(
|
||||
AllTypes.Numeric.EQ(AllTypes.Numeric).AS("eq1"),
|
||||
AllTypes.Decimal.EQ(Float(12.22)).AS("eq2"),
|
||||
AllTypes.Real.EQ(Float(12.12)).AS("eq3"),
|
||||
AllTypes.Numeric.IS_DISTINCT_FROM(AllTypes.Numeric).AS("distinct1"),
|
||||
AllTypes.Decimal.IS_DISTINCT_FROM(Float(12)).AS("distinct2"),
|
||||
AllTypes.Real.IS_DISTINCT_FROM(Float(12.12)).AS("distinct3"),
|
||||
AllTypes.Numeric.IS_NOT_DISTINCT_FROM(AllTypes.Numeric).AS("not_distinct1"),
|
||||
AllTypes.Decimal.IS_NOT_DISTINCT_FROM(Float(12)).AS("not_distinct2"),
|
||||
AllTypes.Real.IS_NOT_DISTINCT_FROM(Float(12.12)).AS("not_distinct3"),
|
||||
AllTypes.Numeric.LT(Float(124)).AS("lt1"),
|
||||
AllTypes.Numeric.LT(Float(34.56)).AS("lt2"),
|
||||
AllTypes.Numeric.GT(Float(124)).AS("gt1"),
|
||||
AllTypes.Numeric.GT(Float(34.56)).AS("gt2"),
|
||||
|
||||
AllTypes.Decimal.ADD(AllTypes.Decimal).AS("add1"),
|
||||
AllTypes.Decimal.ADD(Float(11.22)).AS("add2"),
|
||||
AllTypes.Decimal.SUB(AllTypes.DecimalPtr).AS("sub1"),
|
||||
AllTypes.Decimal.SUB(Float(11.22)).AS("sub2"),
|
||||
AllTypes.Decimal.MUL(AllTypes.DecimalPtr).AS("mul1"),
|
||||
AllTypes.Decimal.MUL(Float(11.22)).AS("mul2"),
|
||||
AllTypes.Decimal.DIV(AllTypes.DecimalPtr).AS("div1"),
|
||||
AllTypes.Decimal.DIV(Float(11.22)).AS("div2"),
|
||||
AllTypes.Decimal.MOD(AllTypes.DecimalPtr).AS("mod1"),
|
||||
AllTypes.Decimal.MOD(Float(11.22)).AS("mod2"),
|
||||
|
||||
// sqlite driver has to enable SQLITE_ENABLE_MATH_FUNCTIONS before commented math functions can be used
|
||||
|
||||
//AllTypes.Decimal.POW(AllTypes.DecimalPtr).AS("pow1"),
|
||||
//AllTypes.Decimal.POW(Float(2.1)).AS("pow2"),
|
||||
|
||||
ABSf(AllTypes.Decimal).AS("abs"),
|
||||
//POWER(AllTypes.Decimal, Float(2.1)).AS("power"),
|
||||
//SQRT(AllTypes.Decimal).AS("sqrt"),
|
||||
//CBRT(AllTypes.Decimal).AS("cbrt"),
|
||||
|
||||
//CEIL(AllTypes.Real).AS("ceil"),
|
||||
//FLOOR(AllTypes.Real).AS("floor"),
|
||||
ROUND(AllTypes.Decimal).AS("round1"),
|
||||
ROUND(AllTypes.Decimal, Int(2)).AS("round2"),
|
||||
//TRUNC(AllTypes.Decimal, Int(1)).AS("trunc"),
|
||||
SIGN(AllTypes.Real).AS("sign"),
|
||||
).LIMIT(1)
|
||||
|
||||
testutils.AssertStatementSql(t, query, `
|
||||
SELECT (all_types.numeric = all_types.numeric) AS "eq1",
|
||||
(all_types.decimal = ?) AS "eq2",
|
||||
(all_types.real = ?) AS "eq3",
|
||||
(all_types.numeric IS NOT all_types.numeric) AS "distinct1",
|
||||
(all_types.decimal IS NOT ?) AS "distinct2",
|
||||
(all_types.real IS NOT ?) AS "distinct3",
|
||||
(all_types.numeric IS all_types.numeric) AS "not_distinct1",
|
||||
(all_types.decimal IS ?) AS "not_distinct2",
|
||||
(all_types.real IS ?) AS "not_distinct3",
|
||||
(all_types.numeric < ?) AS "lt1",
|
||||
(all_types.numeric < ?) AS "lt2",
|
||||
(all_types.numeric > ?) AS "gt1",
|
||||
(all_types.numeric > ?) AS "gt2",
|
||||
(all_types.decimal + all_types.decimal) AS "add1",
|
||||
(all_types.decimal + ?) AS "add2",
|
||||
(all_types.decimal - all_types.decimal_ptr) AS "sub1",
|
||||
(all_types.decimal - ?) AS "sub2",
|
||||
(all_types.decimal * all_types.decimal_ptr) AS "mul1",
|
||||
(all_types.decimal * ?) AS "mul2",
|
||||
(all_types.decimal / all_types.decimal_ptr) AS "div1",
|
||||
(all_types.decimal / ?) AS "div2",
|
||||
(all_types.decimal % all_types.decimal_ptr) AS "mod1",
|
||||
(all_types.decimal % ?) AS "mod2",
|
||||
ABS(all_types.decimal) AS "abs",
|
||||
ROUND(all_types.decimal) AS "round1",
|
||||
ROUND(all_types.decimal, ?) AS "round2",
|
||||
SIGN(all_types.real) AS "sign"
|
||||
FROM all_types
|
||||
LIMIT ?;
|
||||
`)
|
||||
|
||||
var dest struct {
|
||||
common.FloatExpressionTestResult `alias:"."`
|
||||
}
|
||||
|
||||
err := query.Query(sampleDB, &dest)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, *dest.Eq1, true)
|
||||
require.Equal(t, *dest.Distinct1, false)
|
||||
require.Equal(t, *dest.Lt1, true)
|
||||
require.Equal(t, *dest.Add1, 2.22)
|
||||
require.Equal(t, *dest.Mod2, float64(1))
|
||||
require.Equal(t, *dest.Round1, float64(1))
|
||||
require.Equal(t, *dest.Round2, float64(1.11))
|
||||
require.Equal(t, *dest.Sign, float64(1))
|
||||
|
||||
//testutils.AssertJSONFile(t, dest, "./testdata/results/common/float_operators.json")
|
||||
}
|
||||
|
||||
func TestIntegerOperators(t *testing.T) {
|
||||
query := AllTypes.SELECT(
|
||||
AllTypes.BigInt,
|
||||
AllTypes.BigIntPtr,
|
||||
AllTypes.SmallInt,
|
||||
AllTypes.SmallIntPtr,
|
||||
|
||||
AllTypes.BigInt.EQ(AllTypes.BigInt).AS("eq1"),
|
||||
AllTypes.BigInt.EQ(Int(12)).AS("eq2"),
|
||||
|
||||
AllTypes.BigInt.NOT_EQ(AllTypes.BigIntPtr).AS("neq1"),
|
||||
AllTypes.BigInt.NOT_EQ(Int(12)).AS("neq2"),
|
||||
|
||||
AllTypes.BigInt.IS_DISTINCT_FROM(AllTypes.BigInt).AS("distinct1"),
|
||||
AllTypes.BigInt.IS_DISTINCT_FROM(Int(12)).AS("distinct2"),
|
||||
|
||||
AllTypes.BigInt.IS_NOT_DISTINCT_FROM(AllTypes.BigInt).AS("not distinct1"),
|
||||
AllTypes.BigInt.IS_NOT_DISTINCT_FROM(Int(12)).AS("not distinct2"),
|
||||
|
||||
AllTypes.BigInt.LT(AllTypes.BigIntPtr).AS("lt1"),
|
||||
AllTypes.BigInt.LT(Int(65)).AS("lt2"),
|
||||
|
||||
AllTypes.BigInt.LT_EQ(AllTypes.BigIntPtr).AS("lte1"),
|
||||
AllTypes.BigInt.LT_EQ(Int(65)).AS("lte2"),
|
||||
|
||||
AllTypes.BigInt.GT(AllTypes.BigIntPtr).AS("gt1"),
|
||||
AllTypes.BigInt.GT(Int(65)).AS("gt2"),
|
||||
|
||||
AllTypes.BigInt.GT_EQ(AllTypes.BigIntPtr).AS("gte1"),
|
||||
AllTypes.BigInt.GT_EQ(Int(65)).AS("gte2"),
|
||||
|
||||
AllTypes.BigInt.ADD(AllTypes.BigInt).AS("add1"),
|
||||
AllTypes.BigInt.ADD(Int(11)).AS("add2"),
|
||||
|
||||
AllTypes.BigInt.SUB(AllTypes.BigInt).AS("sub1"),
|
||||
AllTypes.BigInt.SUB(Int(11)).AS("sub2"),
|
||||
|
||||
AllTypes.BigInt.MUL(AllTypes.BigInt).AS("mul1"),
|
||||
AllTypes.BigInt.MUL(Int(11)).AS("mul2"),
|
||||
|
||||
AllTypes.BigInt.DIV(AllTypes.BigInt).AS("div1"),
|
||||
AllTypes.BigInt.DIV(Int(11)).AS("div2"),
|
||||
|
||||
AllTypes.BigInt.MOD(AllTypes.BigInt).AS("mod1"),
|
||||
AllTypes.BigInt.MOD(Int(11)).AS("mod2"),
|
||||
|
||||
//AllTypes.SmallInt.POW(AllTypes.SmallInt.DIV(Int(3))).AS("pow1"),
|
||||
//AllTypes.SmallInt.POW(Int(6)).AS("pow2"),
|
||||
|
||||
AllTypes.SmallInt.BIT_AND(AllTypes.SmallInt).AS("bit_and1"),
|
||||
AllTypes.SmallInt.BIT_AND(AllTypes.SmallInt).AS("bit_and2"),
|
||||
|
||||
AllTypes.SmallInt.BIT_OR(AllTypes.SmallInt).AS("bit or 1"),
|
||||
AllTypes.SmallInt.BIT_OR(Int(22)).AS("bit or 2"),
|
||||
|
||||
AllTypes.SmallInt.BIT_XOR(AllTypes.SmallInt).AS("bit xor 1"),
|
||||
AllTypes.SmallInt.BIT_XOR(Int(11)).AS("bit xor 2"),
|
||||
|
||||
BIT_NOT(Int(-1).MUL(AllTypes.SmallInt)).AS("bit_not_1"),
|
||||
BIT_NOT(Int(-1).MUL(Int(11))).AS("bit_not_2"),
|
||||
|
||||
AllTypes.SmallInt.BIT_SHIFT_LEFT(AllTypes.SmallInt.DIV(Int(2))).AS("bit shift left 1"),
|
||||
AllTypes.SmallInt.BIT_SHIFT_LEFT(Int(4)).AS("bit shift left 2"),
|
||||
|
||||
AllTypes.SmallInt.BIT_SHIFT_RIGHT(AllTypes.SmallInt.DIV(Int(5))).AS("bit shift right 1"),
|
||||
AllTypes.SmallInt.BIT_SHIFT_RIGHT(Int(1)).AS("bit shift right 2"),
|
||||
|
||||
ABSi(AllTypes.BigInt).AS("abs"),
|
||||
//SQRT(ABSi(AllTypes.BigInt)).AS("sqrt"),
|
||||
//CBRT(ABSi(AllTypes.BigInt)).AS("cbrt"),
|
||||
).LIMIT(2)
|
||||
|
||||
var dest []struct {
|
||||
common.AllTypesIntegerExpResult `alias:"."`
|
||||
}
|
||||
|
||||
err := query.Query(sampleDB, &dest)
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, *dest[0].Eq1, true)
|
||||
require.Equal(t, *dest[0].Distinct2, true)
|
||||
require.Equal(t, *dest[0].Lt2, false)
|
||||
require.Equal(t, *dest[0].Add1, int64(10000))
|
||||
require.Equal(t, *dest[0].Mul1, int64(25000000))
|
||||
require.Equal(t, *dest[0].Div2, int64(454))
|
||||
require.Equal(t, *dest[0].BitAnd1, int64(14))
|
||||
require.Equal(t, *dest[0].BitXor2, int64(5))
|
||||
require.Equal(t, *dest[0].BitShiftLeft1, int64(1792))
|
||||
require.Equal(t, *dest[0].BitShiftRight2, int64(7))
|
||||
|
||||
}
|
||||
|
||||
func TestStringOperators(t *testing.T) {
|
||||
|
||||
query := SELECT(
|
||||
AllTypes.Text.EQ(AllTypes.Char),
|
||||
AllTypes.Text.EQ(String("Text")),
|
||||
AllTypes.Text.NOT_EQ(AllTypes.VarCharPtr),
|
||||
AllTypes.Text.NOT_EQ(String("Text")),
|
||||
AllTypes.Text.GT(AllTypes.Text),
|
||||
AllTypes.Text.GT(String("Text")),
|
||||
AllTypes.Text.GT_EQ(AllTypes.TextPtr),
|
||||
AllTypes.Text.GT_EQ(String("Text")),
|
||||
AllTypes.Text.LT(AllTypes.Char),
|
||||
AllTypes.Text.LT(String("Text")),
|
||||
AllTypes.Text.LT_EQ(AllTypes.VarCharPtr),
|
||||
AllTypes.Text.LT_EQ(String("Text")),
|
||||
AllTypes.Text.CONCAT(String("text2")),
|
||||
AllTypes.Text.CONCAT(Int(11)),
|
||||
AllTypes.Text.LIKE(String("abc")),
|
||||
AllTypes.Text.NOT_LIKE(String("_b_")),
|
||||
//AllTypes.Text.REGEXP_LIKE(String("aba")),
|
||||
//AllTypes.Text.REGEXP_LIKE(String("aba"), false),
|
||||
//String("ABA").REGEXP_LIKE(String("aba"), true),
|
||||
//AllTypes.Text.NOT_REGEXP_LIKE(String("aba")),
|
||||
//AllTypes.Text.NOT_REGEXP_LIKE(String("aba"), false),
|
||||
//String("ABA").NOT_REGEXP_LIKE(String("aba"), true),
|
||||
|
||||
//BIT_LENGTH(AllTypes.Text),
|
||||
//CHAR_LENGTH(AllTypes.Char),
|
||||
//OCTET_LENGTH(AllTypes.Text),
|
||||
LOWER(AllTypes.VarCharPtr),
|
||||
UPPER(AllTypes.Char),
|
||||
LTRIM(AllTypes.VarCharPtr),
|
||||
RTRIM(AllTypes.VarCharPtr),
|
||||
//CONCAT(String("string1"), Int(1), Float(11.12)),
|
||||
//CONCAT_WS(String("string1"), Int(1), Float(11.12)),
|
||||
//FORMAT(String("Hello %s, %1$s"), String("World")),
|
||||
//LEFTSTR(String("abcde"), Int(2)),
|
||||
//RIGHTSTR(String("abcde"), Int(2)),
|
||||
LENGTH(String("jose")),
|
||||
//LPAD(String("Hi"), Int(5), String("xy")),
|
||||
//RPAD(String("Hi"), Int(5), String("xy")),
|
||||
//MD5(AllTypes.VarCharPtr),
|
||||
//REPEAT(AllTypes.Text, Int(33)),
|
||||
REPLACE(AllTypes.Char, String("BA"), String("AB")),
|
||||
//REVERSE(AllTypes.VarCharPtr),
|
||||
SUBSTR(AllTypes.CharPtr, Int(3)),
|
||||
SUBSTR(AllTypes.CharPtr, Int(3), Int(2)),
|
||||
).FROM(AllTypes)
|
||||
|
||||
dest := []struct{}{}
|
||||
err := query.Query(sampleDB, &dest)
|
||||
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestReservedWord(t *testing.T) {
|
||||
stmt := SELECT(ReservedWords.AllColumns).
|
||||
FROM(ReservedWords)
|
||||
|
||||
testutils.AssertDebugStatementSql(t, stmt, strings.Replace(`
|
||||
SELECT ''ReservedWords''.''column'' AS "ReservedWords.column",
|
||||
''ReservedWords''.use AS "ReservedWords.use",
|
||||
''ReservedWords''.ceil AS "ReservedWords.ceil",
|
||||
''ReservedWords''.''commit'' AS "ReservedWords.commit",
|
||||
''ReservedWords''.''create'' AS "ReservedWords.create",
|
||||
''ReservedWords''.''default'' AS "ReservedWords.default",
|
||||
''ReservedWords''.''desc'' AS "ReservedWords.desc",
|
||||
''ReservedWords''.empty AS "ReservedWords.empty",
|
||||
''ReservedWords''.float AS "ReservedWords.float",
|
||||
''ReservedWords''.''join'' AS "ReservedWords.join",
|
||||
''ReservedWords''.''like'' AS "ReservedWords.like",
|
||||
''ReservedWords''.max AS "ReservedWords.max",
|
||||
''ReservedWords''.rank AS "ReservedWords.rank"
|
||||
FROM ''ReservedWords'';
|
||||
`, "''", "`", -1))
|
||||
|
||||
var dest model.ReservedWords
|
||||
err := stmt.Query(sampleDB, &dest)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, dest, model.ReservedWords{
|
||||
Column: "Column",
|
||||
Use: "CHECK",
|
||||
Ceil: "CEIL",
|
||||
Commit: "COMMIT",
|
||||
Create: "CREATE",
|
||||
Default: "DEFAULT",
|
||||
Desc: "DESC",
|
||||
Empty: "EMPTY",
|
||||
Float: "FLOAT",
|
||||
Join: "JOIN",
|
||||
Like: "LIKE",
|
||||
Max: "MAX",
|
||||
Rank: "RANK",
|
||||
})
|
||||
}
|
||||
|
||||
func TestExactDecimals(t *testing.T) {
|
||||
|
||||
type exactDecimals struct {
|
||||
model.ExactDecimals
|
||||
Decimal decimal.Decimal
|
||||
DecimalPtr decimal.Decimal
|
||||
}
|
||||
|
||||
t.Run("should query decimal", func(t *testing.T) {
|
||||
query := SELECT(
|
||||
ExactDecimals.AllColumns,
|
||||
).FROM(
|
||||
ExactDecimals,
|
||||
).WHERE(ExactDecimals.Decimal.EQ(String("1.11111111111111111111")))
|
||||
|
||||
var result exactDecimals
|
||||
|
||||
err := query.Query(sampleDB, &result)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, "1.11111111111111111111", result.Decimal.String())
|
||||
require.Equal(t, "0", result.DecimalPtr.String()) // NULL
|
||||
|
||||
require.Equal(t, "1.11111111111111111111", result.ExactDecimals.Decimal) // precision loss
|
||||
require.Equal(t, (*string)(nil), result.ExactDecimals.DecimalPtr)
|
||||
require.Equal(t, "2.22222222222222222222", result.ExactDecimals.Numeric)
|
||||
require.Equal(t, (*string)(nil), result.ExactDecimals.NumericPtr) // NULL
|
||||
})
|
||||
|
||||
t.Run("should insert decimal", func(t *testing.T) {
|
||||
|
||||
insertQuery := ExactDecimals.INSERT(
|
||||
ExactDecimals.AllColumns,
|
||||
).MODEL(
|
||||
exactDecimals{
|
||||
ExactDecimals: model.ExactDecimals{
|
||||
// overwritten by wrapped(exactDecimals) scope
|
||||
Decimal: "0.1",
|
||||
DecimalPtr: nil,
|
||||
|
||||
// not overwritten
|
||||
Numeric: "6.7",
|
||||
NumericPtr: testutils.StringPtr("7.7"),
|
||||
},
|
||||
Decimal: decimal.RequireFromString("91.23"),
|
||||
DecimalPtr: decimal.RequireFromString("45.67"),
|
||||
},
|
||||
).RETURNING(ExactDecimals.AllColumns)
|
||||
|
||||
testutils.AssertDebugStatementSql(t, insertQuery, strings.Replace(`
|
||||
INSERT INTO exact_decimals (decimal, decimal_ptr, numeric, numeric_ptr)
|
||||
VALUES ('91.23', '45.67', '6.7', '7.7')
|
||||
RETURNING exact_decimals.decimal AS "exact_decimals.decimal",
|
||||
exact_decimals.decimal_ptr AS "exact_decimals.decimal_ptr",
|
||||
exact_decimals.numeric AS "exact_decimals.numeric",
|
||||
exact_decimals.numeric_ptr AS "exact_decimals.numeric_ptr";
|
||||
`, "''", "`", -1))
|
||||
|
||||
tx := beginSampleDBTx(t)
|
||||
defer tx.Rollback()
|
||||
|
||||
var result exactDecimals
|
||||
|
||||
err := insertQuery.Query(tx, &result)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, "91.23", result.Decimal.String())
|
||||
require.Equal(t, "45.67", result.DecimalPtr.String())
|
||||
|
||||
require.Equal(t, "6.7", result.ExactDecimals.Numeric)
|
||||
require.Equal(t, "7.7", *result.ExactDecimals.NumericPtr)
|
||||
require.Equal(t, "91.23", result.ExactDecimals.Decimal)
|
||||
require.Equal(t, "45.67", *result.ExactDecimals.DecimalPtr)
|
||||
})
|
||||
}
|
||||
|
||||
var timeT = time.Date(2009, 11, 17, 20, 34, 58, 651387237, time.UTC)
|
||||
|
||||
func TestDateExpressions(t *testing.T) {
|
||||
|
||||
query := AllTypes.SELECT(
|
||||
//Date(2009, 11, 17, 2, MONTH, 1, DAY),
|
||||
|
||||
//DateT(timeT, START_OF_THE_MONTH),
|
||||
AllTypes.Date.AS("date"),
|
||||
DATE("2009-11-17").AS("date1"),
|
||||
DATE("2013-10-07 08:23:19.120", DAYS(1)).AS("date2"),
|
||||
DATE(AllTypes.Date, START_OF_YEAR, DAYS(2)).AS("date3"),
|
||||
DATE(timeT, START_OF_MONTH).AS("date3"),
|
||||
DATE("now", WEEKDAY(1)).AS("date4"),
|
||||
DATE(timeT.Unix(), UNIXEPOCH).AS("date5"),
|
||||
DATE(time.Now(), UTC).AS("date6"),
|
||||
DATE(time.Now().UTC(), LOCALTIME).AS("date7"),
|
||||
|
||||
AllTypes.Date.EQ(AllTypes.Date),
|
||||
AllTypes.Date.EQ(Date(2019, 6, 6)),
|
||||
|
||||
AllTypes.DatePtr.NOT_EQ(AllTypes.Date),
|
||||
AllTypes.DatePtr.NOT_EQ(Date(2019, 1, 6)),
|
||||
|
||||
AllTypes.Date.IS_DISTINCT_FROM(AllTypes.Date).AS("distinct1"),
|
||||
AllTypes.Date.IS_DISTINCT_FROM(Date(2008, 7, 4)).AS("distinct2"),
|
||||
|
||||
AllTypes.Date.IS_NOT_DISTINCT_FROM(AllTypes.Date),
|
||||
AllTypes.Date.IS_NOT_DISTINCT_FROM(Date(2019, 3, 6)),
|
||||
|
||||
AllTypes.Date.LT(AllTypes.Date),
|
||||
AllTypes.Date.LT(Date(2019, 4, 6)),
|
||||
|
||||
AllTypes.Date.LT_EQ(AllTypes.Date),
|
||||
AllTypes.Date.LT_EQ(Date(2019, 5, 5)),
|
||||
|
||||
AllTypes.Date.GT(AllTypes.Date),
|
||||
AllTypes.Date.GT(Date(2019, 1, 4)),
|
||||
|
||||
AllTypes.Date.GT_EQ(AllTypes.Date),
|
||||
AllTypes.Date.GT_EQ(Date(2019, 2, 3)),
|
||||
|
||||
//AllTypes.Date.ADD(INTERVAL2(2, HOUR)),
|
||||
//AllTypes.Date.ADD(INTERVAL2(1, DAY, 7, MONTH)),
|
||||
//AllTypes.Date.ADD(INTERVALd(25 * time.Hour + 100 * time.Millisecond)),
|
||||
//AllTypes.Date.ADD(INTERVALd(-25 * time.Hour - 100 * time.Millisecond)),
|
||||
//
|
||||
//AllTypes.Date.SUB(INTERVAL(20, MINUTE)),
|
||||
//AllTypes.Date.SUB(INTERVALe(AllTypes.SmallInt, MINUTE)),
|
||||
//AllTypes.Date.SUB(INTERVALd(3*time.Minute)),
|
||||
|
||||
CURRENT_DATE().AS("current_date"),
|
||||
)
|
||||
|
||||
var dest struct {
|
||||
Date string
|
||||
Date1 time.Time
|
||||
Date2 string
|
||||
Date3 time.Time
|
||||
Date4 string
|
||||
Date5 time.Time
|
||||
Date6 string
|
||||
Date7 time.Time
|
||||
Distinct1 bool
|
||||
Distinct2 bool
|
||||
CurrentDate time.Time
|
||||
}
|
||||
err := query.Query(sampleDB, &dest)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, dest.Date, "2008-07-04T00:00:00Z")
|
||||
require.Equal(t, dest.Date1.Unix(), int64(1258416000))
|
||||
}
|
||||
|
||||
func TestTimeExpressions(t *testing.T) {
|
||||
|
||||
query := AllTypes.SELECT(
|
||||
TIME(AllTypes.Time).AS("time1"),
|
||||
TIME(timeT).AS("time2"),
|
||||
TIME("04:23:19.120-04:00", HOURS(1), MINUTES(2), SECONDS(1.234)).AS("time3"),
|
||||
TIME(timeT.Unix(), UNIXEPOCH).AS("time4"),
|
||||
TIME(time.Now(), UTC).AS("time5"),
|
||||
TIME(time.Now().UTC(), LOCALTIME).AS("time6"),
|
||||
|
||||
Time(timeT.Clock()),
|
||||
|
||||
AllTypes.Time.EQ(AllTypes.Time),
|
||||
AllTypes.Time.EQ(Time(23, 6, 6)),
|
||||
AllTypes.Time.EQ(Time(22, 6, 6, 11*time.Millisecond)),
|
||||
AllTypes.Time.EQ(Time(21, 6, 6, 11111*time.Microsecond)),
|
||||
|
||||
AllTypes.TimePtr.NOT_EQ(AllTypes.Time),
|
||||
AllTypes.TimePtr.NOT_EQ(Time(20, 16, 6)),
|
||||
|
||||
AllTypes.Time.IS_DISTINCT_FROM(AllTypes.Time),
|
||||
AllTypes.Time.IS_DISTINCT_FROM(Time(19, 26, 6)),
|
||||
|
||||
AllTypes.Time.IS_NOT_DISTINCT_FROM(AllTypes.Time),
|
||||
AllTypes.Time.IS_NOT_DISTINCT_FROM(Time(18, 36, 6)),
|
||||
|
||||
AllTypes.Time.LT(AllTypes.Time),
|
||||
AllTypes.Time.LT(Time(17, 46, 6)),
|
||||
|
||||
AllTypes.Time.LT_EQ(AllTypes.Time),
|
||||
AllTypes.Time.LT_EQ(Time(16, 56, 56)),
|
||||
|
||||
AllTypes.Time.GT(AllTypes.Time),
|
||||
AllTypes.Time.GT(Time(15, 16, 46)),
|
||||
|
||||
AllTypes.Time.GT_EQ(AllTypes.Time),
|
||||
AllTypes.Time.GT_EQ(Time(14, 26, 36)),
|
||||
|
||||
//AllTypes.Time.ADD(INTERVAL(10, MINUTE)),
|
||||
//AllTypes.Time.ADD(INTERVALe(AllTypes.Integer, MINUTE)),
|
||||
//AllTypes.Time.ADD(INTERVALd(3*time.Hour)),
|
||||
//
|
||||
//AllTypes.Time.SUB(INTERVAL(20, MINUTE)),
|
||||
//AllTypes.Time.SUB(INTERVALe(AllTypes.SmallInt, MINUTE)),
|
||||
//AllTypes.Time.SUB(INTERVALd(3*time.Minute)),
|
||||
//
|
||||
//AllTypes.Time.ADD(INTERVAL(20, MINUTE)).SUB(INTERVAL(11, HOUR)),
|
||||
|
||||
CURRENT_TIME(),
|
||||
)
|
||||
|
||||
var dest struct {
|
||||
Time1 string
|
||||
Time2 time.Time
|
||||
Time3 string
|
||||
Time4 time.Time
|
||||
Time5 string
|
||||
Time6 time.Time
|
||||
}
|
||||
err := query.Query(sampleDB, &dest)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, dest.Time1, "10:11:12")
|
||||
require.Equal(t, dest.Time2.UTC().String(), "0000-01-01 20:34:58 +0000 UTC")
|
||||
require.Equal(t, dest.Time3, "09:25:20")
|
||||
}
|
||||
|
||||
func TestDateTimeExpressions(t *testing.T) {
|
||||
|
||||
var dateTime = DateTime(2019, 6, 6, 10, 2, 46)
|
||||
|
||||
query := SELECT(
|
||||
DATETIME("now").AS("now"),
|
||||
DATETIME("2013-10-07T08:23:19.120Z", YEARS(2), MONTHS(1), DAYS(1)).AS("datetime1"),
|
||||
DATETIME(AllTypes.DateTime, MONTHS(1), DAYS(1)).AS("datetime2"),
|
||||
DATETIME(timeT.Unix(), UNIXEPOCH).AS("datetime3"),
|
||||
DATETIME(time.Now(), UTC).AS("datetime4"),
|
||||
DATETIME(timeT.UTC(), LOCALTIME).AS("datetime5"),
|
||||
|
||||
JULIANDAY(timeT, DAYS(1)).AS("JulianDay"),
|
||||
STRFTIME(String("%H:%M"), timeT, SECONDS(1.22)).AS("strftime"),
|
||||
|
||||
AllTypes.DateTime.EQ(AllTypes.DateTime),
|
||||
AllTypes.DateTime.EQ(dateTime),
|
||||
|
||||
AllTypes.DateTimePtr.NOT_EQ(AllTypes.DateTime),
|
||||
AllTypes.DateTimePtr.NOT_EQ(DateTime(2019, 6, 6, 10, 2, 46, 100*time.Millisecond)),
|
||||
|
||||
AllTypes.DateTime.IS_DISTINCT_FROM(AllTypes.DateTime),
|
||||
AllTypes.DateTime.IS_DISTINCT_FROM(dateTime),
|
||||
|
||||
AllTypes.DateTime.IS_NOT_DISTINCT_FROM(AllTypes.DateTime),
|
||||
AllTypes.DateTime.IS_NOT_DISTINCT_FROM(dateTime),
|
||||
|
||||
AllTypes.DateTime.LT(AllTypes.DateTime),
|
||||
AllTypes.DateTime.LT(dateTime),
|
||||
|
||||
AllTypes.DateTime.LT_EQ(AllTypes.DateTime),
|
||||
AllTypes.DateTime.LT_EQ(dateTime),
|
||||
|
||||
AllTypes.DateTime.GT(AllTypes.DateTime),
|
||||
AllTypes.DateTime.GT(dateTime),
|
||||
|
||||
AllTypes.DateTime.GT_EQ(AllTypes.DateTime),
|
||||
AllTypes.DateTime.GT_EQ(dateTime),
|
||||
|
||||
//AllTypes.DateTime.ADD(INTERVAL("05:10:20.000100", HOUR_MICROSECOND)),
|
||||
//AllTypes.DateTime.ADD(INTERVALe(AllTypes.BigInt, HOUR)),
|
||||
//AllTypes.DateTime.ADD(INTERVALd(2*time.Hour)),
|
||||
//
|
||||
//AllTypes.DateTime.SUB(INTERVAL("05:10:20.000100", HOUR_MICROSECOND)),
|
||||
//AllTypes.DateTime.SUB(INTERVALe(AllTypes.IntegerPtr, HOUR)),
|
||||
//AllTypes.DateTime.SUB(INTERVALd(3*time.Hour)),
|
||||
|
||||
CURRENT_TIMESTAMP(),
|
||||
).FROM(AllTypes)
|
||||
|
||||
var dest struct {
|
||||
Now time.Time
|
||||
DateTime1 time.Time
|
||||
DateTime2 time.Time
|
||||
DateTime3 time.Time
|
||||
DateTime4 time.Time
|
||||
DateTime5 time.Time
|
||||
JulianDay float64
|
||||
StrfTime string
|
||||
}
|
||||
|
||||
err := query.Query(sampleDB, &dest)
|
||||
require.NoError(t, err)
|
||||
require.True(t, dest.Now.After(time.Now().Add(-1*time.Minute)))
|
||||
require.Equal(t, dest.DateTime1.String(), "2015-11-08 08:23:19 +0000 UTC")
|
||||
require.Equal(t, dest.DateTime2.String(), "2012-01-19 13:17:17 +0000 UTC")
|
||||
require.Equal(t, dest.DateTime3.String(), "2009-11-17 20:34:58 +0000 UTC")
|
||||
require.True(t, dest.DateTime4.After(time.Now().Add(-1*time.Minute)))
|
||||
require.Equal(t, dest.DateTime5.String(), "2009-11-17 21:34:58 +0000 UTC")
|
||||
require.Equal(t, dest.JulianDay, 2.4551543576232754e+06)
|
||||
require.Equal(t, dest.StrfTime, "20:34")
|
||||
}
|
||||
41
tests/sqlite/cast_test.go
Normal file
41
tests/sqlite/cast_test.go
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
package sqlite
|
||||
|
||||
import (
|
||||
"github.com/go-jet/jet/v2/internal/testutils"
|
||||
. "github.com/go-jet/jet/v2/sqlite"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCast(t *testing.T) {
|
||||
query := SELECT(
|
||||
CAST(String("test")).AS("CHARACTER").AS("result.AS1"),
|
||||
CAST(Float(11.33)).AS_TEXT().AS("result.text"),
|
||||
CAST(String("33.44")).AS_REAL().AS("result.real"),
|
||||
CAST(String("33")).AS_INTEGER().AS("result.integer"),
|
||||
CAST(String("Blob blob")).AS_BLOB().AS("result.blob"),
|
||||
)
|
||||
|
||||
type Result struct {
|
||||
As1 string
|
||||
Text string
|
||||
Real float64
|
||||
Integer int64
|
||||
Blob []byte
|
||||
}
|
||||
|
||||
var dest Result
|
||||
|
||||
err := query.Query(db, &dest)
|
||||
require.NoError(t, err)
|
||||
|
||||
testutils.AssertDeepEqual(t, dest, Result{
|
||||
As1: "test",
|
||||
Text: "11.33",
|
||||
Real: 33.44,
|
||||
Integer: 33,
|
||||
Blob: []byte("Blob blob"),
|
||||
})
|
||||
|
||||
requireLogged(t, query)
|
||||
}
|
||||
83
tests/sqlite/delete_test.go
Normal file
83
tests/sqlite/delete_test.go
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
package sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-jet/jet/v2/internal/testutils"
|
||||
. "github.com/go-jet/jet/v2/sqlite"
|
||||
"github.com/go-jet/jet/v2/tests/.gentestdata/sqlite/test_sample/model"
|
||||
. "github.com/go-jet/jet/v2/tests/.gentestdata/sqlite/test_sample/table"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestDelete_WHERE_RETURNING(t *testing.T) {
|
||||
tx := beginSampleDBTx(t)
|
||||
defer tx.Rollback()
|
||||
|
||||
var expectedSQL = `
|
||||
DELETE FROM link
|
||||
WHERE link.name IN ('Bing', 'Yahoo')
|
||||
RETURNING link.id AS "link.id",
|
||||
link.url AS "link.url",
|
||||
link.name AS "link.name",
|
||||
link.description AS "link.description";
|
||||
`
|
||||
deleteStmt := Link.DELETE().
|
||||
WHERE(Link.Name.IN(String("Bing"), String("Yahoo"))).
|
||||
RETURNING(Link.AllColumns)
|
||||
|
||||
testutils.AssertDebugStatementSql(t, deleteStmt, expectedSQL, "Bing", "Yahoo")
|
||||
var dest []model.Link
|
||||
err := deleteStmt.Query(tx, &dest)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, dest, 2)
|
||||
requireLogged(t, deleteStmt)
|
||||
}
|
||||
|
||||
func TestDeleteWithWhereOrderByLimit(t *testing.T) {
|
||||
t.SkipNow() // Until https://github.com/mattn/go-sqlite3/pull/802 is fixed
|
||||
tx := beginSampleDBTx(t)
|
||||
defer tx.Rollback()
|
||||
|
||||
sampleDB.Stats()
|
||||
|
||||
var expectedSQL = `
|
||||
DELETE FROM link
|
||||
WHERE link.name IN ('Bing', 'Yahoo')
|
||||
ORDER BY link.name
|
||||
LIMIT 1;
|
||||
`
|
||||
deleteStmt := Link.DELETE().
|
||||
WHERE(Link.Name.IN(String("Bing"), String("Yahoo"))).
|
||||
ORDER_BY(Link.Name).
|
||||
LIMIT(1)
|
||||
|
||||
testutils.AssertDebugStatementSql(t, deleteStmt, expectedSQL, "Bing", "Yahoo", int64(1))
|
||||
testutils.AssertExec(t, deleteStmt, tx, 1)
|
||||
requireLogged(t, deleteStmt)
|
||||
}
|
||||
|
||||
func TestDeleteContextDeadlineExceeded(t *testing.T) {
|
||||
tx := beginSampleDBTx(t)
|
||||
defer tx.Rollback()
|
||||
|
||||
deleteStmt := Link.
|
||||
DELETE().
|
||||
WHERE(Link.Name.IN(String("Bing"), String("Yahoo")))
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Microsecond)
|
||||
defer cancel()
|
||||
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
dest := []model.Link{}
|
||||
err := deleteStmt.QueryContext(ctx, tx, &dest)
|
||||
require.Error(t, err, "context deadline exceeded")
|
||||
|
||||
_, err = deleteStmt.ExecContext(ctx, tx)
|
||||
require.Error(t, err, "context deadline exceeded")
|
||||
|
||||
requireLogged(t, deleteStmt)
|
||||
}
|
||||
298
tests/sqlite/generator_test.go
Normal file
298
tests/sqlite/generator_test.go
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
package sqlite
|
||||
|
||||
import (
|
||||
"github.com/go-jet/jet/v2/generator/sqlite"
|
||||
"github.com/go-jet/jet/v2/internal/testutils"
|
||||
"github.com/go-jet/jet/v2/tests/.gentestdata/sqlite/sakila/model"
|
||||
"github.com/go-jet/jet/v2/tests/internal/utils/repo"
|
||||
"github.com/stretchr/testify/require"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGeneratedModel(t *testing.T) {
|
||||
actor := model.Actor{}
|
||||
|
||||
require.Equal(t, reflect.TypeOf(actor.ActorID).String(), "int32")
|
||||
actorIDField, ok := reflect.TypeOf(actor).FieldByName("ActorID")
|
||||
require.True(t, ok)
|
||||
require.Equal(t, actorIDField.Tag.Get("sql"), "primary_key")
|
||||
require.Equal(t, reflect.TypeOf(actor.FirstName).String(), "string")
|
||||
require.Equal(t, reflect.TypeOf(actor.LastName).String(), "string")
|
||||
require.Equal(t, reflect.TypeOf(actor.LastUpdate).String(), "time.Time")
|
||||
|
||||
filmActor := model.FilmActor{}
|
||||
|
||||
require.Equal(t, reflect.TypeOf(filmActor.FilmID).String(), "int32")
|
||||
filmIDField, ok := reflect.TypeOf(filmActor).FieldByName("FilmID")
|
||||
require.True(t, ok)
|
||||
require.Equal(t, filmIDField.Tag.Get("sql"), "primary_key")
|
||||
|
||||
require.Equal(t, reflect.TypeOf(filmActor.ActorID).String(), "int32")
|
||||
actorIDField, ok = reflect.TypeOf(filmActor).FieldByName("ActorID")
|
||||
require.True(t, ok)
|
||||
require.Equal(t, filmIDField.Tag.Get("sql"), "primary_key")
|
||||
|
||||
staff := model.Staff{}
|
||||
|
||||
require.Equal(t, reflect.TypeOf(staff.Email).String(), "*string")
|
||||
require.Equal(t, reflect.TypeOf(staff.Picture).String(), "*[]uint8")
|
||||
}
|
||||
|
||||
var testDatabaseFilePath = repo.GetTestDataFilePath("/init/sqlite/sakila.db")
|
||||
var genDestDir = repo.GetTestsFilePath("/sqlite/.gen")
|
||||
|
||||
func TestGenerator(t *testing.T) {
|
||||
for i := 0; i < 3; i++ {
|
||||
err := sqlite.GenerateDSN(testDatabaseFilePath, genDestDir)
|
||||
require.NoError(t, err)
|
||||
|
||||
assertGeneratedFiles(t)
|
||||
}
|
||||
|
||||
err := os.RemoveAll(genDestDir)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestCmdGenerator(t *testing.T) {
|
||||
cmd := exec.Command("jet", "-source=SQLite", "-dsn=file://"+testDatabaseFilePath, "-path="+genDestDir)
|
||||
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stdout = os.Stdout
|
||||
|
||||
err := cmd.Run()
|
||||
require.NoError(t, err)
|
||||
|
||||
assertGeneratedFiles(t)
|
||||
|
||||
err = os.RemoveAll(genDestDir)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func assertGeneratedFiles(t *testing.T) {
|
||||
// Table SQL Builder files
|
||||
tableSQLBuilderFiles, err := ioutil.ReadDir(genDestDir + "/table")
|
||||
require.NoError(t, err)
|
||||
|
||||
testutils.AssertFileNamesEqual(t, tableSQLBuilderFiles, "actor.go", "address.go", "category.go", "city.go", "country.go",
|
||||
"customer.go", "film.go", "film_actor.go", "film_category.go", "film_text.go", "inventory.go", "language.go",
|
||||
"payment.go", "rental.go", "staff.go", "store.go")
|
||||
|
||||
testutils.AssertFileContent(t, genDestDir+"/table/actor.go", actorSQLBuilderFile)
|
||||
|
||||
// View SQL Builder files
|
||||
viewSQLBuilderFiles, err := ioutil.ReadDir(genDestDir + "/view")
|
||||
require.NoError(t, err)
|
||||
|
||||
testutils.AssertFileNamesEqual(t, viewSQLBuilderFiles, "film_list.go", "sales_by_film_category.go",
|
||||
"customer_list.go", "sales_by_store.go", "staff_list.go")
|
||||
|
||||
testutils.AssertFileContent(t, genDestDir+"/view/film_list.go", filmListSQLBuilderFile)
|
||||
|
||||
// Model files
|
||||
modelFiles, err := ioutil.ReadDir(genDestDir + "/model")
|
||||
require.NoError(t, err)
|
||||
|
||||
testutils.AssertFileNamesEqual(t, modelFiles, "actor.go", "address.go", "category.go", "city.go", "country.go",
|
||||
"customer.go", "film.go", "film_actor.go", "film_category.go", "film_text.go", "inventory.go", "language.go",
|
||||
"payment.go", "rental.go", "staff.go", "store.go",
|
||||
"film_list.go", "sales_by_film_category.go",
|
||||
"customer_list.go", "sales_by_store.go", "staff_list.go")
|
||||
|
||||
testutils.AssertFileContent(t, genDestDir+"/model/address.go", addressModelFile)
|
||||
}
|
||||
|
||||
const actorSQLBuilderFile = `
|
||||
//
|
||||
// Code generated by go-jet DO NOT EDIT.
|
||||
//
|
||||
// WARNING: Changes to this file may cause incorrect behavior
|
||||
// and will be lost if the code is regenerated
|
||||
//
|
||||
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/go-jet/jet/v2/sqlite"
|
||||
)
|
||||
|
||||
var Actor = newActorTable("", "actor", "")
|
||||
|
||||
type actorTable struct {
|
||||
sqlite.Table
|
||||
|
||||
//Columns
|
||||
ActorID sqlite.ColumnInteger
|
||||
FirstName sqlite.ColumnString
|
||||
LastName sqlite.ColumnString
|
||||
LastUpdate sqlite.ColumnTimestamp
|
||||
|
||||
AllColumns sqlite.ColumnList
|
||||
MutableColumns sqlite.ColumnList
|
||||
}
|
||||
|
||||
type ActorTable struct {
|
||||
actorTable
|
||||
|
||||
EXCLUDED actorTable
|
||||
}
|
||||
|
||||
// AS creates new ActorTable with assigned alias
|
||||
func (a ActorTable) AS(alias string) *ActorTable {
|
||||
return newActorTable(a.SchemaName(), a.TableName(), alias)
|
||||
}
|
||||
|
||||
// Schema creates new ActorTable with assigned schema name
|
||||
func (a ActorTable) FromSchema(schemaName string) *ActorTable {
|
||||
return newActorTable(schemaName, a.TableName(), a.Alias())
|
||||
}
|
||||
|
||||
func newActorTable(schemaName, tableName, alias string) *ActorTable {
|
||||
return &ActorTable{
|
||||
actorTable: newActorTableImpl(schemaName, tableName, alias),
|
||||
EXCLUDED: newActorTableImpl("", "excluded", ""),
|
||||
}
|
||||
}
|
||||
|
||||
func newActorTableImpl(schemaName, tableName, alias string) actorTable {
|
||||
var (
|
||||
ActorIDColumn = sqlite.IntegerColumn("actor_id")
|
||||
FirstNameColumn = sqlite.StringColumn("first_name")
|
||||
LastNameColumn = sqlite.StringColumn("last_name")
|
||||
LastUpdateColumn = sqlite.TimestampColumn("last_update")
|
||||
allColumns = sqlite.ColumnList{ActorIDColumn, FirstNameColumn, LastNameColumn, LastUpdateColumn}
|
||||
mutableColumns = sqlite.ColumnList{FirstNameColumn, LastNameColumn, LastUpdateColumn}
|
||||
)
|
||||
|
||||
return actorTable{
|
||||
Table: sqlite.NewTable(schemaName, tableName, alias, allColumns...),
|
||||
|
||||
//Columns
|
||||
ActorID: ActorIDColumn,
|
||||
FirstName: FirstNameColumn,
|
||||
LastName: LastNameColumn,
|
||||
LastUpdate: LastUpdateColumn,
|
||||
|
||||
AllColumns: allColumns,
|
||||
MutableColumns: mutableColumns,
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const filmListSQLBuilderFile = `
|
||||
//
|
||||
// Code generated by go-jet DO NOT EDIT.
|
||||
//
|
||||
// WARNING: Changes to this file may cause incorrect behavior
|
||||
// and will be lost if the code is regenerated
|
||||
//
|
||||
|
||||
package view
|
||||
|
||||
import (
|
||||
"github.com/go-jet/jet/v2/sqlite"
|
||||
)
|
||||
|
||||
var FilmList = newFilmListTable("", "film_list", "")
|
||||
|
||||
type filmListTable struct {
|
||||
sqlite.Table
|
||||
|
||||
//Columns
|
||||
Fid sqlite.ColumnInteger
|
||||
Title sqlite.ColumnString
|
||||
Description sqlite.ColumnString
|
||||
Category sqlite.ColumnString
|
||||
Price sqlite.ColumnFloat
|
||||
Length sqlite.ColumnInteger
|
||||
Rating sqlite.ColumnString
|
||||
Actors sqlite.ColumnString
|
||||
|
||||
AllColumns sqlite.ColumnList
|
||||
MutableColumns sqlite.ColumnList
|
||||
}
|
||||
|
||||
type FilmListTable struct {
|
||||
filmListTable
|
||||
|
||||
EXCLUDED filmListTable
|
||||
}
|
||||
|
||||
// AS creates new FilmListTable with assigned alias
|
||||
func (a FilmListTable) AS(alias string) *FilmListTable {
|
||||
return newFilmListTable(a.SchemaName(), a.TableName(), alias)
|
||||
}
|
||||
|
||||
// Schema creates new FilmListTable with assigned schema name
|
||||
func (a FilmListTable) FromSchema(schemaName string) *FilmListTable {
|
||||
return newFilmListTable(schemaName, a.TableName(), a.Alias())
|
||||
}
|
||||
|
||||
func newFilmListTable(schemaName, tableName, alias string) *FilmListTable {
|
||||
return &FilmListTable{
|
||||
filmListTable: newFilmListTableImpl(schemaName, tableName, alias),
|
||||
EXCLUDED: newFilmListTableImpl("", "excluded", ""),
|
||||
}
|
||||
}
|
||||
|
||||
func newFilmListTableImpl(schemaName, tableName, alias string) filmListTable {
|
||||
var (
|
||||
FidColumn = sqlite.IntegerColumn("FID")
|
||||
TitleColumn = sqlite.StringColumn("title")
|
||||
DescriptionColumn = sqlite.StringColumn("description")
|
||||
CategoryColumn = sqlite.StringColumn("category")
|
||||
PriceColumn = sqlite.FloatColumn("price")
|
||||
LengthColumn = sqlite.IntegerColumn("length")
|
||||
RatingColumn = sqlite.StringColumn("rating")
|
||||
ActorsColumn = sqlite.StringColumn("actors")
|
||||
allColumns = sqlite.ColumnList{FidColumn, TitleColumn, DescriptionColumn, CategoryColumn, PriceColumn, LengthColumn, RatingColumn, ActorsColumn}
|
||||
mutableColumns = sqlite.ColumnList{FidColumn, TitleColumn, DescriptionColumn, CategoryColumn, PriceColumn, LengthColumn, RatingColumn, ActorsColumn}
|
||||
)
|
||||
|
||||
return filmListTable{
|
||||
Table: sqlite.NewTable(schemaName, tableName, alias, allColumns...),
|
||||
|
||||
//Columns
|
||||
Fid: FidColumn,
|
||||
Title: TitleColumn,
|
||||
Description: DescriptionColumn,
|
||||
Category: CategoryColumn,
|
||||
Price: PriceColumn,
|
||||
Length: LengthColumn,
|
||||
Rating: RatingColumn,
|
||||
Actors: ActorsColumn,
|
||||
|
||||
AllColumns: allColumns,
|
||||
MutableColumns: mutableColumns,
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const addressModelFile = `
|
||||
//
|
||||
// Code generated by go-jet DO NOT EDIT.
|
||||
//
|
||||
// WARNING: Changes to this file may cause incorrect behavior
|
||||
// and will be lost if the code is regenerated
|
||||
//
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Address struct {
|
||||
AddressID int32 ` + "`sql:\"primary_key\"`" + `
|
||||
Address string
|
||||
Address2 *string
|
||||
District string
|
||||
CityID int32
|
||||
PostalCode *string
|
||||
Phone string
|
||||
LastUpdate time.Time
|
||||
}
|
||||
`
|
||||
393
tests/sqlite/insert_test.go
Normal file
393
tests/sqlite/insert_test.go
Normal file
|
|
@ -0,0 +1,393 @@
|
|||
package sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/rand"
|
||||
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-jet/jet/v2/internal/testutils"
|
||||
. "github.com/go-jet/jet/v2/sqlite"
|
||||
"github.com/go-jet/jet/v2/tests/.gentestdata/sqlite/test_sample/model"
|
||||
. "github.com/go-jet/jet/v2/tests/.gentestdata/sqlite/test_sample/table"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestInsertValues(t *testing.T) {
|
||||
tx := beginSampleDBTx(t)
|
||||
defer tx.Rollback()
|
||||
|
||||
insertQuery := Link.INSERT(Link.ID, Link.URL, Link.Name, Link.Description).
|
||||
VALUES(100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial", nil).
|
||||
VALUES(101, "http://www.google.com", "Google", "Search engine").
|
||||
VALUES(102, "http://www.yahoo.com", "Yahoo", nil)
|
||||
|
||||
testutils.AssertStatementSql(t, insertQuery, `
|
||||
INSERT INTO link (id, url, name, description)
|
||||
VALUES (?, ?, ?, ?),
|
||||
(?, ?, ?, ?),
|
||||
(?, ?, ?, ?);
|
||||
`, 100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial", nil,
|
||||
101, "http://www.google.com", "Google", "Search engine",
|
||||
102, "http://www.yahoo.com", "Yahoo", nil)
|
||||
|
||||
_, err := insertQuery.Exec(tx)
|
||||
require.NoError(t, err)
|
||||
requireLogged(t, insertQuery)
|
||||
|
||||
insertedLinks := []model.Link{}
|
||||
|
||||
err = SELECT(Link.AllColumns).
|
||||
FROM(Link).
|
||||
WHERE(Link.ID.GT_EQ(Int(100))).
|
||||
ORDER_BY(Link.ID).
|
||||
Query(tx, &insertedLinks)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(insertedLinks), 3)
|
||||
testutils.AssertDeepEqual(t, insertedLinks[0], postgreTutorial)
|
||||
testutils.AssertDeepEqual(t, insertedLinks[1], model.Link{
|
||||
ID: 101,
|
||||
URL: "http://www.google.com",
|
||||
Name: "Google",
|
||||
Description: testutils.StringPtr("Search engine"),
|
||||
})
|
||||
testutils.AssertDeepEqual(t, insertedLinks[2], model.Link{
|
||||
ID: 102,
|
||||
URL: "http://www.yahoo.com",
|
||||
Name: "Yahoo",
|
||||
})
|
||||
}
|
||||
|
||||
var postgreTutorial = model.Link{
|
||||
ID: 100,
|
||||
URL: "http://www.postgresqltutorial.com",
|
||||
Name: "PostgreSQL Tutorial",
|
||||
}
|
||||
|
||||
func TestInsertEmptyColumnList(t *testing.T) {
|
||||
tx := beginSampleDBTx(t)
|
||||
defer tx.Rollback()
|
||||
|
||||
expectedSQL := `
|
||||
INSERT INTO link
|
||||
VALUES (100, 'http://www.postgresqltutorial.com', 'PostgreSQL Tutorial', NULL);
|
||||
`
|
||||
|
||||
stmt := Link.INSERT().
|
||||
VALUES(100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial", nil)
|
||||
|
||||
testutils.AssertDebugStatementSql(t, stmt, expectedSQL,
|
||||
100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial", nil)
|
||||
|
||||
_, err := stmt.Exec(tx)
|
||||
require.NoError(t, err)
|
||||
requireLogged(t, stmt)
|
||||
|
||||
insertedLinks := []model.Link{}
|
||||
|
||||
err = SELECT(Link.AllColumns).
|
||||
FROM(Link).
|
||||
WHERE(Link.ID.GT_EQ(Int(100))).
|
||||
ORDER_BY(Link.ID).
|
||||
Query(tx, &insertedLinks)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(insertedLinks), 1)
|
||||
testutils.AssertDeepEqual(t, insertedLinks[0], postgreTutorial)
|
||||
}
|
||||
|
||||
func TestInsertModelObject(t *testing.T) {
|
||||
tx := beginSampleDBTx(t)
|
||||
defer tx.Rollback()
|
||||
|
||||
linkData := model.Link{
|
||||
URL: "http://www.duckduckgo.com",
|
||||
Name: "Duck Duck go",
|
||||
}
|
||||
|
||||
query := Link.INSERT(Link.URL, Link.Name).
|
||||
MODEL(linkData)
|
||||
|
||||
testutils.AssertDebugStatementSql(t, query, `
|
||||
INSERT INTO link (url, name)
|
||||
VALUES ('http://www.duckduckgo.com', 'Duck Duck go');
|
||||
`, "http://www.duckduckgo.com", "Duck Duck go")
|
||||
|
||||
_, err := query.Exec(tx)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestInsertModelObjectEmptyColumnList(t *testing.T) {
|
||||
tx := beginSampleDBTx(t)
|
||||
defer tx.Rollback()
|
||||
|
||||
var expectedSQL = `
|
||||
INSERT INTO link
|
||||
VALUES (1000, 'http://www.duckduckgo.com', 'Duck Duck go', NULL);
|
||||
`
|
||||
|
||||
linkData := model.Link{
|
||||
ID: 1000,
|
||||
URL: "http://www.duckduckgo.com",
|
||||
Name: "Duck Duck go",
|
||||
}
|
||||
|
||||
query := Link.
|
||||
INSERT().
|
||||
MODEL(linkData)
|
||||
|
||||
testutils.AssertDebugStatementSql(t, query, expectedSQL, int32(1000), "http://www.duckduckgo.com", "Duck Duck go", nil)
|
||||
|
||||
_, err := query.Exec(tx)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestInsertModelsObject(t *testing.T) {
|
||||
tx := beginSampleDBTx(t)
|
||||
defer tx.Rollback()
|
||||
|
||||
expectedSQL := `
|
||||
INSERT INTO link (url, name)
|
||||
VALUES ('http://www.postgresqltutorial.com', 'PostgreSQL Tutorial'),
|
||||
('http://www.google.com', 'Google'),
|
||||
('http://www.yahoo.com', 'Yahoo');
|
||||
`
|
||||
|
||||
tutorial := model.Link{
|
||||
URL: "http://www.postgresqltutorial.com",
|
||||
Name: "PostgreSQL Tutorial",
|
||||
}
|
||||
google := model.Link{
|
||||
URL: "http://www.google.com",
|
||||
Name: "Google",
|
||||
}
|
||||
yahoo := model.Link{
|
||||
URL: "http://www.yahoo.com",
|
||||
Name: "Yahoo",
|
||||
}
|
||||
|
||||
query := Link.
|
||||
INSERT(Link.URL, Link.Name).
|
||||
MODELS([]model.Link{
|
||||
tutorial,
|
||||
google,
|
||||
yahoo,
|
||||
})
|
||||
|
||||
testutils.AssertDebugStatementSql(t, query, expectedSQL,
|
||||
"http://www.postgresqltutorial.com", "PostgreSQL Tutorial",
|
||||
"http://www.google.com", "Google",
|
||||
"http://www.yahoo.com", "Yahoo")
|
||||
|
||||
_, err := query.Exec(tx)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestInsertUsingMutableColumns(t *testing.T) {
|
||||
tx := beginSampleDBTx(t)
|
||||
defer tx.Rollback()
|
||||
|
||||
var expectedSQL = `
|
||||
INSERT INTO link (url, name, description)
|
||||
VALUES ('http://www.postgresqltutorial.com', 'PostgreSQL Tutorial', NULL),
|
||||
('http://www.google.com', 'Google', NULL),
|
||||
('http://www.google.com', 'Google', NULL),
|
||||
('http://www.yahoo.com', 'Yahoo', NULL);
|
||||
`
|
||||
|
||||
google := model.Link{
|
||||
URL: "http://www.google.com",
|
||||
Name: "Google",
|
||||
}
|
||||
|
||||
yahoo := model.Link{
|
||||
URL: "http://www.yahoo.com",
|
||||
Name: "Yahoo",
|
||||
}
|
||||
|
||||
stmt := Link.
|
||||
INSERT(Link.MutableColumns).
|
||||
VALUES("http://www.postgresqltutorial.com", "PostgreSQL Tutorial", nil).
|
||||
MODEL(google).
|
||||
MODELS([]model.Link{google, yahoo})
|
||||
|
||||
testutils.AssertDebugStatementSql(t, stmt, expectedSQL,
|
||||
"http://www.postgresqltutorial.com", "PostgreSQL Tutorial", nil,
|
||||
"http://www.google.com", "Google", nil,
|
||||
"http://www.google.com", "Google", nil,
|
||||
"http://www.yahoo.com", "Yahoo", nil)
|
||||
|
||||
_, err := stmt.Exec(tx)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestInsertQuery(t *testing.T) {
|
||||
tx := beginSampleDBTx(t)
|
||||
defer tx.Rollback()
|
||||
|
||||
var expectedSQL = `
|
||||
INSERT INTO link (url, name)
|
||||
SELECT link.url AS "link.url",
|
||||
link.name AS "link.name"
|
||||
FROM link
|
||||
WHERE link.id = 24;
|
||||
`
|
||||
query := Link.INSERT(Link.URL, Link.Name).
|
||||
QUERY(
|
||||
SELECT(Link.URL, Link.Name).
|
||||
FROM(Link).
|
||||
WHERE(Link.ID.EQ(Int(24))),
|
||||
)
|
||||
|
||||
testutils.AssertDebugStatementSql(t, query, expectedSQL, int64(24))
|
||||
|
||||
_, err := query.Exec(tx)
|
||||
require.NoError(t, err)
|
||||
|
||||
youtubeLinks := []model.Link{}
|
||||
err = Link.
|
||||
SELECT(Link.AllColumns).
|
||||
WHERE(Link.Name.EQ(String("Bing"))).
|
||||
Query(tx, &youtubeLinks)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(youtubeLinks), 2)
|
||||
}
|
||||
|
||||
func TestInsert_DEFAULT_VALUES_RETURNING(t *testing.T) {
|
||||
tx := beginSampleDBTx(t)
|
||||
defer tx.Rollback()
|
||||
|
||||
stmt := Link.INSERT().
|
||||
DEFAULT_VALUES().
|
||||
RETURNING(Link.AllColumns)
|
||||
|
||||
testutils.AssertDebugStatementSql(t, stmt, `
|
||||
INSERT INTO link
|
||||
DEFAULT VALUES
|
||||
RETURNING link.id AS "link.id",
|
||||
link.url AS "link.url",
|
||||
link.name AS "link.name",
|
||||
link.description AS "link.description";
|
||||
`)
|
||||
|
||||
var link model.Link
|
||||
err := stmt.Query(tx, &link)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.EqualValues(t, link, model.Link{
|
||||
ID: 25,
|
||||
URL: "www.",
|
||||
Name: "_",
|
||||
Description: nil,
|
||||
})
|
||||
}
|
||||
|
||||
func TestInsertOnConflict(t *testing.T) {
|
||||
|
||||
t.Run("do nothing", func(t *testing.T) {
|
||||
tx := beginSampleDBTx(t)
|
||||
defer tx.Rollback()
|
||||
|
||||
link := model.Link{ID: rand.Int31()}
|
||||
|
||||
stmt := Link.INSERT(Link.AllColumns).
|
||||
MODEL(link).
|
||||
MODEL(link).
|
||||
ON_CONFLICT(Link.ID).DO_NOTHING()
|
||||
|
||||
testutils.AssertStatementSql(t, stmt, `
|
||||
INSERT INTO link (id, url, name, description)
|
||||
VALUES (?, ?, ?, ?),
|
||||
(?, ?, ?, ?)
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
`)
|
||||
testutils.AssertExec(t, stmt, tx, 1)
|
||||
requireLogged(t, stmt)
|
||||
})
|
||||
|
||||
t.Run("do update", func(t *testing.T) {
|
||||
tx := beginSampleDBTx(t)
|
||||
defer tx.Rollback()
|
||||
|
||||
stmt := Link.INSERT(Link.ID, Link.URL, Link.Name, Link.Description).
|
||||
VALUES(21, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial", nil).
|
||||
VALUES(22, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial", nil).
|
||||
ON_CONFLICT(Link.ID).
|
||||
DO_UPDATE(
|
||||
SET(
|
||||
Link.ID.SET(Link.EXCLUDED.ID),
|
||||
Link.URL.SET(String("http://www.postgresqltutorial2.com")),
|
||||
),
|
||||
).RETURNING(Link.AllColumns)
|
||||
|
||||
testutils.AssertStatementSql(t, stmt, `
|
||||
INSERT INTO link (id, url, name, description)
|
||||
VALUES (?, ?, ?, ?),
|
||||
(?, ?, ?, ?)
|
||||
ON CONFLICT (id) DO UPDATE
|
||||
SET id = excluded.id,
|
||||
url = ?
|
||||
RETURNING link.id AS "link.id",
|
||||
link.url AS "link.url",
|
||||
link.name AS "link.name",
|
||||
link.description AS "link.description";
|
||||
`)
|
||||
|
||||
testutils.AssertExec(t, stmt, tx)
|
||||
requireLogged(t, stmt)
|
||||
})
|
||||
|
||||
t.Run("do update complex", func(t *testing.T) {
|
||||
tx := beginSampleDBTx(t)
|
||||
defer tx.Rollback()
|
||||
|
||||
stmt := Link.INSERT(Link.ID, Link.URL, Link.Name, Link.Description).
|
||||
VALUES(21, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial", nil).
|
||||
ON_CONFLICT(Link.ID).
|
||||
WHERE(Link.ID.MUL(Int(2)).GT(Int(10))).
|
||||
DO_UPDATE(
|
||||
SET(
|
||||
Link.ID.SET(
|
||||
IntExp(SELECT(MAXi(Link.ID).ADD(Int(1))).
|
||||
FROM(Link)),
|
||||
),
|
||||
ColumnList{Link.Name, Link.Description}.SET(ROW(Link.EXCLUDED.Name, String(""))),
|
||||
).WHERE(Link.Description.IS_NOT_NULL()),
|
||||
)
|
||||
|
||||
testutils.AssertDebugStatementSql(t, stmt, `
|
||||
INSERT INTO link (id, url, name, description)
|
||||
VALUES (21, 'http://www.postgresqltutorial.com', 'PostgreSQL Tutorial', NULL)
|
||||
ON CONFLICT (id) WHERE (id * 2) > 10 DO UPDATE
|
||||
SET id = (
|
||||
SELECT MAX(link.id) + 1
|
||||
FROM link
|
||||
),
|
||||
(name, description) = (excluded.name, '')
|
||||
WHERE link.description IS NOT NULL;
|
||||
`)
|
||||
|
||||
testutils.AssertExec(t, stmt, tx)
|
||||
requireLogged(t, stmt)
|
||||
})
|
||||
}
|
||||
|
||||
func TestInsertContextDeadlineExceeded(t *testing.T) {
|
||||
stmt := Link.INSERT().
|
||||
VALUES(1100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial", nil)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Microsecond)
|
||||
defer cancel()
|
||||
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
dest := []model.Link{}
|
||||
err := stmt.QueryContext(ctx, sampleDB, &dest)
|
||||
require.Error(t, err, "context deadline exceeded")
|
||||
|
||||
_, err = stmt.ExecContext(ctx, db)
|
||||
require.Error(t, err, "context deadline exceeded")
|
||||
}
|
||||
90
tests/sqlite/main_test.go
Normal file
90
tests/sqlite/main_test.go
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
package sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/go-jet/jet/v2/internal/utils/throw"
|
||||
"github.com/go-jet/jet/v2/sqlite"
|
||||
"github.com/go-jet/jet/v2/tests/dbconfig"
|
||||
"github.com/stretchr/testify/require"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/profile"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
var db *sql.DB
|
||||
var sampleDB *sql.DB
|
||||
var testRoot string
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
rand.Seed(time.Now().Unix())
|
||||
defer profile.Start().Stop()
|
||||
|
||||
setTestRoot()
|
||||
|
||||
var err error
|
||||
db, err = sql.Open("sqlite3", "file:"+dbconfig.SakilaDBPath)
|
||||
throw.OnError(err)
|
||||
|
||||
_, err = db.Exec(fmt.Sprintf("ATTACH DATABASE '%s' as 'chinook';", dbconfig.ChinookDBPath))
|
||||
throw.OnError(err)
|
||||
|
||||
sampleDB, err = sql.Open("sqlite3", dbconfig.TestSampleDBPath)
|
||||
throw.OnError(err)
|
||||
|
||||
defer db.Close()
|
||||
|
||||
ret := m.Run()
|
||||
|
||||
if ret != 0 {
|
||||
os.Exit(ret)
|
||||
}
|
||||
}
|
||||
|
||||
func setTestRoot() {
|
||||
cmd := exec.Command("git", "rev-parse", "--show-toplevel")
|
||||
byteArr, err := cmd.Output()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
testRoot = strings.TrimSpace(string(byteArr)) + "/tests/"
|
||||
}
|
||||
|
||||
var loggedSQL string
|
||||
var loggedSQLArgs []interface{}
|
||||
var loggedDebugSQL string
|
||||
|
||||
func init() {
|
||||
sqlite.SetLogger(func(ctx context.Context, statement sqlite.PrintableStatement) {
|
||||
loggedSQL, loggedSQLArgs = statement.Sql()
|
||||
loggedDebugSQL = statement.DebugSql()
|
||||
})
|
||||
}
|
||||
|
||||
func requireLogged(t *testing.T, statement sqlite.Statement) {
|
||||
query, args := statement.Sql()
|
||||
require.Equal(t, loggedSQL, query)
|
||||
require.Equal(t, loggedSQLArgs, args)
|
||||
require.Equal(t, loggedDebugSQL, statement.DebugSql())
|
||||
}
|
||||
|
||||
func beginSampleDBTx(t *testing.T) *sql.Tx {
|
||||
tx, err := sampleDB.Begin()
|
||||
require.NoError(t, err)
|
||||
return tx
|
||||
}
|
||||
|
||||
func beginDBTx(t *testing.T) *sql.Tx {
|
||||
tx, err := db.Begin()
|
||||
require.NoError(t, err)
|
||||
return tx
|
||||
}
|
||||
121
tests/sqlite/raw_statement_test.go
Normal file
121
tests/sqlite/raw_statement_test.go
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
package sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-jet/jet/v2/internal/testutils"
|
||||
. "github.com/go-jet/jet/v2/sqlite"
|
||||
"github.com/go-jet/jet/v2/tests/.gentestdata/sqlite/sakila/model"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRawStatementSelect(t *testing.T) {
|
||||
stmt := RawStatement(`
|
||||
SELECT actor.first_name AS "actor.first_name"
|
||||
FROM actor
|
||||
WHERE actor.actor_id = 2`)
|
||||
|
||||
testutils.AssertStatementSql(t, stmt, `
|
||||
SELECT actor.first_name AS "actor.first_name"
|
||||
FROM actor
|
||||
WHERE actor.actor_id = 2;
|
||||
`)
|
||||
testutils.AssertDebugStatementSql(t, stmt, `
|
||||
SELECT actor.first_name AS "actor.first_name"
|
||||
FROM actor
|
||||
WHERE actor.actor_id = 2;
|
||||
`)
|
||||
var actor model.Actor
|
||||
err := stmt.Query(db, &actor)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, actor.FirstName, "NICK")
|
||||
}
|
||||
|
||||
func TestRawStatementSelectWithArguments(t *testing.T) {
|
||||
stmt := RawStatement(`
|
||||
SELECT DISTINCT actor.actor_id AS "actor.actor_id",
|
||||
actor.first_name AS "actor.first_name",
|
||||
actor.last_name AS "actor.last_name",
|
||||
actor.last_update AS "actor.last_update"
|
||||
FROM actor
|
||||
WHERE actor.actor_id IN (#actorID1, #actorID2, #actorID3) AND ((#actorID1 / #actorID2) <> (#actorID2 * #actorID3))
|
||||
ORDER BY actor.actor_id`,
|
||||
RawArgs{
|
||||
"#actorID1": int64(1),
|
||||
"#actorID2": int64(2),
|
||||
"#actorID3": int64(3),
|
||||
},
|
||||
)
|
||||
|
||||
testutils.AssertStatementSql(t, stmt, `
|
||||
SELECT DISTINCT actor.actor_id AS "actor.actor_id",
|
||||
actor.first_name AS "actor.first_name",
|
||||
actor.last_name AS "actor.last_name",
|
||||
actor.last_update AS "actor.last_update"
|
||||
FROM actor
|
||||
WHERE actor.actor_id IN (?, ?, ?) AND ((? / ?) <> (? * ?))
|
||||
ORDER BY actor.actor_id;
|
||||
`, int64(1), int64(2), int64(3), int64(1), int64(2), int64(2), int64(3))
|
||||
|
||||
testutils.AssertDebugStatementSql(t, stmt, `
|
||||
SELECT DISTINCT actor.actor_id AS "actor.actor_id",
|
||||
actor.first_name AS "actor.first_name",
|
||||
actor.last_name AS "actor.last_name",
|
||||
actor.last_update AS "actor.last_update"
|
||||
FROM actor
|
||||
WHERE actor.actor_id IN (1, 2, 3) AND ((1 / 2) <> (2 * 3))
|
||||
ORDER BY actor.actor_id;
|
||||
`)
|
||||
|
||||
var actor []model.Actor
|
||||
err := stmt.Query(db, &actor)
|
||||
require.NoError(t, err)
|
||||
|
||||
testutils.AssertDeepEqual(t, actor[1], model.Actor{
|
||||
ActorID: 2,
|
||||
FirstName: "NICK",
|
||||
LastName: "WAHLBERG",
|
||||
LastUpdate: *testutils.TimestampWithoutTimeZone("2019-04-11 18:11:48", 2),
|
||||
})
|
||||
}
|
||||
|
||||
func TestRawStatementRows(t *testing.T) {
|
||||
stmt := RawStatement(`
|
||||
SELECT actor.actor_id AS "actor.actor_id",
|
||||
actor.first_name AS "actor.first_name",
|
||||
actor.last_name AS "actor.last_name",
|
||||
actor.last_update AS "actor.last_update"
|
||||
FROM actor
|
||||
ORDER BY actor.actor_id`)
|
||||
|
||||
rows, err := stmt.Rows(context.Background(), db)
|
||||
require.NoError(t, err)
|
||||
|
||||
for rows.Next() {
|
||||
var actor model.Actor
|
||||
err := rows.Scan(&actor)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NotEqual(t, actor.ActorID, int16(0))
|
||||
require.NotEqual(t, actor.FirstName, "")
|
||||
require.NotEqual(t, actor.LastName, "")
|
||||
require.NotEqual(t, actor.LastUpdate, time.Time{})
|
||||
|
||||
if actor.ActorID == 54 {
|
||||
require.Equal(t, actor.ActorID, int32(54))
|
||||
require.Equal(t, actor.FirstName, "PENELOPE")
|
||||
require.Equal(t, actor.LastName, "PINKETT")
|
||||
require.Equal(t, actor.LastUpdate.Format(time.RFC3339), "2019-04-11T18:11:48Z")
|
||||
}
|
||||
}
|
||||
|
||||
err = rows.Close()
|
||||
require.NoError(t, err)
|
||||
|
||||
err = rows.Err()
|
||||
require.NoError(t, err)
|
||||
|
||||
requireLogged(t, stmt)
|
||||
}
|
||||
749
tests/sqlite/select_test.go
Normal file
749
tests/sqlite/select_test.go
Normal file
|
|
@ -0,0 +1,749 @@
|
|||
package sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
model2 "github.com/go-jet/jet/v2/tests/.gentestdata/sqlite/chinook/model"
|
||||
"github.com/go-jet/jet/v2/tests/.gentestdata/sqlite/chinook/table"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-jet/jet/v2/internal/testutils"
|
||||
. "github.com/go-jet/jet/v2/sqlite"
|
||||
"github.com/go-jet/jet/v2/tests/.gentestdata/sqlite/sakila/model"
|
||||
. "github.com/go-jet/jet/v2/tests/.gentestdata/sqlite/sakila/table"
|
||||
"github.com/go-jet/jet/v2/tests/.gentestdata/sqlite/sakila/view"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSelect_ScanToStruct(t *testing.T) {
|
||||
query := Actor.
|
||||
SELECT(Actor.AllColumns).
|
||||
DISTINCT().
|
||||
WHERE(Actor.ActorID.EQ(Int(2)))
|
||||
|
||||
testutils.AssertStatementSql(t, query, `
|
||||
SELECT DISTINCT actor.actor_id AS "actor.actor_id",
|
||||
actor.first_name AS "actor.first_name",
|
||||
actor.last_name AS "actor.last_name",
|
||||
actor.last_update AS "actor.last_update"
|
||||
FROM actor
|
||||
WHERE actor.actor_id = ?;
|
||||
`, int64(2))
|
||||
|
||||
actor := model.Actor{}
|
||||
err := query.Query(db, &actor)
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
testutils.AssertDeepEqual(t, actor, actor2)
|
||||
requireLogged(t, query)
|
||||
}
|
||||
|
||||
var actor2 = model.Actor{
|
||||
ActorID: 2,
|
||||
FirstName: "NICK",
|
||||
LastName: "WAHLBERG",
|
||||
LastUpdate: *testutils.TimestampWithoutTimeZone("2019-04-11 18:11:48", 2),
|
||||
}
|
||||
|
||||
func TestSelect_ScanToSlice(t *testing.T) {
|
||||
query := SELECT(Actor.AllColumns).
|
||||
FROM(Actor).
|
||||
ORDER_BY(Actor.ActorID)
|
||||
|
||||
testutils.AssertStatementSql(t, query, `
|
||||
SELECT actor.actor_id AS "actor.actor_id",
|
||||
actor.first_name AS "actor.first_name",
|
||||
actor.last_name AS "actor.last_name",
|
||||
actor.last_update AS "actor.last_update"
|
||||
FROM actor
|
||||
ORDER BY actor.actor_id;
|
||||
`)
|
||||
dest := []model.Actor{}
|
||||
|
||||
err := query.Query(db, &dest)
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, len(dest), 200)
|
||||
testutils.AssertDeepEqual(t, dest[1], actor2)
|
||||
|
||||
//testutils.SaveJSONFile(dest, "./testdata/results/sqlite/all_actors.json")
|
||||
testutils.AssertJSONFile(t, dest, "./testdata/results/sqlite/all_actors.json")
|
||||
requireLogged(t, query)
|
||||
}
|
||||
|
||||
func TestSelectGroupByHaving(t *testing.T) {
|
||||
expectedSQL := `
|
||||
SELECT customer.customer_id AS "customer.customer_id",
|
||||
customer.store_id AS "customer.store_id",
|
||||
customer.first_name AS "customer.first_name",
|
||||
customer.last_name AS "customer.last_name",
|
||||
customer.email AS "customer.email",
|
||||
customer.address_id AS "customer.address_id",
|
||||
customer.active AS "customer.active",
|
||||
customer.create_date AS "customer.create_date",
|
||||
customer.last_update AS "customer.last_update",
|
||||
SUM(payment.amount) AS "amount.sum",
|
||||
AVG(payment.amount) AS "amount.avg",
|
||||
MAX(payment.payment_date) AS "amount.max_date",
|
||||
MAX(payment.amount) AS "amount.max",
|
||||
MIN(payment.payment_date) AS "amount.min_date",
|
||||
MIN(payment.amount) AS "amount.min",
|
||||
COUNT(payment.amount) AS "amount.count"
|
||||
FROM payment
|
||||
INNER JOIN customer ON (customer.customer_id = payment.customer_id)
|
||||
GROUP BY payment.customer_id
|
||||
HAVING SUM(payment.amount) > 125.6
|
||||
ORDER BY payment.customer_id, SUM(payment.amount) ASC;
|
||||
`
|
||||
query := Payment.
|
||||
INNER_JOIN(Customer, Customer.CustomerID.EQ(Payment.CustomerID)).
|
||||
SELECT(
|
||||
Customer.AllColumns,
|
||||
|
||||
SUMf(Payment.Amount).AS("amount.sum"),
|
||||
AVG(Payment.Amount).AS("amount.avg"),
|
||||
MAX(Payment.PaymentDate).AS("amount.max_date"),
|
||||
MAXf(Payment.Amount).AS("amount.max"),
|
||||
MIN(Payment.PaymentDate).AS("amount.min_date"),
|
||||
MINf(Payment.Amount).AS("amount.min"),
|
||||
COUNT(Payment.Amount).AS("amount.count"),
|
||||
).
|
||||
GROUP_BY(Payment.CustomerID).
|
||||
HAVING(
|
||||
SUMf(Payment.Amount).GT(Float(125.6)),
|
||||
).
|
||||
ORDER_BY(
|
||||
Payment.CustomerID, SUMf(Payment.Amount).ASC(),
|
||||
)
|
||||
|
||||
testutils.AssertDebugStatementSql(t, query, expectedSQL, float64(125.6))
|
||||
|
||||
var dest []struct {
|
||||
model.Customer
|
||||
|
||||
Amount struct {
|
||||
Sum float64
|
||||
Avg float64
|
||||
Max float64
|
||||
Min float64
|
||||
Count int64
|
||||
} `alias:"amount"`
|
||||
}
|
||||
|
||||
err := query.Query(db, &dest)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(dest), 174)
|
||||
//testutils.SaveJSONFile(dest, "./testdata/results/sqlite/customer_payment_sum.json")
|
||||
testutils.AssertJSONFile(t, dest, "./testdata/results/sqlite/customer_payment_sum.json")
|
||||
requireLogged(t, query)
|
||||
}
|
||||
|
||||
func TestSubQuery(t *testing.T) {
|
||||
|
||||
rRatingFilms :=
|
||||
SELECT(
|
||||
Film.FilmID,
|
||||
Film.Title,
|
||||
Film.Rating,
|
||||
).FROM(
|
||||
Film,
|
||||
).WHERE(Film.Rating.EQ(String("R"))).
|
||||
AsTable("rFilms")
|
||||
|
||||
rFilmID := Film.FilmID.From(rRatingFilms)
|
||||
|
||||
main :=
|
||||
SELECT(
|
||||
Actor.AllColumns,
|
||||
FilmActor.AllColumns,
|
||||
rRatingFilms.AllColumns(),
|
||||
).FROM(
|
||||
rRatingFilms.
|
||||
INNER_JOIN(FilmActor, FilmActor.FilmID.EQ(rFilmID)).
|
||||
INNER_JOIN(Actor, Actor.ActorID.EQ(FilmActor.ActorID)),
|
||||
).ORDER_BY(
|
||||
rFilmID,
|
||||
Actor.ActorID,
|
||||
)
|
||||
|
||||
var dest []struct {
|
||||
model.Film
|
||||
Actors []model.Actor
|
||||
}
|
||||
|
||||
err := main.Query(db, &dest)
|
||||
require.NoError(t, err)
|
||||
|
||||
//testutils.SaveJSONFile(dest, "./testdata/results/sqlite/r_rating_films.json")
|
||||
testutils.AssertJSONFile(t, dest, "./testdata/results/sqlite/r_rating_films.json")
|
||||
}
|
||||
|
||||
func TestSelectAndUnionInProjection(t *testing.T) {
|
||||
query := UNION(
|
||||
SELECT(
|
||||
Payment.PaymentID,
|
||||
).FROM(Payment),
|
||||
|
||||
SELECT(
|
||||
STAR,
|
||||
).FROM(
|
||||
SELECT(Payment.PaymentID).
|
||||
FROM(Payment).LIMIT(1).OFFSET(2).AsTable("p"),
|
||||
),
|
||||
).LIMIT(1).OFFSET(10)
|
||||
|
||||
testutils.AssertDebugStatementSql(t, query, `
|
||||
|
||||
SELECT payment.payment_id AS "payment.payment_id"
|
||||
FROM payment
|
||||
|
||||
UNION
|
||||
|
||||
SELECT *
|
||||
FROM (
|
||||
SELECT payment.payment_id AS "payment.payment_id"
|
||||
FROM payment
|
||||
LIMIT 1
|
||||
OFFSET 2
|
||||
) AS p
|
||||
LIMIT 1
|
||||
OFFSET 10;
|
||||
`, int64(1), int64(2), int64(1), int64(10))
|
||||
|
||||
dest := []struct{}{}
|
||||
err := query.Query(db, &dest)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestSelectUNION(t *testing.T) {
|
||||
expectedSQL := `
|
||||
|
||||
SELECT payment.payment_id AS "payment.payment_id"
|
||||
FROM payment
|
||||
WHERE payment.payment_id > ?
|
||||
|
||||
UNION
|
||||
|
||||
SELECT payment.payment_id AS "payment.payment_id"
|
||||
FROM payment
|
||||
WHERE payment.amount < ?
|
||||
LIMIT ?;
|
||||
`
|
||||
query := UNION(
|
||||
SELECT(Payment.PaymentID).
|
||||
FROM(Payment).
|
||||
WHERE(Payment.PaymentID.GT(Int(11))),
|
||||
|
||||
SELECT(Payment.PaymentID).
|
||||
FROM(Payment).
|
||||
WHERE(Payment.Amount.LT(Float(2000.0))),
|
||||
).LIMIT(1)
|
||||
|
||||
testutils.AssertStatementSql(t, query, expectedSQL, int64(11), 2000.0, int64(1))
|
||||
|
||||
query2 :=
|
||||
SELECT(
|
||||
Payment.PaymentID,
|
||||
).FROM(
|
||||
Payment,
|
||||
).WHERE(
|
||||
Payment.PaymentID.GT(Int(11)),
|
||||
).UNION(
|
||||
SELECT(Payment.PaymentID).
|
||||
FROM(Payment).
|
||||
WHERE(Payment.Amount.LT(Float(2000.0))),
|
||||
).LIMIT(1)
|
||||
|
||||
testutils.AssertStatementSql(t, query2, expectedSQL, int64(11), 2000.0, int64(1))
|
||||
|
||||
dest := []struct{}{}
|
||||
err := query.Query(db, &dest)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestSelectUNION_ALL(t *testing.T) {
|
||||
expectedSQL := `
|
||||
|
||||
SELECT payment.payment_id AS "payment.payment_id"
|
||||
FROM payment
|
||||
WHERE payment.payment_id > ?
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT payment.payment_id AS "payment.payment_id"
|
||||
FROM payment
|
||||
WHERE payment.amount < ?
|
||||
LIMIT ?;
|
||||
`
|
||||
query := UNION_ALL(
|
||||
SELECT(Payment.PaymentID).
|
||||
FROM(Payment).
|
||||
WHERE(Payment.PaymentID.GT(Int(11))),
|
||||
|
||||
SELECT(Payment.PaymentID).
|
||||
FROM(Payment).
|
||||
WHERE(Payment.Amount.LT(Float(2000.0))),
|
||||
).LIMIT(1)
|
||||
|
||||
testutils.AssertStatementSql(t, query, expectedSQL, int64(11), 2000.0, int64(1))
|
||||
|
||||
dest := []struct{}{}
|
||||
err := query.Query(db, &dest)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestJoinQueryStruct(t *testing.T) {
|
||||
|
||||
expectedSQL := `
|
||||
SELECT film_actor.actor_id AS "film_actor.actor_id",
|
||||
film_actor.film_id AS "film_actor.film_id",
|
||||
film_actor.last_update AS "film_actor.last_update",
|
||||
film.film_id AS "film.film_id",
|
||||
film.title AS "film.title",
|
||||
film.description AS "film.description",
|
||||
film.release_year AS "film.release_year",
|
||||
film.language_id AS "film.language_id",
|
||||
film.original_language_id AS "film.original_language_id",
|
||||
film.rental_duration AS "film.rental_duration",
|
||||
film.rental_rate AS "film.rental_rate",
|
||||
film.length AS "film.length",
|
||||
film.replacement_cost AS "film.replacement_cost",
|
||||
film.rating AS "film.rating",
|
||||
film.special_features AS "film.special_features",
|
||||
film.last_update AS "film.last_update",
|
||||
language.language_id AS "language.language_id",
|
||||
language.name AS "language.name",
|
||||
language.last_update AS "language.last_update",
|
||||
actor.actor_id AS "actor.actor_id",
|
||||
actor.first_name AS "actor.first_name",
|
||||
actor.last_name AS "actor.last_name",
|
||||
actor.last_update AS "actor.last_update",
|
||||
inventory.inventory_id AS "inventory.inventory_id",
|
||||
inventory.film_id AS "inventory.film_id",
|
||||
inventory.store_id AS "inventory.store_id",
|
||||
inventory.last_update AS "inventory.last_update",
|
||||
rental.rental_id AS "rental.rental_id",
|
||||
rental.rental_date AS "rental.rental_date",
|
||||
rental.inventory_id AS "rental.inventory_id",
|
||||
rental.customer_id AS "rental.customer_id",
|
||||
rental.return_date AS "rental.return_date",
|
||||
rental.staff_id AS "rental.staff_id",
|
||||
rental.last_update AS "rental.last_update"
|
||||
FROM language
|
||||
INNER JOIN film ON (film.language_id = language.language_id)
|
||||
INNER JOIN film_actor ON (film_actor.film_id = film.film_id)
|
||||
INNER JOIN actor ON (actor.actor_id = film_actor.actor_id)
|
||||
LEFT JOIN inventory ON (inventory.film_id = film.film_id)
|
||||
LEFT JOIN rental ON (rental.inventory_id = inventory.inventory_id)
|
||||
ORDER BY language.language_id ASC, film.film_id ASC, actor.actor_id ASC, inventory.inventory_id ASC, rental.rental_id ASC
|
||||
LIMIT ?;
|
||||
`
|
||||
for i := 0; i < 2; i++ {
|
||||
query :=
|
||||
SELECT(
|
||||
FilmActor.AllColumns,
|
||||
Film.AllColumns,
|
||||
Language.AllColumns,
|
||||
Actor.AllColumns,
|
||||
Inventory.AllColumns,
|
||||
Rental.AllColumns,
|
||||
).
|
||||
FROM(
|
||||
Language.
|
||||
INNER_JOIN(Film, Film.LanguageID.EQ(Language.LanguageID)).
|
||||
INNER_JOIN(FilmActor, FilmActor.FilmID.EQ(Film.FilmID)).
|
||||
INNER_JOIN(Actor, Actor.ActorID.EQ(FilmActor.ActorID)).
|
||||
LEFT_JOIN(Inventory, Inventory.FilmID.EQ(Film.FilmID)).
|
||||
LEFT_JOIN(Rental, Rental.InventoryID.EQ(Inventory.InventoryID)),
|
||||
).ORDER_BY(
|
||||
Language.LanguageID.ASC(),
|
||||
Film.FilmID.ASC(),
|
||||
Actor.ActorID.ASC(),
|
||||
Inventory.InventoryID.ASC(),
|
||||
Rental.RentalID.ASC(),
|
||||
).
|
||||
LIMIT(1000)
|
||||
|
||||
testutils.AssertStatementSql(t, query, expectedSQL, int64(1000))
|
||||
|
||||
var dest []struct {
|
||||
model.Language
|
||||
|
||||
Films []struct {
|
||||
model.Film
|
||||
|
||||
Actors []struct {
|
||||
model.Actor
|
||||
}
|
||||
|
||||
Inventories *[]struct {
|
||||
model.Inventory
|
||||
|
||||
Rentals *[]model.Rental
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err := query.Query(db, &dest)
|
||||
|
||||
require.NoError(t, err)
|
||||
testutils.AssertJSONFile(t, dest, "./testdata/results/sqlite/lang_film_actor_inventory_rental.json")
|
||||
}
|
||||
}
|
||||
|
||||
func TestExpressionWrappers(t *testing.T) {
|
||||
query := SELECT(
|
||||
BoolExp(Raw("true")),
|
||||
IntExp(Raw("11")),
|
||||
FloatExp(Raw("11.22")),
|
||||
StringExp(Raw("'stringer'")),
|
||||
TimeExp(Raw("'raw'")),
|
||||
TimestampExp(Raw("'raw'")),
|
||||
DateTimeExp(Raw("'raw'")),
|
||||
DateExp(Raw("'date'")),
|
||||
)
|
||||
|
||||
testutils.AssertStatementSql(t, query, `
|
||||
SELECT true,
|
||||
11,
|
||||
11.22,
|
||||
'stringer',
|
||||
'raw',
|
||||
'raw',
|
||||
'raw',
|
||||
'date';
|
||||
`)
|
||||
|
||||
dest := []struct{}{}
|
||||
err := query.Query(db, &dest)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestWindowFunction(t *testing.T) {
|
||||
var expectedSQL = `
|
||||
SELECT AVG(payment.amount) OVER (),
|
||||
AVG(payment.amount) OVER (PARTITION BY payment.customer_id),
|
||||
MAX(payment.amount) OVER (ORDER BY payment.payment_date DESC),
|
||||
MIN(payment.amount) OVER (PARTITION BY payment.customer_id ORDER BY payment.payment_date DESC),
|
||||
SUM(payment.amount) OVER (PARTITION BY payment.customer_id ORDER BY payment.payment_date DESC ROWS BETWEEN 1 PRECEDING AND 6 FOLLOWING),
|
||||
SUM(payment.amount) OVER (PARTITION BY payment.customer_id ORDER BY payment.payment_date DESC RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING),
|
||||
MAX(payment.customer_id) OVER (ORDER BY payment.payment_date DESC ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING),
|
||||
MIN(payment.customer_id) OVER (PARTITION BY payment.customer_id ORDER BY payment.payment_date DESC),
|
||||
SUM(payment.customer_id) OVER (PARTITION BY payment.customer_id ORDER BY payment.payment_date DESC),
|
||||
ROW_NUMBER() OVER (ORDER BY payment.payment_date),
|
||||
RANK() OVER (ORDER BY payment.payment_date),
|
||||
DENSE_RANK() OVER (ORDER BY payment.payment_date),
|
||||
CUME_DIST() OVER (ORDER BY payment.payment_date),
|
||||
NTILE(11) OVER (ORDER BY payment.payment_date),
|
||||
LAG(payment.amount) OVER (ORDER BY payment.payment_date),
|
||||
LAG(payment.amount) OVER (ORDER BY payment.payment_date),
|
||||
LAG(payment.amount, 2, payment.amount) OVER (ORDER BY payment.payment_date),
|
||||
LAG(payment.amount, 2, ?) OVER (ORDER BY payment.payment_date),
|
||||
LEAD(payment.amount) OVER (ORDER BY payment.payment_date),
|
||||
LEAD(payment.amount) OVER (ORDER BY payment.payment_date),
|
||||
LEAD(payment.amount, 2, payment.amount) OVER (ORDER BY payment.payment_date),
|
||||
LEAD(payment.amount, 2, ?) OVER (ORDER BY payment.payment_date),
|
||||
FIRST_VALUE(payment.amount) OVER (ORDER BY payment.payment_date),
|
||||
LAST_VALUE(payment.amount) OVER (ORDER BY payment.payment_date),
|
||||
NTH_VALUE(payment.amount, 3) OVER (ORDER BY payment.payment_date)
|
||||
FROM payment
|
||||
WHERE payment.payment_id < ?
|
||||
GROUP BY payment.amount, payment.customer_id, payment.payment_date;
|
||||
`
|
||||
query :=
|
||||
SELECT(
|
||||
AVG(Payment.Amount).OVER(),
|
||||
AVG(Payment.Amount).OVER(PARTITION_BY(Payment.CustomerID)),
|
||||
MAXf(Payment.Amount).OVER(ORDER_BY(Payment.PaymentDate.DESC())),
|
||||
MINf(Payment.Amount).OVER(PARTITION_BY(Payment.CustomerID).ORDER_BY(Payment.PaymentDate.DESC())),
|
||||
SUMf(Payment.Amount).OVER(PARTITION_BY(Payment.CustomerID).
|
||||
ORDER_BY(Payment.PaymentDate.DESC()).ROWS(PRECEDING(1), FOLLOWING(6))),
|
||||
SUMf(Payment.Amount).OVER(PARTITION_BY(Payment.CustomerID).
|
||||
ORDER_BY(Payment.PaymentDate.DESC()).RANGE(PRECEDING(UNBOUNDED), FOLLOWING(UNBOUNDED))),
|
||||
MAXi(Payment.CustomerID).OVER(ORDER_BY(Payment.PaymentDate.DESC()).ROWS(CURRENT_ROW, FOLLOWING(UNBOUNDED))),
|
||||
MINi(Payment.CustomerID).OVER(PARTITION_BY(Payment.CustomerID).ORDER_BY(Payment.PaymentDate.DESC())),
|
||||
SUMi(Payment.CustomerID).OVER(PARTITION_BY(Payment.CustomerID).ORDER_BY(Payment.PaymentDate.DESC())),
|
||||
ROW_NUMBER().OVER(ORDER_BY(Payment.PaymentDate)),
|
||||
RANK().OVER(ORDER_BY(Payment.PaymentDate)),
|
||||
DENSE_RANK().OVER(ORDER_BY(Payment.PaymentDate)),
|
||||
CUME_DIST().OVER(ORDER_BY(Payment.PaymentDate)),
|
||||
NTILE(11).OVER(ORDER_BY(Payment.PaymentDate)),
|
||||
LAG(Payment.Amount).OVER(ORDER_BY(Payment.PaymentDate)),
|
||||
LAG(Payment.Amount, 2).OVER(ORDER_BY(Payment.PaymentDate)),
|
||||
LAG(Payment.Amount, 2, Payment.Amount).OVER(ORDER_BY(Payment.PaymentDate)),
|
||||
LAG(Payment.Amount, 2, 100).OVER(ORDER_BY(Payment.PaymentDate)),
|
||||
LEAD(Payment.Amount).OVER(ORDER_BY(Payment.PaymentDate)),
|
||||
LEAD(Payment.Amount, 2).OVER(ORDER_BY(Payment.PaymentDate)),
|
||||
LEAD(Payment.Amount, 2, Payment.Amount).OVER(ORDER_BY(Payment.PaymentDate)),
|
||||
LEAD(Payment.Amount, 2, 100).OVER(ORDER_BY(Payment.PaymentDate)),
|
||||
FIRST_VALUE(Payment.Amount).OVER(ORDER_BY(Payment.PaymentDate)),
|
||||
LAST_VALUE(Payment.Amount).OVER(ORDER_BY(Payment.PaymentDate)),
|
||||
NTH_VALUE(Payment.Amount, 3).OVER(ORDER_BY(Payment.PaymentDate)),
|
||||
).FROM(
|
||||
Payment,
|
||||
).GROUP_BY(
|
||||
Payment.Amount,
|
||||
Payment.CustomerID,
|
||||
Payment.PaymentDate,
|
||||
).WHERE(Payment.PaymentID.LT(Int(10)))
|
||||
|
||||
testutils.AssertStatementSql(t, query, expectedSQL, 100, 100, int64(10))
|
||||
|
||||
dest := []struct{}{}
|
||||
err := query.Query(db, &dest)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestWindowClause(t *testing.T) {
|
||||
var expectedSQL = `
|
||||
SELECT AVG(payment.amount) OVER (),
|
||||
AVG(payment.amount) OVER (w1),
|
||||
AVG(payment.amount) OVER (w2 ORDER BY payment.customer_id RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING),
|
||||
AVG(payment.amount) OVER (w3 RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
|
||||
FROM payment
|
||||
WHERE payment.payment_id < ?
|
||||
WINDOW w1 AS (PARTITION BY payment.payment_date), w2 AS (w1), w3 AS (w2 ORDER BY payment.customer_id)
|
||||
ORDER BY payment.customer_id;
|
||||
`
|
||||
query := SELECT(
|
||||
AVG(Payment.Amount).OVER(),
|
||||
AVG(Payment.Amount).OVER(Window("w1")),
|
||||
AVG(Payment.Amount).OVER(
|
||||
Window("w2").
|
||||
ORDER_BY(Payment.CustomerID).
|
||||
RANGE(PRECEDING(UNBOUNDED), FOLLOWING(UNBOUNDED)),
|
||||
),
|
||||
AVG(Payment.Amount).OVER(Window("w3").RANGE(PRECEDING(UNBOUNDED), FOLLOWING(UNBOUNDED))),
|
||||
).FROM(
|
||||
Payment,
|
||||
).WHERE(
|
||||
Payment.PaymentID.LT(Int(10)),
|
||||
).
|
||||
WINDOW("w1").AS(PARTITION_BY(Payment.PaymentDate)).
|
||||
WINDOW("w2").AS(Window("w1")).
|
||||
WINDOW("w3").AS(Window("w2").ORDER_BY(Payment.CustomerID)).
|
||||
ORDER_BY(
|
||||
Payment.CustomerID,
|
||||
)
|
||||
|
||||
testutils.AssertStatementSql(t, query, expectedSQL, int64(10))
|
||||
|
||||
dest := []struct{}{}
|
||||
err := query.Query(db, &dest)
|
||||
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestSimpleView(t *testing.T) {
|
||||
query :=
|
||||
SELECT(
|
||||
view.CustomerList.AllColumns,
|
||||
).FROM(
|
||||
view.CustomerList,
|
||||
).ORDER_BY(
|
||||
view.CustomerList.ID,
|
||||
).LIMIT(10)
|
||||
|
||||
var dest []model.CustomerList
|
||||
|
||||
err := query.Query(db, &dest)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, len(dest), 10)
|
||||
require.Equal(t, dest[2], model.CustomerList{
|
||||
ID: testutils.Int32Ptr(3),
|
||||
Name: testutils.StringPtr("LINDA WILLIAMS"),
|
||||
Address: testutils.StringPtr("692 Joliet Street"),
|
||||
ZipCode: testutils.StringPtr("83579"),
|
||||
Phone: testutils.StringPtr(" "),
|
||||
City: testutils.StringPtr("Athenai"),
|
||||
Country: testutils.StringPtr("Greece"),
|
||||
Notes: testutils.StringPtr("active"),
|
||||
Sid: testutils.Int32Ptr(1),
|
||||
})
|
||||
}
|
||||
|
||||
func TestJoinViewWithTable(t *testing.T) {
|
||||
query :=
|
||||
SELECT(
|
||||
view.CustomerList.AllColumns,
|
||||
Rental.AllColumns,
|
||||
).FROM(
|
||||
view.CustomerList.
|
||||
INNER_JOIN(Rental, view.CustomerList.ID.EQ(Rental.CustomerID)),
|
||||
).ORDER_BY(
|
||||
view.CustomerList.ID,
|
||||
).WHERE(
|
||||
view.CustomerList.ID.LT_EQ(Int(2)),
|
||||
)
|
||||
|
||||
var dest []struct {
|
||||
model.CustomerList `sql:"primary_key=ID"`
|
||||
Rentals []model.Rental
|
||||
}
|
||||
|
||||
err := query.Query(db, &dest)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, len(dest), 2)
|
||||
require.Equal(t, len(dest[0].Rentals), 32)
|
||||
require.Equal(t, len(dest[1].Rentals), 27)
|
||||
}
|
||||
|
||||
func TestConditionalProjectionList(t *testing.T) {
|
||||
projectionList := ProjectionList{}
|
||||
|
||||
columnsToSelect := []string{"customer_id", "create_date"}
|
||||
|
||||
for _, columnName := range columnsToSelect {
|
||||
switch columnName {
|
||||
case Customer.CustomerID.Name():
|
||||
projectionList = append(projectionList, Customer.CustomerID)
|
||||
case Customer.Email.Name():
|
||||
projectionList = append(projectionList, Customer.Email)
|
||||
case Customer.CreateDate.Name():
|
||||
projectionList = append(projectionList, Customer.CreateDate)
|
||||
}
|
||||
}
|
||||
|
||||
stmt := SELECT(projectionList).
|
||||
FROM(Customer).
|
||||
LIMIT(3)
|
||||
|
||||
testutils.AssertDebugStatementSql(t, stmt, `
|
||||
SELECT customer.customer_id AS "customer.customer_id",
|
||||
customer.create_date AS "customer.create_date"
|
||||
FROM customer
|
||||
LIMIT 3;
|
||||
`)
|
||||
var dest []model.Customer
|
||||
err := stmt.Query(db, &dest)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, len(dest), 3)
|
||||
}
|
||||
|
||||
func TestUseAttachedDatabase(t *testing.T) {
|
||||
Artists := table.Artists.FromSchema("chinook")
|
||||
Albums := table.Albums.FromSchema("chinook")
|
||||
|
||||
stmt :=
|
||||
SELECT(
|
||||
Artists.AllColumns,
|
||||
Albums.AllColumns,
|
||||
).FROM(
|
||||
Albums.
|
||||
INNER_JOIN(Artists, Artists.ArtistId.EQ(Albums.ArtistId)),
|
||||
).ORDER_BY(
|
||||
Artists.ArtistId,
|
||||
).LIMIT(10)
|
||||
|
||||
testutils.AssertDebugStatementSql(t, stmt, strings.Replace(`
|
||||
SELECT artists.''ArtistId'' AS "artists.ArtistId",
|
||||
artists.''Name'' AS "artists.Name",
|
||||
albums.''AlbumId'' AS "albums.AlbumId",
|
||||
albums.''Title'' AS "albums.Title",
|
||||
albums.''ArtistId'' AS "albums.ArtistId"
|
||||
FROM chinook.albums
|
||||
INNER JOIN chinook.artists ON (artists.''ArtistId'' = albums.''ArtistId'')
|
||||
ORDER BY artists.''ArtistId''
|
||||
LIMIT 10;
|
||||
`, "''", "`", -1))
|
||||
|
||||
var dest []struct {
|
||||
model2.Artists
|
||||
Albums []model2.Albums
|
||||
}
|
||||
|
||||
err := stmt.Query(db, &dest)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, dest, 7)
|
||||
}
|
||||
|
||||
func TestRowsScan(t *testing.T) {
|
||||
stmt :=
|
||||
SELECT(
|
||||
Inventory.AllColumns,
|
||||
).FROM(
|
||||
Inventory,
|
||||
).ORDER_BY(
|
||||
Inventory.InventoryID.ASC(),
|
||||
)
|
||||
|
||||
rows, err := stmt.Rows(context.Background(), db)
|
||||
require.NoError(t, err)
|
||||
|
||||
for rows.Next() {
|
||||
var inventory model.Inventory
|
||||
err = rows.Scan(&inventory)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NotEqual(t, inventory.InventoryID, uint32(0))
|
||||
require.NotEqual(t, inventory.FilmID, uint16(0))
|
||||
require.NotEqual(t, inventory.StoreID, uint16(0))
|
||||
require.NotEqual(t, inventory.LastUpdate, time.Time{})
|
||||
|
||||
if inventory.InventoryID == 2103 {
|
||||
require.Equal(t, inventory.FilmID, int32(456))
|
||||
require.Equal(t, inventory.StoreID, int32(2))
|
||||
require.Equal(t, inventory.LastUpdate.Format(time.RFC3339), "2019-04-11T18:11:48Z")
|
||||
}
|
||||
}
|
||||
|
||||
err = rows.Close()
|
||||
require.NoError(t, err)
|
||||
err = rows.Err()
|
||||
require.NoError(t, err)
|
||||
|
||||
requireLogged(t, stmt)
|
||||
}
|
||||
|
||||
func TestScanNumericToNumber(t *testing.T) {
|
||||
type Number struct {
|
||||
Int8 int8
|
||||
UInt8 uint8
|
||||
Int16 int16
|
||||
UInt16 uint16
|
||||
Int32 int32
|
||||
UInt32 uint32
|
||||
Int64 int64
|
||||
UInt64 uint64
|
||||
Float32 float32
|
||||
Float64 float64
|
||||
}
|
||||
|
||||
numeric := CAST(String("1234567890.111")).AS_REAL()
|
||||
|
||||
stmt := SELECT(
|
||||
numeric.AS("number.int8"),
|
||||
numeric.AS("number.uint8"),
|
||||
numeric.AS("number.int16"),
|
||||
numeric.AS("number.uint16"),
|
||||
numeric.AS("number.int32"),
|
||||
numeric.AS("number.uint32"),
|
||||
numeric.AS("number.int64"),
|
||||
numeric.AS("number.uint64"),
|
||||
numeric.AS("number.float32"),
|
||||
numeric.AS("number.float64"),
|
||||
)
|
||||
|
||||
var number Number
|
||||
err := stmt.Query(db, &number)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, number.Int8, int8(-46)) // overflow
|
||||
require.Equal(t, number.UInt8, uint8(210)) // overflow
|
||||
require.Equal(t, number.Int16, int16(722)) // overflow
|
||||
require.Equal(t, number.UInt16, uint16(722)) // overflow
|
||||
require.Equal(t, number.Int32, int32(1234567890))
|
||||
require.Equal(t, number.UInt32, uint32(1234567890))
|
||||
require.Equal(t, number.Int64, int64(1234567890))
|
||||
require.Equal(t, number.UInt64, uint64(1234567890))
|
||||
require.Equal(t, number.Float32, float32(1.234568e+09))
|
||||
require.Equal(t, number.Float64, float64(1.234567890111e+09))
|
||||
}
|
||||
290
tests/sqlite/update_test.go
Normal file
290
tests/sqlite/update_test.go
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
package sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-jet/jet/v2/internal/testutils"
|
||||
. "github.com/go-jet/jet/v2/sqlite"
|
||||
"github.com/go-jet/jet/v2/tests/.gentestdata/sqlite/test_sample/model"
|
||||
. "github.com/go-jet/jet/v2/tests/.gentestdata/sqlite/test_sample/table"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestUpdateValues(t *testing.T) {
|
||||
tx := beginSampleDBTx(t)
|
||||
defer tx.Rollback()
|
||||
|
||||
var expectedSQL = `
|
||||
UPDATE link
|
||||
SET name = 'Bong',
|
||||
url = 'http://bong.com'
|
||||
WHERE link.name = 'Bing';
|
||||
`
|
||||
t.Run("old version", func(t *testing.T) {
|
||||
query := Link.UPDATE(Link.Name, Link.URL).
|
||||
SET("Bong", "http://bong.com").
|
||||
WHERE(Link.Name.EQ(String("Bing")))
|
||||
|
||||
testutils.AssertDebugStatementSql(t, query, expectedSQL, "Bong", "http://bong.com", "Bing")
|
||||
testutils.AssertExec(t, query, tx)
|
||||
requireLogged(t, query)
|
||||
})
|
||||
|
||||
t.Run("new version", func(t *testing.T) {
|
||||
stmt := Link.UPDATE().
|
||||
SET(
|
||||
Link.Name.SET(String("Bong")),
|
||||
Link.URL.SET(String("http://bong.com")),
|
||||
).
|
||||
WHERE(Link.Name.EQ(String("Bing")))
|
||||
|
||||
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, "Bong", "http://bong.com", "Bing")
|
||||
testutils.AssertExec(t, stmt, tx)
|
||||
requireLogged(t, stmt)
|
||||
})
|
||||
|
||||
links := []model.Link{}
|
||||
|
||||
err := SELECT(Link.AllColumns).
|
||||
FROM(Link).
|
||||
WHERE(Link.Name.EQ(String("Bong"))).
|
||||
Query(tx, &links)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(links), 1)
|
||||
testutils.AssertDeepEqual(t, links[0], model.Link{
|
||||
ID: 24,
|
||||
URL: "http://bong.com",
|
||||
Name: "Bong",
|
||||
})
|
||||
}
|
||||
|
||||
func TestUpdateWithSubQueries(t *testing.T) {
|
||||
tx := beginSampleDBTx(t)
|
||||
defer tx.Rollback()
|
||||
|
||||
expectedSQL := `
|
||||
UPDATE link
|
||||
SET name = ?,
|
||||
url = (
|
||||
SELECT link.url AS "link.url"
|
||||
FROM link
|
||||
WHERE link.name = ?
|
||||
)
|
||||
WHERE link.name = ?;
|
||||
`
|
||||
t.Run("old version", func(t *testing.T) {
|
||||
query := Link.
|
||||
UPDATE(Link.Name, Link.URL).
|
||||
SET(
|
||||
String("Bong"),
|
||||
SELECT(Link.URL).
|
||||
FROM(Link).
|
||||
WHERE(Link.Name.EQ(String("Ask"))),
|
||||
).
|
||||
WHERE(Link.Name.EQ(String("Bing")))
|
||||
|
||||
testutils.AssertStatementSql(t, query, expectedSQL, "Bong", "Ask", "Bing")
|
||||
testutils.AssertExec(t, query, tx)
|
||||
requireLogged(t, query)
|
||||
})
|
||||
|
||||
t.Run("new version", func(t *testing.T) {
|
||||
query := Link.
|
||||
UPDATE().
|
||||
SET(
|
||||
Link.Name.SET(String("Bong")),
|
||||
Link.URL.SET(StringExp(
|
||||
SELECT(Link.URL).
|
||||
FROM(Link).
|
||||
WHERE(Link.Name.EQ(String("Ask"))),
|
||||
)),
|
||||
).
|
||||
WHERE(Link.Name.EQ(String("Bing")))
|
||||
|
||||
testutils.AssertStatementSql(t, query, expectedSQL, "Bong", "Ask", "Bing")
|
||||
testutils.AssertExec(t, query, tx)
|
||||
requireLogged(t, query)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUpdateWithModelDataAndReturning(t *testing.T) {
|
||||
tx := beginSampleDBTx(t)
|
||||
defer tx.Rollback()
|
||||
|
||||
link := model.Link{
|
||||
ID: 20,
|
||||
URL: "http://www.duckduckgo.com",
|
||||
Name: "DuckDuckGo",
|
||||
}
|
||||
|
||||
stmt := Link.UPDATE(Link.AllColumns).
|
||||
MODEL(link).
|
||||
WHERE(Link.ID.EQ(Int32(link.ID))).
|
||||
RETURNING(
|
||||
Link.AllColumns,
|
||||
String("str").AS("dest.literal"),
|
||||
NOT(Bool(false)).AS("dest.unary_operator"),
|
||||
Link.ID.ADD(Int(11)).AS("dest.binary_operator"),
|
||||
CAST(Link.ID).AS_TEXT().AS("dest.cast_operator"),
|
||||
Link.Name.LIKE(String("Bing")).AS("dest.like_operator"),
|
||||
Link.Description.IS_NULL().AS("dest.is_null"),
|
||||
CASE(Link.Name).
|
||||
WHEN(String("Yahoo")).THEN(String("search")).
|
||||
WHEN(String("GMail")).THEN(String("mail")).
|
||||
ELSE(String("unknown")).AS("dest.case_operator"),
|
||||
)
|
||||
|
||||
expectedSQL := `
|
||||
UPDATE link
|
||||
SET id = ?,
|
||||
url = ?,
|
||||
name = ?,
|
||||
description = ?
|
||||
WHERE link.id = ?
|
||||
RETURNING link.id AS "link.id",
|
||||
link.url AS "link.url",
|
||||
link.name AS "link.name",
|
||||
link.description AS "link.description",
|
||||
? AS "dest.literal",
|
||||
(NOT ?) AS "dest.unary_operator",
|
||||
(link.id + ?) AS "dest.binary_operator",
|
||||
CAST(link.id AS TEXT) AS "dest.cast_operator",
|
||||
(link.name LIKE ?) AS "dest.like_operator",
|
||||
link.description IS NULL AS "dest.is_null",
|
||||
(CASE link.name WHEN ? THEN ? WHEN ? THEN ? ELSE ? END) AS "dest.case_operator";
|
||||
`
|
||||
testutils.AssertStatementSql(t, stmt, expectedSQL, int32(20), "http://www.duckduckgo.com", "DuckDuckGo", nil, int32(20),
|
||||
"str", false, int64(11), "Bing", "Yahoo", "search", "GMail", "mail", "unknown")
|
||||
|
||||
type Dest struct {
|
||||
model.Link
|
||||
Literal string
|
||||
UnaryOperator bool
|
||||
BinaryOperator int64
|
||||
CastOperator string
|
||||
LikeOperator bool
|
||||
IsNull bool
|
||||
CaseOperator string
|
||||
}
|
||||
|
||||
var dest Dest
|
||||
|
||||
err := stmt.Query(tx, &dest)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, dest, Dest{
|
||||
Link: link,
|
||||
Literal: "str",
|
||||
UnaryOperator: true,
|
||||
BinaryOperator: 31,
|
||||
CastOperator: "20",
|
||||
LikeOperator: false,
|
||||
IsNull: true,
|
||||
CaseOperator: "unknown",
|
||||
})
|
||||
requireLogged(t, stmt)
|
||||
}
|
||||
|
||||
func TestUpdateWithModelDataAndPredefinedColumnList(t *testing.T) {
|
||||
tx := beginSampleDBTx(t)
|
||||
defer tx.Rollback()
|
||||
|
||||
link := model.Link{
|
||||
ID: 20,
|
||||
URL: "http://www.duckduckgo.com",
|
||||
Name: "DuckDuckGo",
|
||||
}
|
||||
|
||||
updateColumnList := ColumnList{Link.Description, Link.Name, Link.URL}
|
||||
|
||||
stmt := Link.UPDATE(updateColumnList).
|
||||
MODEL(link).
|
||||
WHERE(Link.ID.EQ(Int32(link.ID)))
|
||||
|
||||
var expectedSQL = `
|
||||
UPDATE link
|
||||
SET description = NULL,
|
||||
name = 'DuckDuckGo',
|
||||
url = 'http://www.duckduckgo.com'
|
||||
WHERE link.id = 20;
|
||||
`
|
||||
|
||||
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, nil, "DuckDuckGo", "http://www.duckduckgo.com", int32(20))
|
||||
|
||||
testutils.AssertExec(t, stmt, tx)
|
||||
requireLogged(t, stmt)
|
||||
}
|
||||
|
||||
func TestUpdateWithModelDataAndMutableColumns(t *testing.T) {
|
||||
tx := beginSampleDBTx(t)
|
||||
defer tx.Rollback()
|
||||
|
||||
link := model.Link{
|
||||
ID: 201,
|
||||
URL: "http://www.duckduckgo.com",
|
||||
Name: "DuckDuckGo",
|
||||
}
|
||||
|
||||
stmt := Link.UPDATE(Link.MutableColumns).
|
||||
MODEL(link).
|
||||
WHERE(Link.ID.EQ(Int32(link.ID)))
|
||||
|
||||
var expectedSQL = `
|
||||
UPDATE link
|
||||
SET url = 'http://www.duckduckgo.com',
|
||||
name = 'DuckDuckGo',
|
||||
description = NULL
|
||||
WHERE link.id = 201;
|
||||
`
|
||||
|
||||
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, "http://www.duckduckgo.com", "DuckDuckGo", nil, int32(201))
|
||||
testutils.AssertExec(t, stmt, tx)
|
||||
}
|
||||
|
||||
func TestUpdateWithInvalidModelData(t *testing.T) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
require.Equal(t, r, "missing struct field for column : id")
|
||||
}()
|
||||
|
||||
link := struct {
|
||||
Ident int
|
||||
URL string
|
||||
Name string
|
||||
Description *string
|
||||
Rel *string
|
||||
}{
|
||||
Ident: 201,
|
||||
URL: "http://www.duckduckgo.com",
|
||||
Name: "DuckDuckGo",
|
||||
}
|
||||
|
||||
stmt := Link.UPDATE(Link.AllColumns).
|
||||
MODEL(link).
|
||||
WHERE(Link.ID.EQ(Int(int64(link.Ident))))
|
||||
|
||||
stmt.Sql()
|
||||
}
|
||||
|
||||
func TestUpdateContextDeadlineExceeded(t *testing.T) {
|
||||
tx := beginSampleDBTx(t)
|
||||
defer tx.Rollback()
|
||||
|
||||
updateStmt := Link.UPDATE(Link.Name, Link.URL).
|
||||
SET("Bong", "http://bong.com").
|
||||
WHERE(Link.Name.EQ(String("Bing")))
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Microsecond)
|
||||
defer cancel()
|
||||
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
dest := []model.Link{}
|
||||
err := updateStmt.QueryContext(ctx, tx, &dest)
|
||||
require.Error(t, err, "context deadline exceeded")
|
||||
|
||||
_, err = updateStmt.ExecContext(ctx, tx)
|
||||
require.Error(t, err, "context deadline exceeded")
|
||||
}
|
||||
234
tests/sqlite/with_test.go
Normal file
234
tests/sqlite/with_test.go
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
package sqlite
|
||||
|
||||
import (
|
||||
"github.com/go-jet/jet/v2/internal/testutils"
|
||||
. "github.com/go-jet/jet/v2/sqlite"
|
||||
. "github.com/go-jet/jet/v2/tests/.gentestdata/sqlite/sakila/table"
|
||||
"github.com/stretchr/testify/require"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestWITH_And_SELECT(t *testing.T) {
|
||||
salesRep := CTE("sales_rep")
|
||||
salesRepStaffID := Staff.StaffID.From(salesRep)
|
||||
salesRepFullName := StringColumn("sales_rep_full_name").From(salesRep)
|
||||
customerSalesRep := CTE("customer_sales_rep")
|
||||
|
||||
stmt := WITH(
|
||||
salesRep.AS(
|
||||
SELECT(
|
||||
Staff.StaffID,
|
||||
Staff.FirstName.CONCAT(Staff.LastName).AS(salesRepFullName.Name()),
|
||||
).FROM(Staff),
|
||||
),
|
||||
customerSalesRep.AS(
|
||||
SELECT(
|
||||
Customer.FirstName.CONCAT(Customer.LastName).AS("customer_name"),
|
||||
salesRepFullName,
|
||||
).FROM(
|
||||
salesRep.
|
||||
INNER_JOIN(Store, Store.ManagerStaffID.EQ(salesRepStaffID)).
|
||||
INNER_JOIN(Customer, Customer.StoreID.EQ(Store.StoreID)),
|
||||
),
|
||||
),
|
||||
)(
|
||||
SELECT(customerSalesRep.AllColumns()).
|
||||
FROM(customerSalesRep),
|
||||
)
|
||||
|
||||
testutils.AssertStatementSql(t, stmt, strings.Replace(`
|
||||
WITH sales_rep AS (
|
||||
SELECT staff.staff_id AS "staff.staff_id",
|
||||
(staff.first_name || staff.last_name) AS "sales_rep_full_name"
|
||||
FROM staff
|
||||
),customer_sales_rep AS (
|
||||
SELECT (customer.first_name || customer.last_name) AS "customer_name",
|
||||
sales_rep.sales_rep_full_name AS "sales_rep_full_name"
|
||||
FROM sales_rep
|
||||
INNER JOIN store ON (store.manager_staff_id = sales_rep.''staff.staff_id'')
|
||||
INNER JOIN customer ON (customer.store_id = store.store_id)
|
||||
)
|
||||
SELECT customer_sales_rep.customer_name AS "customer_name",
|
||||
customer_sales_rep.sales_rep_full_name AS "sales_rep_full_name"
|
||||
FROM customer_sales_rep;
|
||||
`, "''", "`", -1))
|
||||
|
||||
var dest []struct {
|
||||
CustomerName string
|
||||
SalesRepFullName string
|
||||
}
|
||||
err := stmt.Query(db, &dest)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(dest), 599)
|
||||
}
|
||||
|
||||
func TestWITH_And_INSERT(t *testing.T) {
|
||||
paymentsToInsert := CTE("payments_to_insert")
|
||||
|
||||
stmt := WITH(
|
||||
paymentsToInsert.AS(
|
||||
SELECT(Payment.AllColumns).
|
||||
FROM(Payment).
|
||||
WHERE(Payment.Amount.LT(Float(0.5))),
|
||||
),
|
||||
)(
|
||||
Payment.INSERT(Payment.AllColumns).
|
||||
QUERY(
|
||||
SELECT(
|
||||
paymentsToInsert.AllColumns(),
|
||||
).FROM(
|
||||
paymentsToInsert,
|
||||
).WHERE(Bool(true)), //https://stackoverflow.com/questions/66230093/error-while-doing-upsert-in-sqlite-3-34-error-near-do-syntax-error
|
||||
).ON_CONFLICT().DO_UPDATE(
|
||||
SET(
|
||||
Payment.PaymentID.SET(Payment.PaymentID.ADD(Int(100000))),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
testutils.AssertDebugStatementSql(t, stmt, strings.Replace(`
|
||||
WITH payments_to_insert AS (
|
||||
SELECT payment.payment_id AS "payment.payment_id",
|
||||
payment.customer_id AS "payment.customer_id",
|
||||
payment.staff_id AS "payment.staff_id",
|
||||
payment.rental_id AS "payment.rental_id",
|
||||
payment.amount AS "payment.amount",
|
||||
payment.payment_date AS "payment.payment_date",
|
||||
payment.last_update AS "payment.last_update"
|
||||
FROM payment
|
||||
WHERE payment.amount < 0.5
|
||||
)
|
||||
INSERT INTO payment (payment_id, customer_id, staff_id, rental_id, amount, payment_date, last_update)
|
||||
SELECT payments_to_insert.''payment.payment_id'' AS "payment.payment_id",
|
||||
payments_to_insert.''payment.customer_id'' AS "payment.customer_id",
|
||||
payments_to_insert.''payment.staff_id'' AS "payment.staff_id",
|
||||
payments_to_insert.''payment.rental_id'' AS "payment.rental_id",
|
||||
payments_to_insert.''payment.amount'' AS "payment.amount",
|
||||
payments_to_insert.''payment.payment_date'' AS "payment.payment_date",
|
||||
payments_to_insert.''payment.last_update'' AS "payment.last_update"
|
||||
FROM payments_to_insert
|
||||
WHERE TRUE
|
||||
ON CONFLICT DO UPDATE
|
||||
SET payment_id = (payment.payment_id + 100000);
|
||||
`, "''", "`", -1))
|
||||
|
||||
tx := beginDBTx(t)
|
||||
defer tx.Rollback()
|
||||
|
||||
testutils.AssertExec(t, stmt, tx, 24)
|
||||
}
|
||||
|
||||
func TestWITH_SELECT_UPDATE(t *testing.T) {
|
||||
paymentsToUpdate := CTE("payments_to_update")
|
||||
paymentsToDeleteID := Payment.PaymentID.From(paymentsToUpdate)
|
||||
|
||||
stmt := WITH(
|
||||
paymentsToUpdate.AS(
|
||||
SELECT(Payment.AllColumns).
|
||||
FROM(Payment).
|
||||
WHERE(Payment.Amount.LT(Float(0.5))),
|
||||
),
|
||||
)(
|
||||
Payment.UPDATE().
|
||||
SET(Payment.Amount.SET(Float(0.0))).
|
||||
WHERE(Payment.PaymentID.IN(
|
||||
SELECT(paymentsToDeleteID).
|
||||
FROM(paymentsToUpdate),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
testutils.AssertDebugStatementSql(t, stmt, strings.Replace(`
|
||||
WITH payments_to_update AS (
|
||||
SELECT payment.payment_id AS "payment.payment_id",
|
||||
payment.customer_id AS "payment.customer_id",
|
||||
payment.staff_id AS "payment.staff_id",
|
||||
payment.rental_id AS "payment.rental_id",
|
||||
payment.amount AS "payment.amount",
|
||||
payment.payment_date AS "payment.payment_date",
|
||||
payment.last_update AS "payment.last_update"
|
||||
FROM payment
|
||||
WHERE payment.amount < 0.5
|
||||
)
|
||||
UPDATE payment
|
||||
SET amount = 0
|
||||
WHERE payment.payment_id IN (
|
||||
SELECT payments_to_update.''payment.payment_id'' AS "payment.payment_id"
|
||||
FROM payments_to_update
|
||||
);
|
||||
`, "''", "`", -1))
|
||||
|
||||
tx := beginDBTx(t)
|
||||
defer tx.Rollback()
|
||||
|
||||
testutils.AssertExec(t, stmt, tx)
|
||||
}
|
||||
|
||||
func TestWITH_And_DELETE(t *testing.T) {
|
||||
paymentsToDelete := CTE("payments_to_delete")
|
||||
paymentsToDeleteID := Payment.PaymentID.From(paymentsToDelete)
|
||||
|
||||
stmt := WITH(
|
||||
paymentsToDelete.AS(
|
||||
SELECT(
|
||||
Payment.AllColumns,
|
||||
).FROM(
|
||||
Payment,
|
||||
).WHERE(
|
||||
Payment.Amount.LT(Float(0.5)),
|
||||
),
|
||||
),
|
||||
)(
|
||||
Payment.DELETE().
|
||||
WHERE(
|
||||
Payment.PaymentID.IN(
|
||||
SELECT(
|
||||
paymentsToDeleteID,
|
||||
).FROM(
|
||||
paymentsToDelete,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
testutils.AssertDebugStatementSql(t, stmt, strings.Replace(`
|
||||
WITH payments_to_delete AS (
|
||||
SELECT payment.payment_id AS "payment.payment_id",
|
||||
payment.customer_id AS "payment.customer_id",
|
||||
payment.staff_id AS "payment.staff_id",
|
||||
payment.rental_id AS "payment.rental_id",
|
||||
payment.amount AS "payment.amount",
|
||||
payment.payment_date AS "payment.payment_date",
|
||||
payment.last_update AS "payment.last_update"
|
||||
FROM payment
|
||||
WHERE payment.amount < 0.5
|
||||
)
|
||||
DELETE FROM payment
|
||||
WHERE payment.payment_id IN (
|
||||
SELECT payments_to_delete.''payment.payment_id'' AS "payment.payment_id"
|
||||
FROM payments_to_delete
|
||||
);
|
||||
`, "''", "`", -1))
|
||||
|
||||
tx := beginDBTx(t)
|
||||
defer tx.Rollback()
|
||||
|
||||
testutils.AssertExec(t, stmt, tx, 24)
|
||||
}
|
||||
|
||||
func TestOperatorIN(t *testing.T) {
|
||||
stmt := SELECT(Payment.PaymentID.IN(SELECT(Int(11)), Int(22))).
|
||||
FROM(Payment)
|
||||
|
||||
testutils.AssertDebugStatementSql(t, stmt, `
|
||||
SELECT payment.payment_id IN ((
|
||||
SELECT 11
|
||||
), 22)
|
||||
FROM payment;
|
||||
`)
|
||||
|
||||
var dest []struct{}
|
||||
err := stmt.Query(db, &dest)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue