Tests folder structure reorganisation.

This commit is contained in:
go-jet 2019-07-30 11:45:10 +02:00
parent d0533f73fb
commit 6bf9c32c07
19 changed files with 22 additions and 24 deletions

View file

@ -0,0 +1,717 @@
package postgres
import (
. "github.com/go-jet/jet"
"github.com/go-jet/jet/internal/testutils"
"github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/model"
. "github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/table"
"github.com/google/uuid"
"gotest.tools/assert"
"testing"
)
func TestAllTypesSelect(t *testing.T) {
dest := []model.AllTypes{}
err := AllTypes.SELECT(AllTypes.AllColumns).Query(db, &dest)
assert.NilError(t, err)
assert.DeepEqual(t, dest[0], allTypesRow0)
assert.DeepEqual(t, dest[1], allTypesRow1)
}
func TestAllTypesInsertModel(t *testing.T) {
query := AllTypes.INSERT(AllTypes.AllColumns).
MODEL(allTypesRow0).
MODEL(&allTypesRow1).
RETURNING(AllTypes.AllColumns)
dest := []model.AllTypes{}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.Equal(t, len(dest), 2)
assert.DeepEqual(t, dest[0], allTypesRow0)
assert.DeepEqual(t, dest[1], allTypesRow1)
}
func TestAllTypesInsertQuery(t *testing.T) {
query := AllTypes.INSERT(AllTypes.AllColumns).
QUERY(
AllTypes.
SELECT(AllTypes.AllColumns).
LIMIT(2),
).
RETURNING(AllTypes.AllColumns)
dest := []model.AllTypes{}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.Equal(t, len(dest), 2)
assert.DeepEqual(t, dest[0], allTypesRow0)
assert.DeepEqual(t, dest[1], allTypesRow1)
}
func TestExpressionOperators(t *testing.T) {
query := AllTypes.SELECT(
AllTypes.Integer.IS_NULL(),
AllTypes.Timestamp.IS_NOT_NULL(),
AllTypes.SmallintPtr.IN(Int(11), Int(22), NULL),
AllTypes.SmallintPtr.IN(AllTypes.SELECT(AllTypes.IntegerPtr)),
AllTypes.SmallintPtr.NOT_IN(Int(11), Int(22), NULL),
AllTypes.SmallintPtr.NOT_IN(AllTypes.SELECT(AllTypes.IntegerPtr)),
CAST(String("TRUE")).AS_BOOL(),
CAST(String("111")).AS_SMALLINT(),
CAST(String("111")).AS_INTEGER(),
CAST(String("111")).AS_BIGINT(),
CAST(String("11.23")).AS_NUMERIC(30, 10),
CAST(String("11.23")).AS_NUMERIC(30),
CAST(String("11.23")).AS_REAL(),
CAST(String("11.23")).AS_DOUBLE(),
CAST(Int(234)).AS_TEXT(),
CAST(String("1/8/1999")).AS_DATE(),
CAST(String("04:05:06.789")).AS_TIME(),
CAST(String("04:05:06 PST")).AS_TIMEZ(),
CAST(String("1999-01-08 04:05:06")).AS_TIMESTAMP(),
CAST(String("January 8 04:05:06 1999 PST")).AS_TIMESTAMPZ(),
TO_CHAR(AllTypes.Timestamp, String("HH12:MI:SS")),
TO_CHAR(AllTypes.Integer, String("999")),
TO_CHAR(AllTypes.DoublePrecision, String("999D9")),
TO_CHAR(AllTypes.Numeric, String("999D99S")),
TO_DATE(String("05 Dec 2000"), String("DD Mon YYYY")),
TO_NUMBER(String("12,454"), String("99G999D9S")),
TO_TIMESTAMP(String("05 Dec 2000"), String("DD Mon YYYY")),
COALESCE(AllTypes.IntegerPtr, AllTypes.SmallintPtr, NULL, Int(11)),
NULLIF(AllTypes.Text, String("(none)")),
GREATEST(AllTypes.Numeric, AllTypes.NumericPtr),
LEAST(AllTypes.Numeric, AllTypes.NumericPtr),
RAW("current_database()"),
)
//fmt.Println(query.DebugSql())
err := query.Query(db, &struct{}{})
assert.NilError(t, err)
}
func TestStringOperators(t *testing.T) {
query := AllTypes.SELECT(
AllTypes.Text.EQ(AllTypes.Character),
AllTypes.Text.EQ(String("Text")),
AllTypes.Text.NOT_EQ(AllTypes.CharacterVaryingPtr),
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.Character),
AllTypes.Text.LT(String("Text")),
AllTypes.Text.LT_EQ(AllTypes.CharacterVaryingPtr),
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.SIMILAR_TO(String("%(b|d)%")),
AllTypes.Text.NOT_SIMILAR_TO(String("(b|c)%")),
BIT_LENGTH(AllTypes.Text),
CHAR_LENGTH(AllTypes.Character),
OCTET_LENGTH(AllTypes.Text),
LOWER(AllTypes.CharacterVaryingPtr),
UPPER(AllTypes.Character),
BTRIM(AllTypes.CharacterVarying),
BTRIM(AllTypes.CharacterVarying, String("AA")),
LTRIM(AllTypes.CharacterVarying),
LTRIM(AllTypes.CharacterVarying, String("A")),
RTRIM(AllTypes.CharacterVarying),
RTRIM(AllTypes.CharacterVarying, String("B")),
CHR(Int(65)),
//CONCAT(String("string1"), Int(1), Float(11.12)),
//CONCAT_WS(String("string1"), Int(1), Float(11.12)),
CONVERT(String("text_in_utf8"), String("UTF8"), String("LATIN1")),
CONVERT_FROM(String("text_in_utf8"), String("UTF8")),
CONVERT_TO(String("text_in_utf8"), String("UTF8")),
ENCODE(String("123\000\001"), String("base64")),
DECODE(String("MTIzAAE="), String("base64")),
//FORMAT(String("Hello %s, %1$s"), String("World")),
INITCAP(String("hi THOMAS")),
LEFT(String("abcde"), Int(2)),
RIGHT(String("abcde"), Int(2)),
LENGTH(String("jose")),
LENGTH(String("jose"), String("UTF8")),
LPAD(String("Hi"), Int(5)),
LPAD(String("Hi"), Int(5), String("xy")),
RPAD(String("Hi"), Int(5)),
RPAD(String("Hi"), Int(5), String("xy")),
MD5(AllTypes.CharacterVarying),
REPEAT(AllTypes.Text, Int(33)),
REPLACE(AllTypes.Character, String("BA"), String("AB")),
REVERSE(AllTypes.CharacterVarying),
STRPOS(AllTypes.Text, String("A")),
SUBSTR(AllTypes.CharacterPtr, Int(3)),
SUBSTR(AllTypes.CharacterPtr, Int(3), Int(2)),
TO_HEX(AllTypes.IntegerPtr),
)
//_, args, _ := query.Sql()
//fmt.Println(query.Sql())
//fmt.Println(args[15])
//fmt.Println(query.DebugSql())
err := query.Query(db, &struct{}{})
assert.NilError(t, err)
}
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_UNKNOWN().AS("is unknown"),
AllTypes.Boolean.IS_NOT_UNKNOWN().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"),
).LIMIT(2)
//fmt.Println(query.Sql())
testutils.AssertStatementSql(t, query, `
SELECT (all_types.boolean = all_types.boolean_ptr) AS "EQ1",
(all_types.boolean = $1) AS "EQ2",
(all_types.boolean != all_types.boolean_ptr) AS "NEq1",
(all_types.boolean != $2) AS "NEq2",
(all_types.boolean IS DISTINCT FROM all_types.boolean_ptr) AS "distinct1",
(all_types.boolean IS DISTINCT FROM $3) AS "distinct2",
(all_types.boolean IS NOT DISTINCT FROM all_types.boolean_ptr) AS "not_distinct_1",
(all_types.boolean IS NOT DISTINCT FROM $4) 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 UNKNOWN AS "is unknown",
all_types.boolean IS NOT UNKNOWN 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 test_sample.all_types
LIMIT $5;
`, true, false, true, true, int64(2))
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(db, &dest)
assert.NilError(t, err)
testutils.AssertJSONFile(t, "./testdata/common/bool_operators.json", dest)
}
func TestFloatOperators(t *testing.T) {
query := AllTypes.SELECT(
AllTypes.Numeric.EQ(AllTypes.Numeric),
AllTypes.Decimal.EQ(Float(12)),
AllTypes.Real.EQ(Float(12.12)),
AllTypes.Numeric.IS_DISTINCT_FROM(AllTypes.Numeric),
AllTypes.Decimal.IS_DISTINCT_FROM(Float(12)),
AllTypes.Real.IS_DISTINCT_FROM(Float(12.12)),
AllTypes.Numeric.IS_NOT_DISTINCT_FROM(AllTypes.Numeric),
AllTypes.Decimal.IS_NOT_DISTINCT_FROM(Float(12)),
AllTypes.Real.IS_NOT_DISTINCT_FROM(Float(12.12)),
//AllTypes.Numeric.LT(AllTypes.Integer),
AllTypes.Numeric.LT(Float(124)),
AllTypes.Numeric.LT(Float(34.56)),
//AllTypes.Numeric.GT(AllTypes.Smallint),
AllTypes.Numeric.GT(Float(124)),
AllTypes.Numeric.GT(Float(34.56)),
AllTypes.Real.ADD(AllTypes.RealPtr),
AllTypes.Real.ADD(Float(11.22)),
AllTypes.Real.SUB(AllTypes.RealPtr),
AllTypes.Real.SUB(Float(11.22)),
AllTypes.Real.MUL(AllTypes.RealPtr),
AllTypes.Real.MUL(Float(11.22)),
AllTypes.Real.DIV(AllTypes.RealPtr),
AllTypes.Real.DIV(Float(11.22)),
AllTypes.Decimal.MOD(AllTypes.Decimal),
AllTypes.Decimal.MOD(Float(11.22)),
AllTypes.Real.POW(AllTypes.RealPtr),
AllTypes.Real.POW(Float(11.22)),
ABSf(AllTypes.Real),
SQRT(AllTypes.Real),
CBRT(AllTypes.Real),
CEIL(AllTypes.Real),
FLOOR(AllTypes.Real),
ROUND(AllTypes.Decimal),
ROUND(AllTypes.Decimal, AllTypes.Integer).AS("round"),
SIGN(AllTypes.Real),
TRUNC(AllTypes.Decimal),
TRUNC(AllTypes.Decimal, Int(1)),
)
//fmt.Println(query.DebugSql())
err := query.Query(db, &struct{}{})
assert.NilError(t, err)
}
func TestIntegerOperators(t *testing.T) {
query := AllTypes.SELECT(
AllTypes.Integer.EQ(AllTypes.IntegerPtr),
AllTypes.Bigint.EQ(Int(12)),
//AllTypes.Smallint.NOT_EQ(AllTypes.Real),
AllTypes.Integer.NOT_EQ(AllTypes.IntegerPtr),
AllTypes.Bigint.NOT_EQ(Int(12)),
AllTypes.Integer.LT(AllTypes.IntegerPtr),
AllTypes.Bigint.LT(Int(65)),
//AllTypes.Smallint.LT_EQ(AllTypes.Numeric),
AllTypes.Integer.LT_EQ(AllTypes.IntegerPtr),
AllTypes.Bigint.LT_EQ(Int(65)),
//AllTypes.Smallint.GT_EQ(AllTypes.Numeric),
AllTypes.Integer.GT(AllTypes.IntegerPtr),
AllTypes.Bigint.GT(Int(65)),
AllTypes.Integer.GT_EQ(AllTypes.IntegerPtr),
AllTypes.Bigint.GT_EQ(Int(65)),
AllTypes.Integer.ADD(AllTypes.Integer),
AllTypes.Integer.ADD(Int(11)),
AllTypes.Integer.SUB(AllTypes.Integer),
AllTypes.Integer.SUB(Int(11)),
AllTypes.Integer.MUL(AllTypes.Integer),
AllTypes.Integer.MUL(Int(11)),
AllTypes.Integer.DIV(AllTypes.Integer),
AllTypes.Integer.DIV(Int(11)),
AllTypes.Integer.MOD(AllTypes.Integer),
AllTypes.Integer.MOD(Int(11)),
AllTypes.Integer.POW(AllTypes.Smallint),
AllTypes.Integer.POW(Int(11)),
AllTypes.Integer.BIT_AND(AllTypes.Smallint),
AllTypes.Integer.BIT_OR(AllTypes.Smallint),
AllTypes.Integer.BIT_XOR(Int(11)),
BIT_NOT(AllTypes.Integer),
AllTypes.Integer.BIT_SHIFT_LEFT(AllTypes.Smallint),
AllTypes.Integer.BIT_SHIFT_LEFT(Int(11)),
AllTypes.Integer.BIT_SHIFT_RIGHT(AllTypes.Smallint),
AllTypes.Integer.BIT_SHIFT_RIGHT(Int(11)),
ABSi(AllTypes.Integer),
SQRT(AllTypes.Integer),
CBRT(AllTypes.Integer),
)
//fmt.Println(query.DebugSql())
err := query.Query(db, &struct{}{})
assert.NilError(t, err)
}
func TestTimeOperators(t *testing.T) {
query := AllTypes.SELECT(
AllTypes.Time.EQ(AllTypes.Time),
AllTypes.Time.EQ(Time(23, 6, 6, 1)),
AllTypes.Timez.EQ(AllTypes.TimezPtr),
AllTypes.Timez.EQ(Timez(23, 6, 6, 222, +200)),
AllTypes.Timestamp.EQ(AllTypes.TimestampPtr),
AllTypes.Timestamp.EQ(Timestamp(2010, 10, 21, 15, 30, 12, 333)),
AllTypes.Timestampz.EQ(AllTypes.TimestampzPtr),
AllTypes.Timestampz.EQ(Timestampz(2010, 10, 21, 15, 30, 12, 444, 0)),
AllTypes.Date.EQ(AllTypes.DatePtr),
AllTypes.Date.EQ(Date(2010, 12, 3)),
AllTypes.Time.NOT_EQ(AllTypes.Time),
AllTypes.Time.NOT_EQ(Time(23, 6, 6, 10)),
AllTypes.Timez.NOT_EQ(AllTypes.TimezPtr),
AllTypes.Timez.NOT_EQ(Timez(23, 6, 6, 555, +200)),
AllTypes.Timestamp.NOT_EQ(AllTypes.TimestampPtr),
AllTypes.Timestamp.NOT_EQ(Timestamp(2010, 10, 21, 15, 30, 12, 666)),
AllTypes.Timestampz.NOT_EQ(AllTypes.TimestampzPtr),
AllTypes.Timestampz.NOT_EQ(Timestampz(2010, 10, 21, 15, 30, 12, 777, 0)),
AllTypes.Date.NOT_EQ(AllTypes.DatePtr),
AllTypes.Date.NOT_EQ(Date(2010, 12, 3)),
AllTypes.Time.IS_DISTINCT_FROM(AllTypes.Time),
AllTypes.Time.IS_DISTINCT_FROM(Time(23, 6, 6, 100)),
AllTypes.Time.IS_NOT_DISTINCT_FROM(AllTypes.Time),
AllTypes.Time.IS_NOT_DISTINCT_FROM(Time(23, 6, 6, 200)),
AllTypes.Time.LT(AllTypes.Time),
AllTypes.Time.LT(Time(23, 6, 6, 22)),
AllTypes.Time.LT_EQ(AllTypes.Time),
AllTypes.Time.LT_EQ(Time(23, 6, 6, 33)),
AllTypes.Time.GT(AllTypes.Time),
AllTypes.Time.GT(Time(23, 6, 6, 0)),
AllTypes.Time.GT_EQ(AllTypes.Time),
AllTypes.Time.GT_EQ(Time(23, 6, 6, 1)),
CURRENT_DATE(),
CURRENT_TIME(),
CURRENT_TIME(2),
CURRENT_TIMESTAMP(),
CURRENT_TIMESTAMP(1),
LOCALTIME(),
LOCALTIME(11),
LOCALTIMESTAMP(),
LOCALTIMESTAMP(4),
NOW(),
)
//fmt.Println(query.DebugSql())
err := query.Query(db, &struct{}{})
assert.NilError(t, err)
}
func TestSubQueryColumnReference(t *testing.T) {
type expected struct {
sql string
args []interface{}
}
subQueries := map[SelectTable]expected{}
selectSubQuery := AllTypes.SELECT(
AllTypes.Boolean,
AllTypes.Integer,
AllTypes.Real,
AllTypes.Text,
AllTypes.Time,
AllTypes.Timez,
AllTypes.Timestamp,
AllTypes.Timestampz,
AllTypes.Date,
AllTypes.Bytea.AS("aliasedColumn"),
).
LIMIT(2).
AsTable("subQuery")
var selectexpectedSQL = ` (
SELECT all_types.boolean AS "all_types.boolean",
all_types.integer AS "all_types.integer",
all_types.real AS "all_types.real",
all_types.text AS "all_types.text",
all_types.time AS "all_types.time",
all_types.timez AS "all_types.timez",
all_types.timestamp AS "all_types.timestamp",
all_types.timestampz AS "all_types.timestampz",
all_types.date AS "all_types.date",
all_types.bytea AS "aliasedColumn"
FROM test_sample.all_types
LIMIT 2
) AS "subQuery"`
unionSubQuery :=
UNION_ALL(
AllTypes.SELECT(
AllTypes.Boolean,
AllTypes.Integer,
AllTypes.Real,
AllTypes.Text,
AllTypes.Time,
AllTypes.Timez,
AllTypes.Timestamp,
AllTypes.Timestampz,
AllTypes.Date,
AllTypes.Bytea.AS("aliasedColumn"),
).
LIMIT(1),
AllTypes.SELECT(
AllTypes.Boolean,
AllTypes.Integer,
AllTypes.Real,
AllTypes.Text,
AllTypes.Time,
AllTypes.Timez,
AllTypes.Timestamp,
AllTypes.Timestampz,
AllTypes.Date,
AllTypes.Bytea.AS("aliasedColumn"),
).
LIMIT(1).OFFSET(1),
).
AsTable("subQuery")
unionexpectedSQL := `
(
(
SELECT all_types.boolean AS "all_types.boolean",
all_types.integer AS "all_types.integer",
all_types.real AS "all_types.real",
all_types.text AS "all_types.text",
all_types.time AS "all_types.time",
all_types.timez AS "all_types.timez",
all_types.timestamp AS "all_types.timestamp",
all_types.timestampz AS "all_types.timestampz",
all_types.date AS "all_types.date",
all_types.bytea AS "aliasedColumn"
FROM test_sample.all_types
LIMIT 1
)
UNION ALL
(
SELECT all_types.boolean AS "all_types.boolean",
all_types.integer AS "all_types.integer",
all_types.real AS "all_types.real",
all_types.text AS "all_types.text",
all_types.time AS "all_types.time",
all_types.timez AS "all_types.timez",
all_types.timestamp AS "all_types.timestamp",
all_types.timestampz AS "all_types.timestampz",
all_types.date AS "all_types.date",
all_types.bytea AS "aliasedColumn"
FROM test_sample.all_types
LIMIT 1
OFFSET 1
)
) AS "subQuery"`
subQueries[unionSubQuery] = expected{sql: unionexpectedSQL, args: []interface{}{int64(1), int64(1), int64(1)}}
subQueries[selectSubQuery] = expected{sql: selectexpectedSQL, args: []interface{}{int64(2)}}
for subQuery, expected := range subQueries {
boolColumn := AllTypes.Boolean.From(subQuery)
intColumn := AllTypes.Integer.From(subQuery)
floatColumn := AllTypes.Real.From(subQuery)
stringColumn := AllTypes.Text.From(subQuery)
timeColumn := AllTypes.Time.From(subQuery)
timezColumn := AllTypes.Timez.From(subQuery)
timestampColumn := AllTypes.Timestamp.From(subQuery)
timestampzColumn := AllTypes.Timestampz.From(subQuery)
dateColumn := AllTypes.Date.From(subQuery)
aliasedColumn := StringColumn("aliasedColumn").From(subQuery)
stmt1 := SELECT(
boolColumn,
intColumn,
floatColumn,
stringColumn,
timeColumn,
timezColumn,
timestampColumn,
timestampzColumn,
dateColumn,
aliasedColumn,
).
FROM(subQuery)
var expectedSQL = `
SELECT "subQuery"."all_types.boolean" AS "all_types.boolean",
"subQuery"."all_types.integer" AS "all_types.integer",
"subQuery"."all_types.real" AS "all_types.real",
"subQuery"."all_types.text" AS "all_types.text",
"subQuery"."all_types.time" AS "all_types.time",
"subQuery"."all_types.timez" AS "all_types.timez",
"subQuery"."all_types.timestamp" AS "all_types.timestamp",
"subQuery"."all_types.timestampz" AS "all_types.timestampz",
"subQuery"."all_types.date" AS "all_types.date",
"subQuery"."aliasedColumn" AS "aliasedColumn"
FROM`
testutils.AssertDebugStatementSql(t, stmt1, expectedSQL+expected.sql+";\n", expected.args...)
dest1 := []model.AllTypes{}
err := stmt1.Query(db, &dest1)
assert.NilError(t, err)
assert.Equal(t, len(dest1), 2)
assert.Equal(t, dest1[0].Boolean, allTypesRow0.Boolean)
assert.Equal(t, dest1[0].Integer, allTypesRow0.Integer)
assert.Equal(t, dest1[0].Real, allTypesRow0.Real)
assert.Equal(t, dest1[0].Text, allTypesRow0.Text)
assert.DeepEqual(t, dest1[0].Time, allTypesRow0.Time)
assert.DeepEqual(t, dest1[0].Timez, allTypesRow0.Timez)
assert.DeepEqual(t, dest1[0].Timestamp, allTypesRow0.Timestamp)
assert.DeepEqual(t, dest1[0].Timestampz, allTypesRow0.Timestampz)
assert.DeepEqual(t, dest1[0].Date, allTypesRow0.Date)
stmt2 := SELECT(
subQuery.AllColumns(),
).
FROM(subQuery)
//fmt.Println(stmt2.DebugSql())
testutils.AssertDebugStatementSql(t, stmt2, expectedSQL+expected.sql+";\n", expected.args...)
dest2 := []model.AllTypes{}
err = stmt2.Query(db, &dest2)
assert.NilError(t, err)
assert.DeepEqual(t, dest1, dest2)
}
}
var allTypesRow0 = model.AllTypes{
SmallintPtr: Int16Ptr(1),
Smallint: 1,
IntegerPtr: Int32Ptr(300),
Integer: 300,
BigintPtr: Int64Ptr(50000),
Bigint: 5000,
DecimalPtr: Float64Ptr(11.44),
Decimal: 11.44,
NumericPtr: Float64Ptr(55.77),
Numeric: 55.77,
RealPtr: Float32Ptr(99.1),
Real: 99.1,
DoublePrecisionPtr: Float64Ptr(11111111.22),
DoublePrecision: 11111111.22,
Smallserial: 1,
Serial: 1,
Bigserial: 1,
//MoneyPtr: nil,
//Money:
CharacterVaryingPtr: StringPtr("ABBA"),
CharacterVarying: "ABBA",
CharacterPtr: StringPtr("JOHN "),
Character: "JOHN ",
TextPtr: StringPtr("Some text"),
Text: "Some text",
ByteaPtr: ByteArrayPtr([]byte("bytea")),
Bytea: []byte("bytea"),
TimestampzPtr: TimestampWithTimeZone("1999-01-08 13:05:06 +0100 CET", 0),
Timestampz: *TimestampWithTimeZone("1999-01-08 13:05:06 +0100 CET", 0),
TimestampPtr: testutils.TimestampWithoutTimeZone("1999-01-08 04:05:06", 0),
Timestamp: *testutils.TimestampWithoutTimeZone("1999-01-08 04:05:06", 0),
DatePtr: testutils.TimestampWithoutTimeZone("1999-01-08 00:00:00", 0),
Date: *testutils.TimestampWithoutTimeZone("1999-01-08 00:00:00", 0),
TimezPtr: TimeWithTimeZone("04:05:06 -0800"),
Timez: *TimeWithTimeZone("04:05:06 -0800"),
TimePtr: TimeWithoutTimeZone("04:05:06"),
Time: *TimeWithoutTimeZone("04:05:06"),
IntervalPtr: StringPtr("3 days 04:05:06"),
Interval: "3 days 04:05:06",
BooleanPtr: BoolPtr(true),
Boolean: false,
PointPtr: StringPtr("(2,3)"),
BitPtr: StringPtr("101"),
Bit: "101",
BitVaryingPtr: StringPtr("101111"),
BitVarying: "101111",
TsvectorPtr: StringPtr("'supernova':1"),
Tsvector: "'supernova':1",
UUIDPtr: UUIDPtr("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"),
UUID: uuid.MustParse("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"),
XMLPtr: StringPtr("<Sub>abc</Sub>"),
XML: "<Sub>abc</Sub>",
JSONPtr: StringPtr(`{"a": 1, "b": 3}`),
JSON: `{"a": 1, "b": 3}`,
JsonbPtr: StringPtr(`{"a": 1, "b": 3}`),
Jsonb: `{"a": 1, "b": 3}`,
IntegerArrayPtr: StringPtr("{1,2,3}"),
IntegerArray: "{1,2,3}",
TextArrayPtr: StringPtr("{breakfast,consulting}"),
TextArray: "{breakfast,consulting}",
JsonbArray: `{"{\"a\": 1, \"b\": 2}","{\"a\": 3, \"b\": 4}"}`,
TextMultiDimArrayPtr: StringPtr("{{meeting,lunch},{training,presentation}}"),
TextMultiDimArray: "{{meeting,lunch},{training,presentation}}",
}
var allTypesRow1 = model.AllTypes{
SmallintPtr: nil,
Smallint: 1,
IntegerPtr: nil,
Integer: 300,
BigintPtr: nil,
Bigint: 5000,
DecimalPtr: nil,
Decimal: 11.44,
NumericPtr: nil,
Numeric: 55.77,
RealPtr: nil,
Real: 99.1,
DoublePrecisionPtr: nil,
DoublePrecision: 11111111.22,
Smallserial: 2,
Serial: 2,
Bigserial: 2,
//MoneyPtr: nil,
//Money:
CharacterVaryingPtr: nil,
CharacterVarying: "ABBA",
CharacterPtr: nil,
Character: "JOHN ",
TextPtr: nil,
Text: "Some text",
ByteaPtr: nil,
Bytea: []byte("bytea"),
TimestampzPtr: nil,
Timestampz: *TimestampWithTimeZone("1999-01-08 13:05:06 +0100 CET", 0),
TimestampPtr: nil,
Timestamp: *testutils.TimestampWithoutTimeZone("1999-01-08 04:05:06", 0),
DatePtr: nil,
Date: *testutils.TimestampWithoutTimeZone("1999-01-08 00:00:00", 0),
TimezPtr: nil,
Timez: *TimeWithTimeZone("04:05:06 -0800"),
TimePtr: nil,
Time: *TimeWithoutTimeZone("04:05:06"),
IntervalPtr: nil,
Interval: "3 days 04:05:06",
BooleanPtr: nil,
Boolean: false,
PointPtr: nil,
BitPtr: nil,
Bit: "101",
BitVaryingPtr: nil,
BitVarying: "101111",
TsvectorPtr: nil,
Tsvector: "'supernova':1",
UUIDPtr: nil,
UUID: uuid.MustParse("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"),
XMLPtr: nil,
XML: "<Sub>abc</Sub>",
JSONPtr: nil,
JSON: `{"a": 1, "b": 3}`,
JsonbPtr: nil,
Jsonb: `{"a": 1, "b": 3}`,
IntegerArrayPtr: nil,
IntegerArray: "{1,2,3}",
TextArrayPtr: nil,
TextArray: "{breakfast,consulting}",
JsonbArray: `{"{\"a\": 1, \"b\": 2}","{\"a\": 3, \"b\": 4}"}`,
TextMultiDimArrayPtr: nil,
TextMultiDimArray: "{{meeting,lunch},{training,presentation}}",
}

View file

@ -0,0 +1,350 @@
package postgres
import (
"context"
. "github.com/go-jet/jet"
"github.com/go-jet/jet/internal/testutils"
"github.com/go-jet/jet/tests/.gentestdata/jetdb/chinook/model"
. "github.com/go-jet/jet/tests/.gentestdata/jetdb/chinook/table"
"gotest.tools/assert"
"testing"
"time"
)
func TestSelect(t *testing.T) {
stmt := Album.
SELECT(Album.AllColumns).
ORDER_BY(Album.AlbumId.ASC())
testutils.AssertDebugStatementSql(t, stmt, `
SELECT "Album"."AlbumId" AS "Album.AlbumId",
"Album"."Title" AS "Album.Title",
"Album"."ArtistId" AS "Album.ArtistId"
FROM chinook."Album"
ORDER BY "Album"."AlbumId" ASC;
`)
dest := []model.Album{}
err := stmt.Query(db, &dest)
assert.NilError(t, err)
assert.Equal(t, len(dest), 347)
assert.DeepEqual(t, dest[0], album1)
assert.DeepEqual(t, dest[1], album2)
assert.DeepEqual(t, dest[len(dest)-1], album347)
}
func TestJoinEverything(t *testing.T) {
manager := Employee.AS("Manager")
stmt := Artist.
LEFT_JOIN(Album, Artist.ArtistId.EQ(Album.ArtistId)).
LEFT_JOIN(Track, Track.AlbumId.EQ(Album.AlbumId)).
LEFT_JOIN(Genre, Genre.GenreId.EQ(Track.GenreId)).
LEFT_JOIN(MediaType, MediaType.MediaTypeId.EQ(Track.MediaTypeId)).
LEFT_JOIN(PlaylistTrack, PlaylistTrack.TrackId.EQ(Track.TrackId)).
LEFT_JOIN(Playlist, Playlist.PlaylistId.EQ(PlaylistTrack.PlaylistId)).
LEFT_JOIN(InvoiceLine, InvoiceLine.TrackId.EQ(Track.TrackId)).
LEFT_JOIN(Invoice, Invoice.InvoiceId.EQ(InvoiceLine.InvoiceId)).
LEFT_JOIN(Customer, Customer.CustomerId.EQ(Invoice.CustomerId)).
LEFT_JOIN(Employee, Employee.EmployeeId.EQ(Customer.SupportRepId)).
LEFT_JOIN(manager, manager.EmployeeId.EQ(Employee.ReportsTo)).
SELECT(
Artist.AllColumns,
Album.AllColumns,
Track.AllColumns,
Genre.AllColumns,
MediaType.AllColumns,
PlaylistTrack.AllColumns,
Playlist.AllColumns,
Invoice.AllColumns,
Customer.AllColumns,
Employee.AllColumns,
manager.AllColumns,
).
ORDER_BY(Artist.ArtistId, Album.AlbumId, Track.TrackId,
Genre.GenreId, MediaType.MediaTypeId, Playlist.PlaylistId,
Invoice.InvoiceId, Customer.CustomerId)
var dest []struct { //list of all artist
model.Artist
Albums []struct { // list of albums per artist
model.Album
Tracks []struct { // list of tracks per album
model.Track
Genre model.Genre // track genre
MediaType model.MediaType // track media type
Playlists []model.Playlist // list of playlist where track is used
Invoices []struct { // list of invoices where track occurs
model.Invoice
Customer struct { // customer data for invoice
model.Customer
Employee *struct { // employee data for customer if exists
model.Employee
Manager *model.Employee `alias:"Manager"`
}
}
}
}
}
}
err := stmt.Query(db, &dest)
assert.NilError(t, err)
assert.Equal(t, len(dest), 275)
testutils.AssertJSONFile(t, "./postgres/testdata/joined_everything.json", dest)
}
func TestSelfJoin(t *testing.T) {
var dest []struct {
model.Employee
Manager *model.Employee `alias:"Manager.*"`
}
manager := Employee.AS("Manager")
stmt := Employee.
LEFT_JOIN(manager, Employee.ReportsTo.EQ(manager.EmployeeId)).
SELECT(
Employee.EmployeeId,
Employee.FirstName,
Employee.LastName,
manager.EmployeeId,
manager.FirstName,
manager.LastName,
).
ORDER_BY(Employee.EmployeeId)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT "Employee"."EmployeeId" AS "Employee.EmployeeId",
"Employee"."FirstName" AS "Employee.FirstName",
"Employee"."LastName" AS "Employee.LastName",
"Manager"."EmployeeId" AS "Manager.EmployeeId",
"Manager"."FirstName" AS "Manager.FirstName",
"Manager"."LastName" AS "Manager.LastName"
FROM chinook."Employee"
LEFT JOIN chinook."Employee" AS "Manager" ON ("Employee"."ReportsTo" = "Manager"."EmployeeId")
ORDER BY "Employee"."EmployeeId";
`)
err := stmt.Query(db, &dest)
assert.NilError(t, err)
assert.Equal(t, len(dest), 8)
testutils.AssertJSON(t, dest[0:2], `
[
{
"EmployeeId": 1,
"LastName": "Adams",
"FirstName": "Andrew",
"Title": null,
"ReportsTo": null,
"BirthDate": null,
"HireDate": null,
"Address": null,
"City": null,
"State": null,
"Country": null,
"PostalCode": null,
"Phone": null,
"Fax": null,
"Email": null,
"Manager": null
},
{
"EmployeeId": 2,
"LastName": "Edwards",
"FirstName": "Nancy",
"Title": null,
"ReportsTo": null,
"BirthDate": null,
"HireDate": null,
"Address": null,
"City": null,
"State": null,
"Country": null,
"PostalCode": null,
"Phone": null,
"Fax": null,
"Email": null,
"Manager": {
"EmployeeId": 1,
"LastName": "Adams",
"FirstName": "Andrew",
"Title": null,
"ReportsTo": null,
"BirthDate": null,
"HireDate": null,
"Address": null,
"City": null,
"State": null,
"Country": null,
"PostalCode": null,
"Phone": null,
"Fax": null,
"Email": null
}
}
]
`)
}
func TestUnionForQuotedNames(t *testing.T) {
stmt := UNION_ALL(
Album.SELECT(Album.AllColumns).WHERE(Album.AlbumId.EQ(Int(1))),
Album.SELECT(Album.AllColumns).WHERE(Album.AlbumId.EQ(Int(2))),
).
ORDER_BY(Album.AlbumId)
//fmt.Println(stmt.DebugSql())
testutils.AssertDebugStatementSql(t, stmt, `
(
(
SELECT "Album"."AlbumId" AS "Album.AlbumId",
"Album"."Title" AS "Album.Title",
"Album"."ArtistId" AS "Album.ArtistId"
FROM chinook."Album"
WHERE "Album"."AlbumId" = 1
)
UNION ALL
(
SELECT "Album"."AlbumId" AS "Album.AlbumId",
"Album"."Title" AS "Album.Title",
"Album"."ArtistId" AS "Album.ArtistId"
FROM chinook."Album"
WHERE "Album"."AlbumId" = 2
)
)
ORDER BY "Album.AlbumId";
`, int64(1), int64(2))
dest := []model.Album{}
err := stmt.Query(db, &dest)
assert.NilError(t, err)
assert.Equal(t, len(dest), 2)
assert.DeepEqual(t, dest[0], album1)
assert.DeepEqual(t, dest[1], album2)
}
func TestQueryWithContext(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
dest := []model.Album{}
err := Album.
CROSS_JOIN(Track).
CROSS_JOIN(InvoiceLine).
SELECT(Album.AllColumns, Track.AllColumns, InvoiceLine.AllColumns).
QueryContext(ctx, db, &dest)
assert.Error(t, err, "context deadline exceeded")
}
func TestExecWithContext(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
_, err := Album.
CROSS_JOIN(Track).
CROSS_JOIN(InvoiceLine).
SELECT(Album.AllColumns, Track.AllColumns, InvoiceLine.AllColumns).
ExecContext(ctx, db)
assert.Error(t, err, "pq: canceling statement due to user request")
}
func TestSubQueriesForQuotedNames(t *testing.T) {
first10Artist := Artist.
SELECT(Artist.AllColumns).
ORDER_BY(Artist.ArtistId).
LIMIT(10).
AsTable("first10Artist")
artistID := Artist.ArtistId.From(first10Artist)
first10Albums := Album.
SELECT(Album.AllColumns).
ORDER_BY(Album.AlbumId).
LIMIT(10).
AsTable("first10Albums")
albumArtistID := Album.ArtistId.From(first10Albums)
stmt := first10Artist.
INNER_JOIN(first10Albums, artistID.EQ(albumArtistID)).
SELECT(first10Artist.AllColumns(), first10Albums.AllColumns()).
ORDER_BY(artistID)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT "first10Artist"."Artist.ArtistId" AS "Artist.ArtistId",
"first10Artist"."Artist.Name" AS "Artist.Name",
"first10Albums"."Album.AlbumId" AS "Album.AlbumId",
"first10Albums"."Album.Title" AS "Album.Title",
"first10Albums"."Album.ArtistId" AS "Album.ArtistId"
FROM (
SELECT "Artist"."ArtistId" AS "Artist.ArtistId",
"Artist"."Name" AS "Artist.Name"
FROM chinook."Artist"
ORDER BY "Artist"."ArtistId"
LIMIT 10
) AS "first10Artist"
INNER JOIN (
SELECT "Album"."AlbumId" AS "Album.AlbumId",
"Album"."Title" AS "Album.Title",
"Album"."ArtistId" AS "Album.ArtistId"
FROM chinook."Album"
ORDER BY "Album"."AlbumId"
LIMIT 10
) AS "first10Albums" ON ("first10Artist"."Artist.ArtistId" = "first10Albums"."Album.ArtistId")
ORDER BY "first10Artist"."Artist.ArtistId";
`, int64(10), int64(10))
var dest []struct {
model.Artist
Album []model.Album
}
err := stmt.Query(db, &dest)
assert.NilError(t, err)
//spew.Dump(dest)
}
var album1 = model.Album{
AlbumId: 1,
Title: "For Those About To Rock We Salute You",
ArtistId: 1,
}
var album2 = model.Album{
AlbumId: 2,
Title: "Balls to the Wall",
ArtistId: 2,
}
var album347 = model.Album{
AlbumId: 347,
Title: "Koyaanisqatsi (Soundtrack from the Motion Picture)",
ArtistId: 275,
}

View file

@ -0,0 +1,100 @@
package postgres
import (
"context"
. "github.com/go-jet/jet"
"github.com/go-jet/jet/internal/testutils"
"github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/model"
. "github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/table"
"gotest.tools/assert"
"testing"
"time"
)
func TestDeleteWithWhere(t *testing.T) {
initForDeleteTest(t)
var expectedSQL = `
DELETE FROM test_sample.link
WHERE link.name IN ('Gmail', 'Outlook');
`
deleteStmt := Link.
DELETE().
WHERE(Link.Name.IN(String("Gmail"), String("Outlook")))
testutils.AssertDebugStatementSql(t, deleteStmt, expectedSQL, "Gmail", "Outlook")
assertExec(t, deleteStmt, 2)
}
func TestDeleteWithWhereAndReturning(t *testing.T) {
initForDeleteTest(t)
var expectedSQL = `
DELETE FROM test_sample.link
WHERE link.name IN ('Gmail', 'Outlook')
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("Gmail"), String("Outlook"))).
RETURNING(Link.AllColumns)
testutils.AssertDebugStatementSql(t, deleteStmt, expectedSQL, "Gmail", "Outlook")
dest := []model.Link{}
err := deleteStmt.Query(db, &dest)
assert.NilError(t, err)
assert.Equal(t, len(dest), 2)
assert.DeepEqual(t, dest[0].Name, "Gmail")
assert.DeepEqual(t, dest[1].Name, "Outlook")
}
func initForDeleteTest(t *testing.T) {
cleanUpLinkTable(t)
stmt := Link.INSERT(Link.URL, Link.Name, Link.Description).
VALUES("www.gmail.com", "Gmail", "Email service developed by Google").
VALUES("www.outlook.live.com", "Outlook", "Email service developed by Microsoft")
assertExec(t, stmt, 2)
}
func TestDeleteQueryContext(t *testing.T) {
initForDeleteTest(t)
deleteStmt := Link.
DELETE().
WHERE(Link.Name.IN(String("Gmail"), String("Outlook")))
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Microsecond)
defer cancel()
time.Sleep(10 * time.Millisecond)
dest := []model.Link{}
err := deleteStmt.QueryContext(ctx, db, &dest)
assert.Error(t, err, "context deadline exceeded")
}
func TestDeleteExecContext(t *testing.T) {
initForDeleteTest(t)
deleteStmt := Link.
DELETE().
WHERE(Link.Name.IN(String("Gmail"), String("Outlook")))
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Microsecond)
defer cancel()
time.Sleep(10 * time.Millisecond)
_, err := deleteStmt.ExecContext(ctx, db)
assert.Error(t, err, "context deadline exceeded")
}

View file

@ -0,0 +1,284 @@
package postgres
import (
"context"
. "github.com/go-jet/jet"
"github.com/go-jet/jet/internal/testutils"
"github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/model"
. "github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/table"
"gotest.tools/assert"
"testing"
"time"
)
func TestInsertValues(t *testing.T) {
cleanUpLinkTable(t)
var expectedSQL = `
INSERT INTO test_sample.link (id, url, name, description) VALUES
(100, 'http://www.postgresqltutorial.com', 'PostgreSQL Tutorial', DEFAULT),
(101, 'http://www.google.com', 'Google', DEFAULT),
(102, 'http://www.yahoo.com', 'Yahoo', NULL)
RETURNING link.id AS "link.id",
link.url AS "link.url",
link.name AS "link.name",
link.description AS "link.description";
`
insertQuery := Link.INSERT(Link.ID, Link.URL, Link.Name, Link.Description).
VALUES(100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial", DEFAULT).
VALUES(101, "http://www.google.com", "Google", DEFAULT).
VALUES(102, "http://www.yahoo.com", "Yahoo", nil).
RETURNING(Link.AllColumns)
testutils.AssertDebugStatementSql(t, insertQuery, expectedSQL,
100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial",
101, "http://www.google.com", "Google",
102, "http://www.yahoo.com", "Yahoo", nil)
insertedLinks := []model.Link{}
err := insertQuery.Query(db, &insertedLinks)
assert.NilError(t, err)
assert.Equal(t, len(insertedLinks), 3)
assert.DeepEqual(t, insertedLinks[0], model.Link{
ID: 100,
URL: "http://www.postgresqltutorial.com",
Name: "PostgreSQL Tutorial",
})
assert.DeepEqual(t, insertedLinks[1], model.Link{
ID: 101,
URL: "http://www.google.com",
Name: "Google",
})
assert.DeepEqual(t, insertedLinks[2], model.Link{
ID: 102,
URL: "http://www.yahoo.com",
Name: "Yahoo",
})
allLinks := []model.Link{}
err = Link.SELECT(Link.AllColumns).
WHERE(Link.ID.GT_EQ(Int(100))).
ORDER_BY(Link.ID).
Query(db, &allLinks)
assert.NilError(t, err)
assert.DeepEqual(t, insertedLinks, allLinks)
}
func TestInsertEmptyColumnList(t *testing.T) {
cleanUpLinkTable(t)
expectedSQL := `
INSERT INTO test_sample.link VALUES
(100, 'http://www.postgresqltutorial.com', 'PostgreSQL Tutorial', DEFAULT);
`
stmt := Link.INSERT().
VALUES(100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial", DEFAULT)
testutils.AssertDebugStatementSql(t, stmt, expectedSQL,
100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial")
assertExec(t, stmt, 1)
}
func TestInsertModelObject(t *testing.T) {
cleanUpLinkTable(t)
var expectedSQL = `
INSERT INTO test_sample.link (url, name) VALUES
('http://www.duckduckgo.com', 'Duck Duck go');
`
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, expectedSQL, "http://www.duckduckgo.com", "Duck Duck go")
assertExec(t, query, 1)
}
func TestInsertModelObjectEmptyColumnList(t *testing.T) {
cleanUpLinkTable(t)
var expectedSQL = `
INSERT INTO test_sample.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)
assertExec(t, query, 1)
}
func TestInsertModelsObject(t *testing.T) {
expectedSQL := `
INSERT INTO test_sample.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",
}
stmt := Link.
INSERT(Link.URL, Link.Name).
MODELS([]model.Link{tutorial, google, yahoo})
testutils.AssertDebugStatementSql(t, stmt, expectedSQL,
"http://www.postgresqltutorial.com", "PostgreSQL Tutorial",
"http://www.google.com", "Google",
"http://www.yahoo.com", "Yahoo")
assertExec(t, stmt, 3)
}
func TestInsertUsingMutableColumns(t *testing.T) {
var expectedSQL = `
INSERT INTO test_sample.link (url, name, description) VALUES
('http://www.postgresqltutorial.com', 'PostgreSQL Tutorial', DEFAULT),
('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", DEFAULT).
MODEL(google).
MODELS([]model.Link{google, yahoo})
testutils.AssertDebugStatementSql(t, stmt, expectedSQL,
"http://www.postgresqltutorial.com", "PostgreSQL Tutorial",
"http://www.google.com", "Google", nil,
"http://www.google.com", "Google", nil,
"http://www.yahoo.com", "Yahoo", nil)
assertExec(t, stmt, 4)
}
func TestInsertQuery(t *testing.T) {
_, err := Link.DELETE().
WHERE(Link.ID.NOT_EQ(Int(0)).AND(Link.Name.EQ(String("Youtube")))).
Exec(db)
assert.NilError(t, err)
var expectedSQL = `
INSERT INTO test_sample.link (url, name) (
SELECT link.url AS "link.url",
link.name AS "link.name"
FROM test_sample.link
WHERE link.id = 0
)
RETURNING link.id AS "link.id",
link.url AS "link.url",
link.name AS "link.name",
link.description AS "link.description";
`
query := Link.
INSERT(Link.URL, Link.Name).
QUERY(
SELECT(Link.URL, Link.Name).
FROM(Link).
WHERE(Link.ID.EQ(Int(0))),
).
RETURNING(Link.AllColumns)
testutils.AssertDebugStatementSql(t, query, expectedSQL, int64(0))
dest := []model.Link{}
err = query.Query(db, &dest)
assert.NilError(t, err)
youtubeLinks := []model.Link{}
err = Link.
SELECT(Link.AllColumns).
WHERE(Link.Name.EQ(String("Youtube"))).
Query(db, &youtubeLinks)
assert.NilError(t, err)
assert.Equal(t, len(youtubeLinks), 2)
}
func TestInsertWithQueryContext(t *testing.T) {
cleanUpLinkTable(t)
stmt := Link.INSERT().
VALUES(1100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial", DEFAULT).
RETURNING(Link.AllColumns)
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Microsecond)
defer cancel()
time.Sleep(10 * time.Millisecond)
dest := []model.Link{}
err := stmt.QueryContext(ctx, db, &dest)
assert.Error(t, err, "context deadline exceeded")
}
func TestInsertWithExecContext(t *testing.T) {
cleanUpLinkTable(t)
stmt := Link.INSERT().
VALUES(100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial", DEFAULT)
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Microsecond)
defer cancel()
time.Sleep(10 * time.Millisecond)
_, err := stmt.ExecContext(ctx, db)
assert.Error(t, err, "context deadline exceeded")
}

View file

@ -0,0 +1,74 @@
package postgres
import (
"context"
"github.com/go-jet/jet/internal/testutils"
"gotest.tools/assert"
"testing"
"time"
. "github.com/go-jet/jet"
. "github.com/go-jet/jet/tests/.gentestdata/jetdb/dvds/table"
)
func TestLockTable(t *testing.T) {
expectedSQL := `
LOCK TABLE dvds.address IN`
var testData = []TableLockMode{
LOCK_ACCESS_SHARE,
LOCK_ROW_SHARE,
LOCK_ROW_EXCLUSIVE,
LOCK_SHARE_UPDATE_EXCLUSIVE,
LOCK_SHARE,
LOCK_SHARE_ROW_EXCLUSIVE,
LOCK_EXCLUSIVE,
LOCK_ACCESS_EXCLUSIVE,
}
for _, lockMode := range testData {
query := Address.LOCK().IN(lockMode)
testutils.AssertDebugStatementSql(t, query, expectedSQL+" "+string(lockMode)+" MODE;\n")
tx, _ := db.Begin()
_, err := query.Exec(tx)
assert.NilError(t, err)
err = tx.Rollback()
assert.NilError(t, err)
}
for _, lockMode := range testData {
query := Address.LOCK().IN(lockMode).NOWAIT()
testutils.AssertDebugStatementSql(t, query, expectedSQL+" "+string(lockMode)+" MODE NOWAIT;\n")
tx, _ := db.Begin()
_, err := query.Exec(tx)
assert.NilError(t, err)
err = tx.Rollback()
assert.NilError(t, err)
}
}
func TestLockExecContext(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Microsecond)
defer cancel()
time.Sleep(10 * time.Millisecond)
tx, _ := db.Begin()
defer tx.Rollback()
_, err := Address.LOCK().IN(LOCK_ACCESS_SHARE).ExecContext(ctx, tx)
assert.Error(t, err, "context deadline exceeded")
}

251
tests/postgres/main_test.go Normal file
View file

@ -0,0 +1,251 @@
package postgres
import (
"bytes"
"database/sql"
"github.com/go-jet/jet/generator/postgres"
"github.com/go-jet/jet/tests/.gentestdata/jetdb/dvds/model"
"github.com/go-jet/jet/tests/dbconfig"
_ "github.com/lib/pq"
"github.com/pkg/profile"
"gotest.tools/assert"
"io/ioutil"
"os"
"os/exec"
"reflect"
"testing"
)
var db *sql.DB
func TestMain(m *testing.M) {
defer profile.Start().Stop()
var err error
db, err = sql.Open("postgres", dbconfig.PostgresConnectString)
if err != nil {
panic("Failed to connect to test db")
}
defer db.Close()
ret := m.Run()
os.Exit(ret)
}
func TestGeneratedModel(t *testing.T) {
actor := model.Actor{}
assert.Equal(t, reflect.TypeOf(actor.ActorID).String(), "int32")
actorIDField, ok := reflect.TypeOf(actor).FieldByName("ActorID")
assert.Assert(t, ok)
assert.Equal(t, actorIDField.Tag.Get("sql"), "primary_key")
assert.Equal(t, reflect.TypeOf(actor.FirstName).String(), "string")
assert.Equal(t, reflect.TypeOf(actor.LastName).String(), "string")
assert.Equal(t, reflect.TypeOf(actor.LastUpdate).String(), "time.Time")
filmActor := model.FilmActor{}
assert.Equal(t, reflect.TypeOf(filmActor.FilmID).String(), "int16")
filmIDField, ok := reflect.TypeOf(filmActor).FieldByName("FilmID")
assert.Assert(t, ok)
assert.Equal(t, filmIDField.Tag.Get("sql"), "primary_key")
assert.Equal(t, reflect.TypeOf(filmActor.ActorID).String(), "int16")
actorIDField, ok = reflect.TypeOf(filmActor).FieldByName("ActorID")
assert.Assert(t, ok)
assert.Equal(t, filmIDField.Tag.Get("sql"), "primary_key")
staff := model.Staff{}
assert.Equal(t, reflect.TypeOf(staff.Email).String(), "*string")
assert.Equal(t, reflect.TypeOf(staff.Picture).String(), "*[]uint8")
}
const genTestDir2 = "./.gentestdata2"
func TestCmdGenerator(t *testing.T) {
err := os.RemoveAll(genTestDir2)
assert.NilError(t, err)
cmd := exec.Command("jet", "-dbname=jetdb", "-host=localhost", "-port=5432",
"-user=jet", "-password=jet", "-schema=dvds", "-path="+genTestDir2)
err = cmd.Run()
assert.NilError(t, err)
assertGeneratedFiles(t)
err = os.RemoveAll(genTestDir2)
assert.NilError(t, err)
}
func TestGenerator(t *testing.T) {
err := os.RemoveAll(genTestDir2)
assert.NilError(t, err)
err = postgres.Generate(genTestDir2, postgres.DBConnection{
Host: dbconfig.Host,
Port: dbconfig.Port,
User: dbconfig.User,
Password: dbconfig.Password,
SslMode: "disable",
Params: "",
DBName: dbconfig.DBName,
SchemaName: "dvds",
})
assert.NilError(t, err)
assertGeneratedFiles(t)
err = os.RemoveAll(genTestDir2)
assert.NilError(t, err)
}
func assertGeneratedFiles(t *testing.T) {
// Table SQL Builder files
tableSQLBuilderFiles, err := ioutil.ReadDir("./.gentestdata2/jetdb/dvds/table")
assert.NilError(t, err)
assertFileNameEqual(t, tableSQLBuilderFiles, "actor.go", "address.go", "category.go", "city.go", "country.go",
"customer.go", "film.go", "film_actor.go", "film_category.go", "inventory.go", "language.go",
"payment.go", "rental.go", "staff.go", "store.go")
assertFileContent(t, "./.gentestdata2/jetdb/dvds/table/actor.go", "\npackage table", actorSQLBuilderFile)
// Enums SQL Builder files
enumFiles, err := ioutil.ReadDir("./.gentestdata2/jetdb/dvds/enum")
assert.NilError(t, err)
assertFileNameEqual(t, enumFiles, "mpaa_rating.go")
assertFileContent(t, "./.gentestdata2/jetdb/dvds/enum/mpaa_rating.go", "\npackage enum", mpaaRatingEnumFile)
// Model files
modelFiles, err := ioutil.ReadDir("./.gentestdata2/jetdb/dvds/model")
assert.NilError(t, err)
assertFileNameEqual(t, modelFiles, "actor.go", "address.go", "category.go", "city.go", "country.go",
"customer.go", "film.go", "film_actor.go", "film_category.go", "inventory.go", "language.go",
"payment.go", "rental.go", "staff.go", "store.go", "mpaa_rating.go")
assertFileContent(t, "./.gentestdata2/jetdb/dvds/model/actor.go", "\npackage model", actorModelFile)
}
func assertFileContent(t *testing.T, filePath string, contentBegin string, expectedContent string) {
enumFileData, err := ioutil.ReadFile(filePath)
assert.NilError(t, err)
beginIndex := bytes.Index(enumFileData, []byte(contentBegin))
//fmt.Println("-"+string(enumFileData[beginIndex:])+"-")
assert.DeepEqual(t, string(enumFileData[beginIndex:]), expectedContent)
}
func assertFileNameEqual(t *testing.T, fileInfos []os.FileInfo, fileNames ...string) {
fileNamesMap := map[string]bool{}
for _, fileInfo := range fileInfos {
fileNamesMap[fileInfo.Name()] = true
}
for _, fileName := range fileNames {
assert.Assert(t, fileNamesMap[fileName], fileName+" does not exist.")
}
}
var mpaaRatingEnumFile = `
package enum
import "github.com/go-jet/jet"
var MpaaRating = &struct {
G jet.StringExpression
Pg jet.StringExpression
Pg13 jet.StringExpression
R jet.StringExpression
Nc17 jet.StringExpression
}{
G: jet.NewEnumValue("G"),
Pg: jet.NewEnumValue("PG"),
Pg13: jet.NewEnumValue("PG-13"),
R: jet.NewEnumValue("R"),
Nc17: jet.NewEnumValue("NC-17"),
}
`
var actorSQLBuilderFile = `
package table
import (
"github.com/go-jet/jet"
"github.com/go-jet/jet/postgres"
)
var Actor = newActorTable()
type ActorTable struct {
jet.Table
//Columns
ActorID postgres.ColumnInteger
FirstName postgres.ColumnString
LastName postgres.ColumnString
LastUpdate postgres.ColumnTimestamp
AllColumns jet.ColumnList
MutableColumns jet.ColumnList
}
// creates new ActorTable with assigned alias
func (a *ActorTable) AS(alias string) *ActorTable {
aliasTable := newActorTable()
aliasTable.Table.AS(alias)
return aliasTable
}
func newActorTable() *ActorTable {
var (
ActorIDColumn = postgres.IntegerColumn("actor_id")
FirstNameColumn = postgres.StringColumn("first_name")
LastNameColumn = postgres.StringColumn("last_name")
LastUpdateColumn = postgres.TimestampColumn("last_update")
)
return &ActorTable{
Table: jet.NewTable(jet.PostgreSQL, "dvds", "actor", ActorIDColumn, FirstNameColumn, LastNameColumn, LastUpdateColumn),
//Columns
ActorID: ActorIDColumn,
FirstName: FirstNameColumn,
LastName: LastNameColumn,
LastUpdate: LastUpdateColumn,
AllColumns: jet.ColumnList{ActorIDColumn, FirstNameColumn, LastNameColumn, LastUpdateColumn},
MutableColumns: jet.ColumnList{FirstNameColumn, LastNameColumn, LastUpdateColumn},
}
}
`
var actorModelFile = `
package model
import (
"time"
)
type Actor struct {
ActorID int32 ` + "`sql:\"primary_key\"`" + `
FirstName string
LastName string
LastUpdate time.Time
}
`

View file

@ -0,0 +1,66 @@
package postgres
import (
"github.com/go-jet/jet/internal/testutils"
"github.com/go-jet/jet/tests/.gentestdata/jetdb/northwind/model"
. "github.com/go-jet/jet/tests/.gentestdata/jetdb/northwind/table"
"gotest.tools/assert"
"testing"
)
func TestNorthwindJoinEverything(t *testing.T) {
stmt := Customers.
LEFT_JOIN(CustomerCustomerDemo, Customers.CustomerID.EQ(CustomerCustomerDemo.CustomerID)).
LEFT_JOIN(CustomerDemographics, CustomerCustomerDemo.CustomerTypeID.EQ(CustomerDemographics.CustomerTypeID)).
LEFT_JOIN(Orders, Orders.CustomerID.EQ(Customers.CustomerID)).
LEFT_JOIN(Shippers, Orders.ShipVia.EQ(Shippers.ShipperID)).
LEFT_JOIN(OrderDetails, Orders.OrderID.EQ(OrderDetails.OrderID)).
LEFT_JOIN(Products, OrderDetails.ProductID.EQ(Products.ProductID)).
LEFT_JOIN(Categories, Products.CategoryID.EQ(Categories.CategoryID)).
LEFT_JOIN(Suppliers, Products.SupplierID.EQ(Suppliers.SupplierID)).
LEFT_JOIN(Employees, Orders.EmployeeID.EQ(Employees.EmployeeID)).
LEFT_JOIN(EmployeeTerritories, EmployeeTerritories.EmployeeID.EQ(Employees.EmployeeID)).
LEFT_JOIN(Territories, EmployeeTerritories.TerritoryID.EQ(Territories.TerritoryID)).
LEFT_JOIN(Region, Territories.RegionID.EQ(Region.RegionID)).
SELECT(
Customers.AllColumns,
CustomerDemographics.AllColumns,
Orders.AllColumns,
Shippers.AllColumns,
OrderDetails.AllColumns,
Products.AllColumns,
Categories.AllColumns,
Suppliers.AllColumns,
).
ORDER_BY(Customers.CustomerID, Orders.OrderID, Products.ProductID)
var dest []struct {
model.Customers
Demographics model.CustomerDemographics
Orders []struct {
model.Orders
Shipper model.Shippers
Details struct {
model.OrderDetails
Products []struct {
model.Products
Category model.Categories
Supplier model.Suppliers
}
}
}
}
err := stmt.Query(db, &dest)
assert.NilError(t, err)
//jsonSave("./testdata/northwind-all.json", dest)
testutils.AssertJSONFile(t, "./postgres/testdata/northwind-all.json", dest)
}

View file

@ -0,0 +1,182 @@
package postgres
import (
. "github.com/go-jet/jet"
"github.com/go-jet/jet/internal/testutils"
"github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/model"
. "github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/table"
"github.com/google/uuid"
"gotest.tools/assert"
"testing"
)
func TestUUIDType(t *testing.T) {
query := AllTypes.
SELECT(AllTypes.UUID, AllTypes.UUIDPtr).
WHERE(AllTypes.UUID.EQ(String("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11")))
testutils.AssertDebugStatementSql(t, query, `
SELECT all_types.uuid AS "all_types.uuid",
all_types.uuid_ptr AS "all_types.uuid_ptr"
FROM test_sample.all_types
WHERE all_types.uuid = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11';
`, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11")
result := model.AllTypes{}
err := query.Query(db, &result)
assert.NilError(t, err)
assert.Equal(t, result.UUID, uuid.MustParse("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"))
assert.DeepEqual(t, result.UUIDPtr, UUIDPtr("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"))
}
func TestEnumType(t *testing.T) {
query := Person.
SELECT(Person.AllColumns)
testutils.AssertDebugStatementSql(t, query, `
SELECT person.person_id AS "person.person_id",
person.first_name AS "person.first_name",
person.last_name AS "person.last_name",
person."Mood" AS "person.Mood"
FROM test_sample.person;
`)
result := []model.Person{}
err := query.Query(db, &result)
assert.NilError(t, err)
testutils.AssertJSON(t, result, `
[
{
"PersonID": "b68dbff4-a87d-11e9-a7f2-98ded00c39c6",
"FirstName": "Sad",
"LastName": "John",
"Mood": "sad"
},
{
"PersonID": "b68dbff5-a87d-11e9-a7f2-98ded00c39c7",
"FirstName": "Ok",
"LastName": "John",
"Mood": "ok"
},
{
"PersonID": "b68dbff6-a87d-11e9-a7f2-98ded00c39c8",
"FirstName": "Ok",
"LastName": "John",
"Mood": "ok"
}
]
`)
}
func TestSelecSelfJoin1(t *testing.T) {
var expectedSQL = `
SELECT employee.employee_id AS "employee.employee_id",
employee.first_name AS "employee.first_name",
employee.last_name AS "employee.last_name",
employee.employment_date AS "employee.employment_date",
employee.manager_id AS "employee.manager_id",
manager.employee_id AS "manager.employee_id",
manager.first_name AS "manager.first_name",
manager.last_name AS "manager.last_name",
manager.employment_date AS "manager.employment_date",
manager.manager_id AS "manager.manager_id"
FROM test_sample.employee
LEFT JOIN test_sample.employee AS manager ON (manager.employee_id = employee.manager_id)
ORDER BY employee.employee_id;
`
manager := Employee.AS("manager")
query := Employee.
LEFT_JOIN(manager, manager.EmployeeID.EQ(Employee.ManagerID)).
SELECT(
Employee.AllColumns,
manager.AllColumns,
).
ORDER_BY(Employee.EmployeeID)
testutils.AssertDebugStatementSql(t, query, expectedSQL)
type Manager model.Employee
var dest []struct {
model.Employee
Manager *Manager
}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.Equal(t, len(dest), 8)
assert.DeepEqual(t, dest[0].Employee, model.Employee{
EmployeeID: 1,
FirstName: "Windy",
LastName: "Hays",
EmploymentDate: TimestampWithTimeZone("1999-01-08 04:05:06.1 +0100 CET", 1),
ManagerID: nil,
})
assert.Assert(t, dest[0].Manager == nil)
assert.DeepEqual(t, dest[7].Employee, model.Employee{
EmployeeID: 8,
FirstName: "Salley",
LastName: "Lester",
EmploymentDate: TimestampWithTimeZone("1999-01-08 04:05:06 +0100 CET", 1),
ManagerID: Int32Ptr(3),
})
}
func TestWierdNamesTable(t *testing.T) {
stmt := WeirdNamesTable.SELECT(WeirdNamesTable.AllColumns)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT "WEIRD NAMES TABLE".weird_column_name1 AS "WEIRD NAMES TABLE.weird_column_name1",
"WEIRD NAMES TABLE"."Weird_Column_Name2" AS "WEIRD NAMES TABLE.Weird_Column_Name2",
"WEIRD NAMES TABLE"."wEiRd_cOluMn_nAmE3" AS "WEIRD NAMES TABLE.wEiRd_cOluMn_nAmE3",
"WEIRD NAMES TABLE"."WeIrd_CoLuMN_Name4" AS "WEIRD NAMES TABLE.WeIrd_CoLuMN_Name4",
"WEIRD NAMES TABLE"."WEIRD_COLUMN_NAME5" AS "WEIRD NAMES TABLE.WEIRD_COLUMN_NAME5",
"WEIRD NAMES TABLE"."WeirdColumnName6" AS "WEIRD NAMES TABLE.WeirdColumnName6",
"WEIRD NAMES TABLE"."weirdColumnName7" AS "WEIRD NAMES TABLE.weirdColumnName7",
"WEIRD NAMES TABLE".weirdcolumnname8 AS "WEIRD NAMES TABLE.weirdcolumnname8",
"WEIRD NAMES TABLE"."weird col name9" AS "WEIRD NAMES TABLE.weird col name9",
"WEIRD NAMES TABLE"."wEiRd cOlu nAmE10" AS "WEIRD NAMES TABLE.wEiRd cOlu nAmE10",
"WEIRD NAMES TABLE"."WEIRD COLU NAME11" AS "WEIRD NAMES TABLE.WEIRD COLU NAME11",
"WEIRD NAMES TABLE"."Weird Colu Name12" AS "WEIRD NAMES TABLE.Weird Colu Name12",
"WEIRD NAMES TABLE"."weird-col-name13" AS "WEIRD NAMES TABLE.weird-col-name13",
"WEIRD NAMES TABLE"."wEiRd-cOlu-nAmE14" AS "WEIRD NAMES TABLE.wEiRd-cOlu-nAmE14",
"WEIRD NAMES TABLE"."WEIRD-COLU-NAME15" AS "WEIRD NAMES TABLE.WEIRD-COLU-NAME15",
"WEIRD NAMES TABLE"."Weird-Colu-Name16" AS "WEIRD NAMES TABLE.Weird-Colu-Name16"
FROM test_sample."WEIRD NAMES TABLE";
`)
dest := []model.WeirdNamesTable{}
err := stmt.Query(db, &dest)
assert.NilError(t, err)
assert.Equal(t, len(dest), 1)
assert.DeepEqual(t, dest[0], model.WeirdNamesTable{
WeirdColumnName1: "Doe",
WeirdColumnName2: "Doe",
WeirdColumnName3: "Doe",
WeirdColumnName4: "Doe",
WeirdColumnName5: "Doe",
WeirdColumnName6: "Doe",
WeirdColumnName7: "Doe",
Weirdcolumnname8: StringPtr("Doe"),
WeirdColName9: "Doe",
WeirdColuName10: "Doe",
WeirdColuName11: "Doe",
WeirdColuName12: "Doe",
WeirdColName13: "Doe",
WeirdColuName14: "Doe",
WeirdColuName15: "Doe",
WeirdColuName16: "Doe",
})
}

799
tests/postgres/scan_test.go Normal file
View file

@ -0,0 +1,799 @@
package postgres
import (
. "github.com/go-jet/jet"
"github.com/go-jet/jet/internal/testutils"
"github.com/go-jet/jet/tests/.gentestdata/jetdb/dvds/model"
. "github.com/go-jet/jet/tests/.gentestdata/jetdb/dvds/table"
"github.com/google/uuid"
"gotest.tools/assert"
"testing"
)
var query = Inventory.
SELECT(Inventory.AllColumns).
LIMIT(1).
ORDER_BY(Inventory.InventoryID)
func TestScanToInvalidDestination(t *testing.T) {
t.Run("nil dest", func(t *testing.T) {
err := query.Query(db, nil)
assert.Error(t, err, "jet: Destination is nil")
})
t.Run("struct dest", func(t *testing.T) {
err := query.Query(db, struct{}{})
assert.Error(t, err, "jet: Destination has to be a pointer to slice or pointer to struct")
})
t.Run("slice dest", func(t *testing.T) {
err := query.Query(db, []struct{}{})
assert.Error(t, err, "jet: Destination has to be a pointer to slice or pointer to struct")
})
t.Run("slice of pointers to pointer dest", func(t *testing.T) {
err := query.Query(db, []**struct{}{})
assert.Error(t, err, "jet: Destination has to be a pointer to slice or pointer to struct")
})
t.Run("map dest", func(t *testing.T) {
err := query.Query(db, []map[string]string{})
assert.Error(t, err, "jet: Destination has to be a pointer to slice or pointer to struct")
})
}
func TestScanToValidDestination(t *testing.T) {
t.Run("pointer to struct", func(t *testing.T) {
err := query.Query(db, &struct{}{})
assert.NilError(t, err)
})
t.Run("pointer to slice", func(t *testing.T) {
err := query.Query(db, &[]struct{}{})
assert.NilError(t, err)
})
t.Run("pointer to slice of pointer to structs", func(t *testing.T) {
err := query.Query(db, &[]*struct{}{})
assert.NilError(t, err)
})
t.Run("pointer to slice of strings", func(t *testing.T) {
err := query.Query(db, &[]int32{})
assert.NilError(t, err)
})
t.Run("pointer to slice of strings", func(t *testing.T) {
err := query.Query(db, &[]*int32{})
assert.NilError(t, err)
})
}
func TestScanToStruct(t *testing.T) {
query := Inventory.
SELECT(Inventory.AllColumns).
ORDER_BY(Inventory.InventoryID)
t.Run("one struct", func(t *testing.T) {
dest := model.Inventory{}
err := query.LIMIT(1).Query(db, &dest)
assert.NilError(t, err)
assert.DeepEqual(t, inventory1, dest)
})
t.Run("multiple structs, just first one used", func(t *testing.T) {
dest := model.Inventory{}
err := query.LIMIT(10).Query(db, &dest)
assert.NilError(t, err)
assert.DeepEqual(t, inventory1, dest)
})
t.Run("one struct", func(t *testing.T) {
dest := struct {
model.Inventory
}{}
err := query.LIMIT(1).Query(db, &dest)
assert.NilError(t, err)
assert.DeepEqual(t, inventory1, dest.Inventory)
})
t.Run("one struct", func(t *testing.T) {
dest := struct {
*model.Inventory
}{}
err := query.LIMIT(1).Query(db, &dest)
assert.NilError(t, err)
assert.DeepEqual(t, inventory1, *dest.Inventory)
})
t.Run("invalid dest", func(t *testing.T) {
dest := struct {
Inventory **model.Inventory
}{}
err := query.Query(db, &dest)
assert.Error(t, err, "jet: Unsupported dest type: Inventory **model.Inventory")
})
t.Run("invalid dest 2", func(t *testing.T) {
dest := struct {
Inventory ***model.Inventory
}{}
err := query.Query(db, &dest)
assert.Error(t, err, "jet: Unsupported dest type: Inventory ***model.Inventory")
})
t.Run("custom struct", func(t *testing.T) {
type Inventory struct {
InventoryID *int32 `sql:"primary_key"`
FilmID int16
StoreID *int16
}
dest := Inventory{}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.Equal(t, *dest.InventoryID, int32(1))
assert.Equal(t, dest.FilmID, int16(1))
assert.Equal(t, *dest.StoreID, int16(1))
})
t.Run("type convert int32 to int", func(t *testing.T) {
type Inventory struct {
InventoryID int
FilmID string
}
dest := Inventory{}
err := query.Query(db, &dest)
assert.NilError(t, err)
})
t.Run("type mismatch scanner type", func(t *testing.T) {
type Inventory struct {
InventoryID uuid.UUID
FilmID string
}
dest := Inventory{}
err := query.Query(db, &dest)
assert.Error(t, err, `Scan: unable to scan type int32 into UUID, at struct field: InventoryID uuid.UUID of type postgres.Inventory. `)
})
}
func TestScanToNestedStruct(t *testing.T) {
query := Inventory.
INNER_JOIN(Film, Inventory.FilmID.EQ(Film.FilmID)).
INNER_JOIN(Store, Inventory.StoreID.EQ(Store.StoreID)).
SELECT(Inventory.AllColumns, Film.AllColumns, Store.AllColumns).
WHERE(Inventory.InventoryID.EQ(Int(1)))
t.Run("embedded structs", func(t *testing.T) {
dest := struct {
model.Inventory
model.Film
model.Store
}{}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.DeepEqual(t, dest.Inventory, inventory1)
assert.DeepEqual(t, dest.Film, film1)
assert.DeepEqual(t, dest.Store, store1)
})
t.Run("embedded pointer structs", func(t *testing.T) {
dest := struct {
*model.Inventory
*model.Film
*model.Store
}{}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.DeepEqual(t, *dest.Inventory, inventory1)
assert.DeepEqual(t, *dest.Film, film1)
assert.DeepEqual(t, *dest.Store, store1)
})
t.Run("embedded unused structs", func(t *testing.T) {
dest := struct {
model.Inventory
model.Actor //unused
}{}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.DeepEqual(t, dest.Inventory, inventory1)
assert.DeepEqual(t, dest.Actor, model.Actor{})
})
t.Run("embedded unused pointer structs", func(t *testing.T) {
dest := struct {
model.Inventory
*model.Actor //unused
}{}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.DeepEqual(t, dest.Inventory, inventory1)
assert.DeepEqual(t, dest.Actor, (*model.Actor)(nil))
})
t.Run("embedded unused pointer structs", func(t *testing.T) {
dest := struct {
model.Inventory
Actor *model.Actor //unused
}{}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.DeepEqual(t, dest.Inventory, inventory1)
assert.DeepEqual(t, dest.Actor, (*model.Actor)(nil))
})
t.Run("embedded pointer to selected column", func(t *testing.T) {
query := Inventory.
INNER_JOIN(Film, Inventory.FilmID.EQ(Film.FilmID)).
INNER_JOIN(Store, Inventory.StoreID.EQ(Store.StoreID)).
SELECT(Inventory.AllColumns, Film.AllColumns, Store.AllColumns, String("").AS("actor.first_name")).
WHERE(Inventory.InventoryID.EQ(Int(1)))
dest := struct {
model.Inventory
Actor *model.Actor //unused
}{}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.DeepEqual(t, dest.Inventory, inventory1)
assert.Assert(t, dest.Actor != nil)
})
t.Run("struct embedded unused pointer", func(t *testing.T) {
dest := struct {
model.Inventory
Actor *struct {
model.Actor
} //unused
}{}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.DeepEqual(t, dest.Inventory, inventory1)
assert.DeepEqual(t, dest.Actor, (*struct{ model.Actor })(nil))
})
t.Run("multiple embedded unused pointer", func(t *testing.T) {
dest := struct {
model.Inventory
Actor *struct {
model.Actor //unused
model.Language //unesed
}
}{}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.DeepEqual(t, dest.Inventory, inventory1)
assert.DeepEqual(t, dest.Actor, (*struct {
model.Actor
model.Language
})(nil))
})
t.Run("field not nil, embedded selected model", func(t *testing.T) {
dest := struct {
model.Inventory
Actor *struct {
model.Actor //unselected
model.Film //selected
}
}{}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.DeepEqual(t, dest.Inventory, inventory1)
assert.Assert(t, dest.Actor != nil)
assert.DeepEqual(t, dest.Actor.Actor, model.Actor{})
assert.DeepEqual(t, dest.Actor.Film, film1)
})
t.Run("field not nil, deeply nested selected model", func(t *testing.T) {
dest := struct {
model.Inventory
Actor *struct {
model.Actor //unselected
Film *struct {
*model.Film //selected
}
}
}{}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.DeepEqual(t, dest.Inventory, inventory1)
assert.Assert(t, dest.Actor != nil)
assert.Assert(t, dest.Actor.Film != nil)
assert.DeepEqual(t, dest.Actor.Film.Film, &film1)
})
t.Run("embedded structs", func(t *testing.T) {
query := Inventory.
INNER_JOIN(Film, Inventory.FilmID.EQ(Film.FilmID)).
INNER_JOIN(Store, Inventory.StoreID.EQ(Store.StoreID)).
INNER_JOIN(Language, Film.LanguageID.EQ(Language.LanguageID)).
SELECT(Inventory.AllColumns, Film.AllColumns, Store.AllColumns, Language.AllColumns).
WHERE(Inventory.InventoryID.EQ(Int(1)))
type Language3 model.Language
dest := struct {
model.Inventory
Film struct {
model.Film
Language model.Language
Language2 *model.Language `alias:"Language.*"`
Language3 *Language3 `alias:"language"`
Lang struct {
model.Language
}
Lang2 *struct {
model.Language
}
}
Store model.Store
}{}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.DeepEqual(t, dest.Inventory, inventory1)
assert.DeepEqual(t, dest.Film.Film, film1)
assert.DeepEqual(t, dest.Store, store1)
assert.DeepEqual(t, dest.Film.Language, language1)
assert.DeepEqual(t, dest.Film.Lang.Language, language1)
assert.DeepEqual(t, dest.Film.Lang2.Language, language1)
assert.DeepEqual(t, dest.Film.Language2, &language1)
assert.DeepEqual(t, model.Language(*dest.Film.Language3), language1)
})
}
func TestScanToSlice(t *testing.T) {
t.Run("slice of structs", func(t *testing.T) {
query := Inventory.
SELECT(Inventory.AllColumns).
ORDER_BY(Inventory.InventoryID).
LIMIT(10)
t.Run("slice od inventory", func(t *testing.T) {
dest := []model.Inventory{}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.Equal(t, len(dest), 10)
assert.DeepEqual(t, dest[0], inventory1)
assert.DeepEqual(t, dest[1], inventory2)
})
t.Run("slice of ints", func(t *testing.T) {
var dest []int32
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.DeepEqual(t, dest, []int32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
})
t.Run("slice type mismatch ", func(t *testing.T) {
var dest []int
err := query.Query(db, &dest)
assert.Error(t, err, `jet: can't append int32 to []int slice `)
})
})
t.Run("slice of complex structs", func(t *testing.T) {
query := Inventory.
INNER_JOIN(Film, Inventory.FilmID.EQ(Film.FilmID)).
INNER_JOIN(Store, Inventory.StoreID.EQ(Store.StoreID)).
SELECT(
Inventory.AllColumns,
Film.AllColumns,
Store.AllColumns,
).
ORDER_BY(Inventory.InventoryID).
LIMIT(10)
t.Run("struct with slice of ints", func(t *testing.T) {
var dest struct {
model.Film
IDs []int32 `alias:"inventory.inventory_id"`
}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.DeepEqual(t, dest.Film, film1)
assert.DeepEqual(t, dest.IDs, []int32{1, 2, 3, 4, 5, 6, 7, 8})
})
t.Run("slice of structs with slice of ints", func(t *testing.T) {
var dest []struct {
model.Film
IDs []int32 `alias:"inventory.inventory_id"`
}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.Equal(t, len(dest), 2)
assert.DeepEqual(t, dest[0].Film, film1)
assert.DeepEqual(t, dest[0].IDs, []int32{1, 2, 3, 4, 5, 6, 7, 8})
assert.DeepEqual(t, dest[1].Film, film2)
assert.DeepEqual(t, dest[1].IDs, []int32{9, 10})
})
t.Run("slice of structs with slice of pointer to ints", func(t *testing.T) {
var dest []struct {
model.Film
IDs []*int32 `alias:"inventory.inventory_id"`
}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.Equal(t, len(dest), 2)
assert.DeepEqual(t, dest[0].Film, film1)
assert.DeepEqual(t, dest[0].IDs, []*int32{Int32Ptr(1), Int32Ptr(2), Int32Ptr(3), Int32Ptr(4),
Int32Ptr(5), Int32Ptr(6), Int32Ptr(7), Int32Ptr(8)})
assert.DeepEqual(t, dest[1].Film, film2)
assert.DeepEqual(t, dest[1].IDs, []*int32{Int32Ptr(9), Int32Ptr(10)})
})
t.Run("complex struct 1", func(t *testing.T) {
dest := []struct {
model.Inventory
model.Film
model.Store
}{}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.Equal(t, len(dest), 10)
assert.DeepEqual(t, dest[0].Inventory, inventory1)
assert.DeepEqual(t, dest[0].Film, film1)
assert.DeepEqual(t, dest[0].Store, store1)
assert.DeepEqual(t, dest[1].Inventory, inventory2)
})
t.Run("complex struct 2", func(t *testing.T) {
var dest []struct {
*model.Inventory
model.Film
*model.Store
}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.Equal(t, len(dest), 10)
assert.DeepEqual(t, dest[0].Inventory, &inventory1)
assert.DeepEqual(t, dest[0].Film, film1)
assert.DeepEqual(t, dest[0].Store, &store1)
assert.DeepEqual(t, dest[1].Inventory, &inventory2)
})
t.Run("complex struct 3", func(t *testing.T) {
var dest []struct {
Inventory model.Inventory
Film *model.Film
Store struct {
*model.Store
}
}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.Equal(t, len(dest), 10)
assert.DeepEqual(t, dest[0].Inventory, inventory1)
assert.DeepEqual(t, dest[0].Film, &film1)
assert.DeepEqual(t, dest[0].Store.Store, &store1)
assert.DeepEqual(t, dest[1].Inventory, inventory2)
})
t.Run("complex struct 4", func(t *testing.T) {
var dest []struct {
model.Film
Inventories []struct {
model.Inventory
model.Store
}
}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.Equal(t, len(dest), 2)
assert.DeepEqual(t, dest[0].Film, film1)
assert.DeepEqual(t, len(dest[0].Inventories), 8)
assert.DeepEqual(t, dest[0].Inventories[0].Inventory, inventory1)
assert.DeepEqual(t, dest[0].Inventories[0].Store, store1)
})
t.Run("complex struct 5", func(t *testing.T) {
var dest []struct {
model.Film
Inventories []struct {
model.Inventory
Rentals *[]model.Rental
Rentals2 []model.Rental
}
}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.Equal(t, len(dest), 2)
assert.DeepEqual(t, dest[0].Film, film1)
assert.Equal(t, len(dest[0].Inventories), 8)
assert.DeepEqual(t, dest[0].Inventories[0].Inventory, inventory1)
assert.Assert(t, dest[0].Inventories[0].Rentals == nil)
assert.Assert(t, dest[0].Inventories[0].Rentals2 == nil)
})
})
t.Run("slice of complex structs 2", func(t *testing.T) {
query := Country.
INNER_JOIN(City, City.CountryID.EQ(Country.CountryID)).
INNER_JOIN(Address, Address.CityID.EQ(City.CityID)).
INNER_JOIN(Customer, Customer.AddressID.EQ(Address.AddressID)).
SELECT(Country.AllColumns, City.AllColumns, Address.AllColumns, Customer.AllColumns).
ORDER_BY(Country.CountryID.ASC(), City.CityID.ASC(), Address.AddressID.ASC(), Customer.CustomerID.ASC()).
LIMIT(1000)
t.Run("dest1", func(t *testing.T) {
var dest []struct {
model.Country
Cities []struct {
model.City
Adresses []struct {
model.Address
Customer model.Customer
}
}
}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.Equal(t, len(dest), 108)
assert.DeepEqual(t, dest[100].Country, countryUk)
assert.Equal(t, len(dest[100].Cities), 8)
assert.DeepEqual(t, dest[100].Cities[2].City, cityLondon)
assert.Equal(t, len(dest[100].Cities[2].Adresses), 2)
assert.DeepEqual(t, dest[100].Cities[2].Adresses[0].Address, address256)
assert.DeepEqual(t, dest[100].Cities[2].Adresses[0].Customer, customer256)
assert.DeepEqual(t, dest[100].Cities[2].Adresses[1].Address, addres517)
assert.DeepEqual(t, dest[100].Cities[2].Adresses[1].Customer, customer512)
})
t.Run("dest1", func(t *testing.T) {
var dest []*struct {
*model.Country
Cities []*struct {
*model.City
Adresses *[]*struct {
*model.Address
Customer *model.Customer
}
}
}
err := query.Query(db, &dest)
assert.NilError(t, err)
assert.Equal(t, len(dest), 108)
assert.DeepEqual(t, dest[100].Country, &countryUk)
assert.Equal(t, len(dest[100].Cities), 8)
assert.DeepEqual(t, dest[100].Cities[2].City, &cityLondon)
assert.Equal(t, len(*dest[100].Cities[2].Adresses), 2)
assert.DeepEqual(t, (*dest[100].Cities[2].Adresses)[0].Address, &address256)
assert.DeepEqual(t, (*dest[100].Cities[2].Adresses)[0].Customer, &customer256)
assert.DeepEqual(t, (*dest[100].Cities[2].Adresses)[1].Address, &addres517)
assert.DeepEqual(t, (*dest[100].Cities[2].Adresses)[1].Customer, &customer512)
})
})
t.Run("dest1", func(t *testing.T) {
var dest []*struct {
*model.Country
Cities []**struct {
*model.City
}
}
err := query.Query(db, &dest)
assert.Error(t, err, "jet: Unsupported dest type: Cities []**struct { *model.City }")
})
}
var address256 = model.Address{
AddressID: 256,
Address: "1497 Yuzhou Drive",
Address2: StringPtr(""),
District: "England",
CityID: 312,
PostalCode: StringPtr("3433"),
Phone: "246810237916",
LastUpdate: *testutils.TimestampWithoutTimeZone("2006-02-15 09:45:30", 0),
}
var addres517 = model.Address{
AddressID: 517,
Address: "548 Uruapan Street",
Address2: StringPtr(""),
District: "Ontario",
CityID: 312,
PostalCode: StringPtr("35653"),
Phone: "879347453467",
LastUpdate: *testutils.TimestampWithoutTimeZone("2006-02-15 09:45:30", 0),
}
var customer256 = model.Customer{
CustomerID: 252,
StoreID: 2,
FirstName: "Mattie",
LastName: "Hoffman",
Email: StringPtr("mattie.hoffman@sakilacustomer.org"),
AddressID: 256,
Activebool: true,
CreateDate: *testutils.TimestampWithoutTimeZone("2006-02-14 00:00:00", 0),
LastUpdate: testutils.TimestampWithoutTimeZone("2013-05-26 14:49:45.738", 0),
Active: Int32Ptr(1),
}
var customer512 = model.Customer{
CustomerID: 512,
StoreID: 1,
FirstName: "Cecil",
LastName: "Vines",
Email: StringPtr("cecil.vines@sakilacustomer.org"),
AddressID: 517,
Activebool: true,
CreateDate: *testutils.TimestampWithoutTimeZone("2006-02-14 00:00:00", 0),
LastUpdate: testutils.TimestampWithoutTimeZone("2013-05-26 14:49:45.738", 0),
Active: Int32Ptr(1),
}
var countryUk = model.Country{
CountryID: 102,
Country: "United Kingdom",
LastUpdate: *testutils.TimestampWithoutTimeZone("2006-02-15 09:44:00", 0),
}
var cityLondon = model.City{
CityID: 312,
City: "London",
CountryID: 102,
LastUpdate: *testutils.TimestampWithoutTimeZone("2006-02-15 09:45:25", 0),
}
var inventory1 = model.Inventory{
InventoryID: 1,
FilmID: 1,
StoreID: 1,
LastUpdate: *testutils.TimestampWithoutTimeZone("2006-02-15 10:09:17", 0),
}
var inventory2 = model.Inventory{
InventoryID: 2,
FilmID: 1,
StoreID: 1,
LastUpdate: *testutils.TimestampWithoutTimeZone("2006-02-15 10:09:17", 0),
}
var film1 = model.Film{
FilmID: 1,
Title: "Academy Dinosaur",
Description: StringPtr("A Epic Drama of a Feminist And a Mad Scientist who must Battle a Teacher in The Canadian Rockies"),
ReleaseYear: Int32Ptr(2006),
LanguageID: 1,
RentalDuration: 6,
RentalRate: 0.99,
Length: Int16Ptr(86),
ReplacementCost: 20.99,
Rating: &pgRating,
LastUpdate: *testutils.TimestampWithoutTimeZone("2013-05-26 14:50:58.951", 3),
SpecialFeatures: StringPtr("{\"Deleted Scenes\",\"Behind the Scenes\"}"),
Fulltext: "'academi':1 'battl':15 'canadian':20 'dinosaur':2 'drama':5 'epic':4 'feminist':8 'mad':11 'must':14 'rocki':21 'scientist':12 'teacher':17",
}
var film2 = model.Film{
FilmID: 2,
Title: "Ace Goldfinger",
Description: StringPtr("A Astounding Epistle of a Database Administrator And a Explorer who must Find a Car in Ancient China"),
ReleaseYear: Int32Ptr(2006),
LanguageID: 1,
RentalDuration: 3,
RentalRate: 4.99,
Length: Int16Ptr(48),
ReplacementCost: 12.99,
Rating: &gRating,
LastUpdate: *testutils.TimestampWithoutTimeZone("2013-05-26 14:50:58.951", 3),
SpecialFeatures: StringPtr(`{Trailers,"Deleted Scenes"}`),
Fulltext: `'ace':1 'administr':9 'ancient':19 'astound':4 'car':17 'china':20 'databas':8 'epistl':5 'explor':12 'find':15 'goldfing':2 'must':14`,
}
var store1 = model.Store{
StoreID: 1,
ManagerStaffID: 1,
AddressID: 1,
LastUpdate: *testutils.TimestampWithoutTimeZone("2006-02-15 09:57:12", 0),
}
var pgRating = model.MpaaRating_Pg
var gRating = model.MpaaRating_G
var language1 = model.Language{
LanguageID: 1,
Name: "English ",
LastUpdate: *testutils.TimestampWithoutTimeZone("2006-02-15 10:02:19", 0),
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

135339
tests/postgres/testdata/northwind-all.json vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,302 @@
package postgres
import (
"context"
. "github.com/go-jet/jet"
"github.com/go-jet/jet/internal/testutils"
"github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/model"
. "github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/table"
"gotest.tools/assert"
"testing"
"time"
)
func TestUpdateValues(t *testing.T) {
setupLinkTableForUpdateTest(t)
query := Link.
UPDATE(Link.Name, Link.URL).
SET("Bong", "http://bong.com").
WHERE(Link.Name.EQ(String("Bing")))
var expectedSQL = `
UPDATE test_sample.link
SET (name, url) = ('Bong', 'http://bong.com')
WHERE link.name = 'Bing';
`
testutils.AssertDebugStatementSql(t, query, expectedSQL, "Bong", "http://bong.com", "Bing")
assertExec(t, query, 1)
links := []model.Link{}
err := Link.
SELECT(Link.AllColumns).
WHERE(Link.Name.EQ(String("Bong"))).
Query(db, &links)
assert.NilError(t, err)
assert.Equal(t, len(links), 1)
assert.DeepEqual(t, links[0], model.Link{
ID: 204,
URL: "http://bong.com",
Name: "Bong",
})
}
func TestUpdateWithSubQueries(t *testing.T) {
setupLinkTableForUpdateTest(t)
query := Link.
UPDATE(Link.Name, Link.URL).
SET(
SELECT(String("Bong")),
SELECT(Link.URL).
FROM(Link).
WHERE(Link.Name.EQ(String("Bing"))),
).
WHERE(Link.Name.EQ(String("Bing")))
expectedSQL := `
UPDATE test_sample.link
SET (name, url) = ((
SELECT 'Bong'
), (
SELECT link.url AS "link.url"
FROM test_sample.link
WHERE link.name = 'Bing'
))
WHERE link.name = 'Bing';
`
testutils.AssertDebugStatementSql(t, query, expectedSQL, "Bong", "Bing", "Bing")
assertExec(t, query, 1)
}
func TestUpdateAndReturning(t *testing.T) {
setupLinkTableForUpdateTest(t)
expectedSQL := `
UPDATE test_sample.link
SET (name, url) = ('DuckDuckGo', 'http://www.duckduckgo.com')
WHERE link.name = 'Ask'
RETURNING link.id AS "link.id",
link.url AS "link.url",
link.name AS "link.name",
link.description AS "link.description";
`
stmt := Link.
UPDATE(Link.Name, Link.URL).
SET("DuckDuckGo", "http://www.duckduckgo.com").
WHERE(Link.Name.EQ(String("Ask"))).
RETURNING(Link.AllColumns)
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, "DuckDuckGo", "http://www.duckduckgo.com", "Ask")
links := []model.Link{}
err := stmt.Query(db, &links)
assert.NilError(t, err)
assert.Equal(t, len(links), 2)
assert.Equal(t, links[0].Name, "DuckDuckGo")
assert.Equal(t, links[1].Name, "DuckDuckGo")
}
func TestUpdateWithSelect(t *testing.T) {
stmt := Link.UPDATE(Link.AllColumns).
SET(
Link.
SELECT(Link.AllColumns).
WHERE(Link.ID.EQ(Int(0))),
).
WHERE(Link.ID.EQ(Int(0)))
expectedSQL := `
UPDATE test_sample.link
SET (id, url, name, description) = (
SELECT link.id AS "link.id",
link.url AS "link.url",
link.name AS "link.name",
link.description AS "link.description"
FROM test_sample.link
WHERE link.id = 0
)
WHERE link.id = 0;
`
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, int64(0), int64(0))
assertExec(t, stmt, 1)
}
func TestUpdateWithInvalidSelect(t *testing.T) {
stmt := Link.UPDATE(Link.AllColumns).
SET(
Link.
SELECT(Link.ID, Link.Name).
WHERE(Link.ID.EQ(Int(0))),
).
WHERE(Link.ID.EQ(Int(0)))
var expectedSQL = `
UPDATE test_sample.link
SET (id, url, name, description) = (
SELECT link.id AS "link.id",
link.name AS "link.name"
FROM test_sample.link
WHERE link.id = 0
)
WHERE link.id = 0;
`
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, int64(0), int64(0))
assertExecErr(t, stmt, "pq: number of columns does not match number of values")
}
func TestUpdateWithModelData(t *testing.T) {
setupLinkTableForUpdateTest(t)
link := model.Link{
ID: 201,
URL: "http://www.duckduckgo.com",
Name: "DuckDuckGo",
}
stmt := Link.
UPDATE(Link.AllColumns).
MODEL(link).
WHERE(Link.ID.EQ(Int(int64(link.ID))))
expectedSQL := `
UPDATE test_sample.link
SET (id, url, name, description) = (201, 'http://www.duckduckgo.com', 'DuckDuckGo', NULL)
WHERE link.id = 201;
`
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, int32(201), "http://www.duckduckgo.com", "DuckDuckGo", nil, int64(201))
assertExec(t, stmt, 1)
}
func TestUpdateWithModelDataAndPredefinedColumnList(t *testing.T) {
setupLinkTableForUpdateTest(t)
link := model.Link{
ID: 201,
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(Int(int64(link.ID))))
var expectedSQL = `
UPDATE test_sample.link
SET (description, name, url) = (NULL, 'DuckDuckGo', 'http://www.duckduckgo.com')
WHERE link.id = 201;
`
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, nil, "DuckDuckGo", "http://www.duckduckgo.com", int64(201))
assertExec(t, stmt, 1)
}
func TestUpdateWithInvalidModelData(t *testing.T) {
defer func() {
r := recover()
assert.Equal(t, r, "missing struct field for column : id")
}()
setupLinkTableForUpdateTest(t)
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))))
var expectedSQL = `
UPDATE test_sample.link
SET (id, url, name, description, rel) = ('http://www.duckduckgo.com', 'DuckDuckGo', NULL, NULL)
WHERE link.id = 201;
`
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, "http://www.duckduckgo.com", "DuckDuckGo", nil, nil, int64(201))
assertExecErr(t, stmt, "pq: number of columns does not match number of values")
}
func TestUpdateQueryContext(t *testing.T) {
setupLinkTableForUpdateTest(t)
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, db, &dest)
assert.Error(t, err, "context deadline exceeded")
}
func TestUpdateExecContext(t *testing.T) {
setupLinkTableForUpdateTest(t)
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)
_, err := updateStmt.ExecContext(ctx, db)
assert.Error(t, err, "context deadline exceeded")
}
func setupLinkTableForUpdateTest(t *testing.T) {
cleanUpLinkTable(t)
_, err := Link.INSERT(Link.ID, Link.URL, Link.Name, Link.Description).
VALUES(200, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial", DEFAULT).
VALUES(201, "http://www.ask.com", "Ask", DEFAULT).
VALUES(202, "http://www.ask.com", "Ask", DEFAULT).
VALUES(203, "http://www.yahoo.com", "Yahoo", DEFAULT).
VALUES(204, "http://www.bing.com", "Bing", DEFAULT).
Exec(db)
assert.NilError(t, err)
}
func cleanUpLinkTable(t *testing.T) {
_, err := Link.DELETE().WHERE(Link.ID.GT(Int(0))).Exec(db)
assert.NilError(t, err)
}

139
tests/postgres/util_test.go Normal file
View file

@ -0,0 +1,139 @@
package postgres
import (
"github.com/go-jet/jet"
"github.com/go-jet/jet/internal/testutils"
"github.com/go-jet/jet/tests/.gentestdata/jetdb/dvds/model"
"github.com/google/uuid"
"gotest.tools/assert"
"strings"
"testing"
"time"
)
func assertExec(t *testing.T, stmt jet.Statement, rowsAffected int64) {
res, err := stmt.Exec(db)
assert.NilError(t, err)
rows, err := res.RowsAffected()
assert.NilError(t, err)
assert.Equal(t, rows, rowsAffected)
}
func assertExecErr(t *testing.T, stmt jet.Statement, errorStr string) {
_, err := stmt.Exec(db)
assert.Error(t, err, errorStr)
}
func BoolPtr(b bool) *bool {
return &b
}
func Int16Ptr(i int16) *int16 {
return &i
}
func Int32Ptr(i int32) *int32 {
return &i
}
func Int64Ptr(i int64) *int64 {
return &i
}
func StringPtr(s string) *string {
return &s
}
func ByteArrayPtr(arr []byte) *[]byte {
return &arr
}
func Float32Ptr(f float32) *float32 {
return &f
}
func Float64Ptr(f float64) *float64 {
return &f
}
func UUIDPtr(u string) *uuid.UUID {
newUUID := uuid.MustParse(u)
return &newUUID
}
func TimeWithoutTimeZone(t string) *time.Time {
newTime, err := time.Parse("15:04:05", t)
if err != nil {
panic(err)
}
return &newTime
}
func TimeWithTimeZone(t string) *time.Time {
newTimez, err := time.Parse("15:04:05 -0700", t)
if err != nil {
panic(err)
}
return &newTimez
}
func TimestampWithTimeZone(t string, precision int) *time.Time {
precisionStr := ""
if precision > 0 {
precisionStr = "." + strings.Repeat("9", precision)
}
newTime, err := time.Parse("2006-01-02 15:04:05"+precisionStr+" -0700 MST", t)
if err != nil {
panic(err)
}
return &newTime
}
var customer0 = model.Customer{
CustomerID: 1,
StoreID: 1,
FirstName: "Mary",
LastName: "Smith",
Email: StringPtr("mary.smith@sakilacustomer.org"),
AddressID: 5,
Activebool: true,
CreateDate: *testutils.TimestampWithoutTimeZone("2006-02-14 00:00:00", 0),
LastUpdate: testutils.TimestampWithoutTimeZone("2013-05-26 14:49:45.738", 3),
Active: Int32Ptr(1),
}
var customer1 = model.Customer{
CustomerID: 2,
StoreID: 1,
FirstName: "Patricia",
LastName: "Johnson",
Email: StringPtr("patricia.johnson@sakilacustomer.org"),
AddressID: 6,
Activebool: true,
CreateDate: *testutils.TimestampWithoutTimeZone("2006-02-14 00:00:00", 0),
LastUpdate: testutils.TimestampWithoutTimeZone("2013-05-26 14:49:45.738", 3),
Active: Int32Ptr(1),
}
var lastCustomer = model.Customer{
CustomerID: 599,
StoreID: 2,
FirstName: "Austin",
LastName: "Cintron",
Email: StringPtr("austin.cintron@sakilacustomer.org"),
AddressID: 605,
Activebool: true,
CreateDate: *testutils.TimestampWithoutTimeZone("2006-02-14 00:00:00", 0),
LastUpdate: testutils.TimestampWithoutTimeZone("2013-05-26 14:49:45.738", 3),
Active: Int32Ptr(1),
}