Add support for additional array types.

This commit is contained in:
go-jet 2025-10-16 15:09:07 +02:00
parent 45d4ced9b0
commit 4ee047a675
47 changed files with 1994 additions and 4277 deletions

View file

@ -1,15 +1,13 @@
package postgres
import (
"database/sql"
"github.com/lib/pq"
"encoding/base64"
"fmt"
"github.com/go-jet/jet/v2/internal/utils/ptr"
"github.com/stretchr/testify/assert"
"math"
"github.com/go-jet/jet/v2/qrm"
"github.com/lib/pq"
"testing"
"time"
@ -46,8 +44,7 @@ func TestAllTypesSelectJson(t *testing.T) {
AllTypesAllColumns.Except(
AllTypes.JSON, AllTypes.JSONPtr,
AllTypes.Jsonb, AllTypes.JsonbPtr,
AllTypes.TextArray, AllTypes.TextArrayPtr,
AllTypes.JsonbArray, AllTypes.IntegerArray, AllTypes.IntegerArrayPtr,
AllTypes.JsonbArray,
AllTypes.TextMultiDimArray, AllTypes.TextMultiDimArrayPtr,
),
// unsupported at the moment, casting to text allows these columns to be assigned to string fields
@ -55,11 +52,7 @@ func TestAllTypesSelectJson(t *testing.T) {
CAST(AllTypes.JSON).AS_TEXT().AS("JSON"),
CAST(AllTypes.JsonbPtr).AS_TEXT().AS("jsonbPtr"),
CAST(AllTypes.Jsonb).AS_TEXT().AS("Jsonb"),
CAST(AllTypes.TextArrayPtr).AS_TEXT().AS("TextArrayPtr"),
CAST(AllTypes.TextArray).AS_TEXT().AS("TextArray"),
CAST(AllTypes.JsonbArray).AS_TEXT().AS("JsonbArray"),
CAST(AllTypes.IntegerArray).AS_TEXT().AS("IntegerArray"),
CAST(AllTypes.IntegerArrayPtr).AS_TEXT().AS("IntegerArrayPtr"),
CAST(AllTypes.JsonbArray).AS_TEXT_ARRAY().AS("JsonbArray"),
CAST(AllTypes.TextMultiDimArray).AS_TEXT().AS("TextMultiDimArray"),
CAST(AllTypes.TextMultiDimArrayPtr).AS_TEXT().AS("TextMultiDimArrayPtr"),
).FROM(AllTypes)
@ -117,17 +110,17 @@ FROM (
all_types.uuid AS "uuid",
all_types.xml_ptr AS "xmlPtr",
all_types.xml AS "xml",
all_types.integer_array_ptr AS "integerArrayPtr",
all_types.integer_array AS "integerArray",
all_types.text_array_ptr AS "textArrayPtr",
all_types.text_array AS "textArray",
all_types.mood_ptr AS "moodPtr",
all_types.mood AS "mood",
all_types.json_ptr::text AS "jsonPtr",
all_types.json::text AS "JSON",
all_types.jsonb_ptr::text AS "jsonbPtr",
all_types.jsonb::text AS "Jsonb",
all_types.text_array_ptr::text AS "TextArrayPtr",
all_types.text_array::text AS "TextArray",
all_types.jsonb_array::text AS "JsonbArray",
all_types.integer_array::text AS "IntegerArray",
all_types.integer_array_ptr::text AS "IntegerArrayPtr",
all_types.jsonb_array::text[] AS "JsonbArray",
all_types.text_multi_dim_array::text AS "TextMultiDimArray",
all_types.text_multi_dim_array_ptr::text AS "TextMultiDimArrayPtr"
FROM test_sample.all_types
@ -259,7 +252,7 @@ func TestUUIDType(t *testing.T) {
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';
WHERE all_types.uuid = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid;
`, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11")
result := model.AllTypes{}
@ -875,10 +868,7 @@ FROM (
err := stmtJson.QueryContext(ctx, db, &destSelectJson)
require.NoError(t, err)
testutils.PrintJson(destSelectJson)
require.Equal(t, dest, destSelectJson)
})
}
@ -1583,8 +1573,6 @@ func TestInterval(t *testing.T) {
AllTypes.IntervalPtr.DIV(Float(22.222)).EQ(AllTypes.IntervalPtr),
).FROM(AllTypes)
fmt.Println(stmt.Sql())
testutils.AssertDebugStatementSql(t, stmt, `
SELECT INTERVAL '1 YEAR',
INTERVAL '1 MONTH',
@ -2250,7 +2238,7 @@ var allTypesRow0 = model.AllTypes{
TextArrayPtr: &pq.StringArray{"breakfast", "consulting"},
TextArray: pq.StringArray{"breakfast", "consulting"},
JsonbArray: pq.StringArray{`{"a": 1, "b": 2}`, `{"a": 3, "b": 4}`},
TextMultiDimArrayPtr: testutils.StringPtr("{{meeting,lunch},{training,presentation}}"),
TextMultiDimArrayPtr: ptr.Of("{{meeting,lunch},{training,presentation}}"),
TextMultiDimArray: "{{meeting,lunch},{training,presentation}}",
MoodPtr: &moodSad,
Mood: model.Mood_Happy,

View file

@ -0,0 +1,719 @@
package postgres
import (
"github.com/go-jet/jet/v2/internal/testutils"
"github.com/go-jet/jet/v2/internal/utils/ptr"
. "github.com/go-jet/jet/v2/postgres"
"github.com/go-jet/jet/v2/qrm"
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/test_sample/enum"
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/test_sample/model"
. "github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/test_sample/table"
"github.com/google/uuid"
"github.com/lib/pq"
"github.com/stretchr/testify/require"
"testing"
"time"
)
func TestArraySelect(t *testing.T) {
stmt := SELECT(
SampleArrays.AllColumns,
).FROM(
SampleArrays,
)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT sample_arrays.id AS "sample_arrays.id",
sample_arrays.bool_array AS "sample_arrays.bool_array",
sample_arrays.int2_array_ptr AS "sample_arrays.int2_array_ptr",
sample_arrays.int4_array AS "sample_arrays.int4_array",
sample_arrays.int8_array AS "sample_arrays.int8_array",
sample_arrays.numeric_array AS "sample_arrays.numeric_array",
sample_arrays.decimal_array AS "sample_arrays.decimal_array",
sample_arrays.real_array AS "sample_arrays.real_array",
sample_arrays.double_array AS "sample_arrays.double_array",
sample_arrays.text_array AS "sample_arrays.text_array",
sample_arrays.varchar_array AS "sample_arrays.varchar_array",
sample_arrays.char_array AS "sample_arrays.char_array",
sample_arrays.bytea_array AS "sample_arrays.bytea_array",
sample_arrays.date_array AS "sample_arrays.date_array",
sample_arrays.timestamp_array AS "sample_arrays.timestamp_array",
sample_arrays.timestamptz_array AS "sample_arrays.timestamptz_array",
sample_arrays.time_array AS "sample_arrays.time_array",
sample_arrays.timetz_array AS "sample_arrays.timetz_array",
sample_arrays.interval_array AS "sample_arrays.interval_array",
sample_arrays.uuid_array AS "sample_arrays.uuid_array",
sample_arrays.mood_enum_array AS "sample_arrays.mood_enum_array"
FROM test_sample.sample_arrays;
`)
var dest []model.SampleArrays
err := stmt.Query(db, &dest)
require.NoError(t, err)
require.Len(t, dest, 1)
require.Equal(t, dest[0], sampleArrayRow0)
}
func TestArrayOperations(t *testing.T) {
boolArray := BoolArray(true, false, false, true)
int32Array := Int32Array(-1, 2, -3, 4, 5)
int64Array := Int64Array(10, -11, 12, -13, 14, 1515551)
float32Array := Float32Array(1.01, -2.02, 3.03, 4.04)
float64Array := Float64Array(10.001, 20.002, -3.003, 400050.04)
stringArray := StringArray("temp", "text", "array")
byteaArray := ByteaArray([]byte("temporal"), []byte("byte array"), []byte("array"))
dateArray := DateArray(*testutils.Date("2022-04-06"), *testutils.Date("2018-05-06"))
dateArray2 := ARRAY(Date(2022, 2, 3), Date(2023, 2, 2))
timestampArray := TimestampArray(*testutils.TimestampWithoutTimeZone("1999-01-08 04:05:06", 0))
timestampzArray := TimestampzArray(time.Date(2022, 1, 1, 8, 30, 50, 0, time.UTC))
timestampzArray2 := ARRAY(Timestampz(2023, 2, 3, 10, 29, 34, 1000, "UTC"))
timeArray := TimeArray(*testutils.TimeWithoutTimeZone("14:20:45"), *testutils.TimeWithoutTimeZone("8:10:15"))
timezArray := TimezArray(*testutils.TimeWithTimeZone("04:05:06 -0800"), *testutils.TimeWithTimeZone("01:02:03 -0600"))
timeArray2 := ARRAY(Time(10, 20, 30), Time(5, 45, 45))
timezArray2 := ARRAY(Timez(10, 20, 30, 0, "UTC"), Timez(5, 45, 45, 0, "UTC"))
timestampz := Timestampz(1950, 2, 3, 10, 30, 40, 0, "UTC")
query := SELECT(
// array constructors
boolArray.AS("bool_array"),
int32Array.AS("int32_array"),
int64Array.AS("int64_array"),
float32Array.AS("float32_array"),
float64Array.AS("float64_array"),
stringArray.AS("string_array"),
byteaArray.AS("bytea_array"),
dateArray.AS("date_array"),
timestampArray.AS("timestamp_array"),
timestampzArray.AS("timestampz_array"),
timeArray.AS("time_array"),
timezArray.AS("timez_array"),
// operators
SampleArrays.BoolArray.EQ(boolArray).AS("bool_eq"),
SampleArrays.TextArray.EQ(SampleArrays.TextArray).AS("text_eq"),
SampleArrays.TextArray.NOT_EQ(stringArray).AS("text_neq"),
SampleArrays.Int4Array.LT(int32Array).IS_TRUE().AS("int4_lt"),
SampleArrays.Int8Array.LT_EQ(int64Array).IS_FALSE().AS("int8_lteq"),
SampleArrays.RealArray.GT(float32Array).AS("decimal_gt"),
SampleArrays.DoubleArray.GT_EQ(float64Array).AS("numeric_gt_eq"),
SampleArrays.ByteaArray.CONTAINS(byteaArray).AS("bytea_contains"),
byteaArray.IS_CONTAINED_BY(SampleArrays.ByteaArray).AS("bytea_contained_by"),
SampleArrays.DateArray.OVERLAP(dateArray2).AS("date_overlaps"),
SampleArrays.TimestampArray.CONCAT(timestampArray).AS("timestamp_concat"),
timestampzArray2.CONCAT_ELEMENT(timestampz).AS("timestampz_concat_elem"),
SampleArrays.TimeArray.AT(Int32(1)).AS("time_at"),
Int32(22).EQ(ANY(SampleArrays.Int4Array)).AS("int32_eq_any"),
Double(7.89).NOT_EQ(ANY(SampleArrays.DoubleArray)).AS("double_neq_any"),
String("temp").EQ(ALL(stringArray)).AS("string_eq_all"),
// functions
ARRAY_APPEND(SampleArrays.TextArray, String("after")).AS("append"),
ARRAY_CAT(SampleArrays.TimeArray, timeArray2).AS("cat"),
ARRAY_LENGTH(timezArray2, Int32(1)).AS("length"),
// ARRAY_LOWER(SampleArrays.UUIDArray).AS("lower"), //newer postgres versions
ARRAY_POSITIONS(stringArray, String("text")).AS("position"),
ARRAY_PREPEND(String("before"), SampleArrays.TextArray).AS("prepend"),
ARRAY_REMOVE(boolArray, Bool(true)).AS("remove"),
ARRAY_REPLACE(SampleArrays.VarcharArray, String("hello"), String("hi")).AS("replace"),
//ARRAY_REVERSE(SampleArrays.TextArray).AS("reverse"),
//ARRAY_SAMPLE(SampleArrays.TimestampArray, Int(2)).AS("sample"),
//ARRAY_SHUFFLE(SampleArrays.BoolArray).AS("shuffle"),
//ARRAY_SORT(SampleArrays.Int8Array, Bool(true)),
ARRAY_TO_STRING(SampleArrays.MoodEnumArray, String(", ")).AS("to_string"),
ARRAY_UPPER(SampleArrays.Int8Array, Int(1)).AS("upper"),
CARDINALITY(SampleArrays.DoubleArray).AS("cardinality"),
// unsupported by cockroachdb
//ARRAY_DIMS(SampleArrays.IntervalArray).AS("dims"),
//ARRAY_NDIMS(SampleArrays.TextArray).AS("ndims"),
//TRIM_ARRAY(SampleArrays.DateArray, Int(1)).AS("trim"),
).FROM(
SampleArrays,
).WHERE(
SampleArrays.BoolArray.CONTAINS(BoolArray(true)),
)
testutils.AssertStatementSql(t, query, `
SELECT $1::boolean[] AS "bool_array",
$2::integer[] AS "int32_array",
$3::bigint[] AS "int64_array",
$4::real[] AS "float32_array",
$5::double precision[] AS "float64_array",
$6::text[] AS "string_array",
$7::bytea[] AS "bytea_array",
$8::date[] AS "date_array",
$9::timestamp without time zone[] AS "timestamp_array",
$10::timestamp with time zone[] AS "timestampz_array",
$11::time without time zone[] AS "time_array",
$12::time with time zone[] AS "timez_array",
(sample_arrays.bool_array = $13::boolean[]) AS "bool_eq",
(sample_arrays.text_array = sample_arrays.text_array) AS "text_eq",
(sample_arrays.text_array != $14::text[]) AS "text_neq",
(sample_arrays.int4_array < $15::integer[]) IS TRUE AS "int4_lt",
(sample_arrays.int8_array <= $16::bigint[]) IS FALSE AS "int8_lteq",
(sample_arrays.real_array > $17::real[]) AS "decimal_gt",
(sample_arrays.double_array >= $18::double precision[]) AS "numeric_gt_eq",
(sample_arrays.bytea_array @> $19::bytea[]) AS "bytea_contains",
($20::bytea[] <@ sample_arrays.bytea_array) AS "bytea_contained_by",
(sample_arrays.date_array && ARRAY[$21::date,$22::date]) AS "date_overlaps",
(sample_arrays.timestamp_array || $23::timestamp without time zone[]) AS "timestamp_concat",
(ARRAY[$24::timestamp with time zone] || $25::timestamp with time zone) AS "timestampz_concat_elem",
sample_arrays.time_array[$26::integer] AS "time_at",
($27::integer = ANY(sample_arrays.int4_array)) AS "int32_eq_any",
($28::double precision != ANY(sample_arrays.double_array)) AS "double_neq_any",
($29::text = ALL($30::text[])) AS "string_eq_all",
ARRAY_APPEND(sample_arrays.text_array, $31::text) AS "append",
ARRAY_CAT(sample_arrays.time_array, ARRAY[$32::time without time zone,$33::time without time zone]) AS "cat",
ARRAY_LENGTH(ARRAY[$34::time with time zone,$35::time with time zone], $36::integer) AS "length",
ARRAY_POSITIONS($37::text[], $38::text) AS "position",
ARRAY_PREPEND($39::text, sample_arrays.text_array) AS "prepend",
ARRAY_REMOVE($40::boolean[], $41::boolean) AS "remove",
ARRAY_REPLACE(sample_arrays.varchar_array, $42::text, $43::text) AS "replace",
ARRAY_TO_STRING(sample_arrays.mood_enum_array, $44::text) AS "to_string",
ARRAY_UPPER(sample_arrays.int8_array, $45) AS "upper",
CARDINALITY(sample_arrays.double_array) AS "cardinality"
FROM test_sample.sample_arrays
WHERE sample_arrays.bool_array @> $46::boolean[];
`)
var dest struct {
// array constructors
BoolArray pq.BoolArray
Int32Array pq.Int32Array
Int64Array pq.Int64Array
Float32Array pq.Float32Array
Float64Array pq.Float64Array
StringArray pq.StringArray
ByteaArray pq.ByteaArray
DateArray pq.StringArray
TimestampArray pq.StringArray
TimestampzArray pq.StringArray
TimeArray pq.StringArray
TimezArray pq.StringArray
// array operators
TextEq bool
BoolEq bool
TextNeq bool
Int4Lt bool
Int8Lteq bool
DecimalGt bool
NumericGtEq bool
ByteaContains bool
ByteaContainedBy bool
DateOverlaps bool
TimestampConcat pq.StringArray
TimestampzConcatElem pq.StringArray
TimeAt time.Time
Int32EqAny bool
DoubleNeqAny bool
StringEqAll bool
// functions
Append pq.StringArray
Cat pq.StringArray
Dims string
Length int32
Lower int32
NDims int32
Position pq.Int32Array
Prepend pq.StringArray
Remove pq.BoolArray
Replace pq.StringArray
ToString string
Upper int32
Cardinality int32
Trim pq.StringArray
}
err := query.Query(db, &dest)
require.NoError(t, err)
testutils.AssertJSON(t, dest, `
{
"BoolArray": [
true,
false,
false,
true
],
"Int32Array": [
-1,
2,
-3,
4,
5
],
"Int64Array": [
10,
-11,
12,
-13,
14,
1515551
],
"Float32Array": [
1.01,
-2.02,
3.03,
4.04
],
"Float64Array": [
10.001,
20.002,
-3.003,
400050.04
],
"StringArray": [
"temp",
"text",
"array"
],
"ByteaArray": [
"dGVtcG9yYWw=",
"Ynl0ZSBhcnJheQ==",
"YXJyYXk="
],
"DateArray": [
"2022-04-06",
"2018-05-06"
],
"TimestampArray": [
"1999-01-08 04:05:06"
],
"TimestampzArray": [
"2022-01-01 08:30:50+00"
],
"TimeArray": [
"14:20:45",
"08:10:15"
],
"TimezArray": [
"04:05:06-08",
"01:02:03-06"
],
"TextEq": true,
"BoolEq": false,
"TextNeq": true,
"Int4Lt": false,
"Int8Lteq": true,
"DecimalGt": true,
"NumericGtEq": true,
"ByteaContains": false,
"ByteaContainedBy": false,
"DateOverlaps": false,
"TimestampConcat": [
"2025-01-01 10:00:00",
"2025-02-01 10:00:00",
"1999-01-08 04:05:06"
],
"TimestampzConcatElem": [
"2023-02-03 10:29:34.000001+00",
"1950-02-03 10:30:40+00"
],
"TimeAt": "0000-01-01T12:00:00Z",
"Int32EqAny": false,
"DoubleNeqAny": true,
"StringEqAll": false,
"Append": [
"alpha",
"beta",
"gama",
"after"
],
"Cat": [
"12:00:00",
"13:00:00",
"10:20:30",
"05:45:45"
],
"Dims": "",
"Length": 2,
"Lower": 0,
"NDims": 0,
"Position": [
2
],
"Prepend": [
"before",
"alpha",
"beta",
"gama"
],
"Remove": [
false,
false
],
"Replace": [
"hi",
"world"
],
"ToString": "happy, ok",
"Upper": 4,
"Cardinality": 3,
"Trim": null
}
`)
requireLogged(t, query)
}
func TestArraySelectColumnsFromSubQuery(t *testing.T) {
subQuery := SELECT(
SampleArrays.AllColumns,
Int64Array(10, -11, 12, -13, 14, 1515551).AS("int64_array"),
).FROM(
SampleArrays,
).AsTable("sub_query")
int64Array := IntegerArrayColumn("int64_array").From(subQuery)
stmt := SELECT(
subQuery.AllColumns().Except(int64Array),
int64Array,
).FROM(
subQuery,
)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT sub_query."sample_arrays.id" AS "sample_arrays.id",
sub_query."sample_arrays.bool_array" AS "sample_arrays.bool_array",
sub_query."sample_arrays.int2_array_ptr" AS "sample_arrays.int2_array_ptr",
sub_query."sample_arrays.int4_array" AS "sample_arrays.int4_array",
sub_query."sample_arrays.int8_array" AS "sample_arrays.int8_array",
sub_query."sample_arrays.numeric_array" AS "sample_arrays.numeric_array",
sub_query."sample_arrays.decimal_array" AS "sample_arrays.decimal_array",
sub_query."sample_arrays.real_array" AS "sample_arrays.real_array",
sub_query."sample_arrays.double_array" AS "sample_arrays.double_array",
sub_query."sample_arrays.text_array" AS "sample_arrays.text_array",
sub_query."sample_arrays.varchar_array" AS "sample_arrays.varchar_array",
sub_query."sample_arrays.char_array" AS "sample_arrays.char_array",
sub_query."sample_arrays.bytea_array" AS "sample_arrays.bytea_array",
sub_query."sample_arrays.date_array" AS "sample_arrays.date_array",
sub_query."sample_arrays.timestamp_array" AS "sample_arrays.timestamp_array",
sub_query."sample_arrays.timestamptz_array" AS "sample_arrays.timestamptz_array",
sub_query."sample_arrays.time_array" AS "sample_arrays.time_array",
sub_query."sample_arrays.timetz_array" AS "sample_arrays.timetz_array",
sub_query."sample_arrays.interval_array" AS "sample_arrays.interval_array",
sub_query."sample_arrays.uuid_array" AS "sample_arrays.uuid_array",
sub_query."sample_arrays.mood_enum_array" AS "sample_arrays.mood_enum_array",
sub_query.int64_array AS "int64_array"
FROM (
SELECT sample_arrays.id AS "sample_arrays.id",
sample_arrays.bool_array AS "sample_arrays.bool_array",
sample_arrays.int2_array_ptr AS "sample_arrays.int2_array_ptr",
sample_arrays.int4_array AS "sample_arrays.int4_array",
sample_arrays.int8_array AS "sample_arrays.int8_array",
sample_arrays.numeric_array AS "sample_arrays.numeric_array",
sample_arrays.decimal_array AS "sample_arrays.decimal_array",
sample_arrays.real_array AS "sample_arrays.real_array",
sample_arrays.double_array AS "sample_arrays.double_array",
sample_arrays.text_array AS "sample_arrays.text_array",
sample_arrays.varchar_array AS "sample_arrays.varchar_array",
sample_arrays.char_array AS "sample_arrays.char_array",
sample_arrays.bytea_array AS "sample_arrays.bytea_array",
sample_arrays.date_array AS "sample_arrays.date_array",
sample_arrays.timestamp_array AS "sample_arrays.timestamp_array",
sample_arrays.timestamptz_array AS "sample_arrays.timestamptz_array",
sample_arrays.time_array AS "sample_arrays.time_array",
sample_arrays.timetz_array AS "sample_arrays.timetz_array",
sample_arrays.interval_array AS "sample_arrays.interval_array",
sample_arrays.uuid_array AS "sample_arrays.uuid_array",
sample_arrays.mood_enum_array AS "sample_arrays.mood_enum_array",
'{10,-11,12,-13,14,1515551}'::bigint[] AS "int64_array"
FROM test_sample.sample_arrays
) AS sub_query;
`)
var dest struct {
model.SampleArrays
Int64Array pq.Int64Array
}
err := stmt.Query(db, &dest)
require.NoError(t, err)
testutils.AssertDeepEqual(t, dest.SampleArrays, sampleArrayRow0)
testutils.AssertDeepEqual(t, dest.Int64Array, pq.Int64Array{10, -11, 12, -13, 14, 1515551})
}
func TestArrayTableInsert(t *testing.T) {
sampleArrayRow3 := testutils.DeepCopy(t, sampleArrayRow0)
sampleArrayRow3.ID = 3
insertQuery := SampleArrays.INSERT(SampleArrays.AllColumns).
VALUES(
Int64(2),
ARRAY(Bool(false), Bool(false), Bool(true)),
ARRAY(Int16(4), Int16(5), Int(6)),
Int32Array(40, 50, 60),
Int64Array(400, 500, 600),
ARRAY(Decimal("1.11"), Decimal("2.22")),
ARRAY(Decimal("1.11"), Decimal("2.22")),
Float32Array(4.4, 5.5, 6.6, 7.7),
Float64Array(40.04, 50.05, 60.06, 70.07),
StringArray("john", "doe"),
ARRAY(VarChar(10)("Andy"), VarChar(10)("Bob")),
ARRAY(Char(1)("q"), Char(1)("w"), Char(1)("e")),
ByteaArray([]byte("title"), []byte("name")),
ARRAY(Date(2010, 2, 3), Date(2025, 4, 5)),
ARRAY(Timestamp(2025, 2, 3, 0, 10, 20, 0)),
ARRAY(Timestampz(2025, 2, 3, 0, 10, 20, 0, "UTC")),
ARRAY(Time(12, 15, 45), Time(2, 30, 40)),
ARRAY(Timez(12, 15, 45, 0, "UTC"), Timez(2, 30, 40, 0, "UTC")),
ARRAY(INTERVAL(1, DAY, 3, MINUTE), INTERVAL(2, YEAR, 30, DAY)),
ARRAY(UUID(uuid.MustParse("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"))),
CAST(ARRAY(enum.Mood.Happy, enum.Mood.Sad)).AS("test_sample.mood[]"),
).
MODEL(
sampleArrayRow3,
).
RETURNING(SampleArrays.AllColumns)
testutils.AssertStatementSql(t, insertQuery, `
INSERT INTO test_sample.sample_arrays (id, bool_array, int2_array_ptr, int4_array, int8_array, numeric_array, decimal_array, real_array, double_array, text_array, varchar_array, char_array, bytea_array, date_array, timestamp_array, timestamptz_array, time_array, timetz_array, interval_array, uuid_array, mood_enum_array)
VALUES ($1::bigint, ARRAY[$2::boolean,$3::boolean,$4::boolean], ARRAY[$5::smallint,$6::smallint,$7], $8::integer[], $9::bigint[], ARRAY[$10::decimal,$11::decimal], ARRAY[$12::decimal,$13::decimal], $14::real[], $15::double precision[], $16::text[], ARRAY[$17::varchar(10),$18::varchar(10)], ARRAY[$19::char(1),$20::char(1),$21::char(1)], $22::bytea[], ARRAY[$23::date,$24::date], ARRAY[$25::timestamp without time zone], ARRAY[$26::timestamp with time zone], ARRAY[$27::time without time zone,$28::time without time zone], ARRAY[$29::time with time zone,$30::time with time zone], ARRAY[INTERVAL '1 DAY 3 MINUTE',INTERVAL '2 YEAR 30 DAY'], ARRAY[$31::uuid], ARRAY['happy','sad']::test_sample.mood[]),
($32, $33, $34, $35, $36, $37, $38, $39, $40, $41, $42, $43, $44, $45, $46, $47, $48, $49, $50, $51, $52)
RETURNING sample_arrays.id AS "sample_arrays.id",
sample_arrays.bool_array AS "sample_arrays.bool_array",
sample_arrays.int2_array_ptr AS "sample_arrays.int2_array_ptr",
sample_arrays.int4_array AS "sample_arrays.int4_array",
sample_arrays.int8_array AS "sample_arrays.int8_array",
sample_arrays.numeric_array AS "sample_arrays.numeric_array",
sample_arrays.decimal_array AS "sample_arrays.decimal_array",
sample_arrays.real_array AS "sample_arrays.real_array",
sample_arrays.double_array AS "sample_arrays.double_array",
sample_arrays.text_array AS "sample_arrays.text_array",
sample_arrays.varchar_array AS "sample_arrays.varchar_array",
sample_arrays.char_array AS "sample_arrays.char_array",
sample_arrays.bytea_array AS "sample_arrays.bytea_array",
sample_arrays.date_array AS "sample_arrays.date_array",
sample_arrays.timestamp_array AS "sample_arrays.timestamp_array",
sample_arrays.timestamptz_array AS "sample_arrays.timestamptz_array",
sample_arrays.time_array AS "sample_arrays.time_array",
sample_arrays.timetz_array AS "sample_arrays.timetz_array",
sample_arrays.interval_array AS "sample_arrays.interval_array",
sample_arrays.uuid_array AS "sample_arrays.uuid_array",
sample_arrays.mood_enum_array AS "sample_arrays.mood_enum_array";
`)
testutils.ExecuteInTxAndRollback(t, db, func(tx qrm.DB) {
var dest []model.SampleArrays
err := insertQuery.Query(tx, &dest)
require.NoError(t, err)
require.Len(t, dest, 2)
testutils.AssertDeepEqual(t, sampleArrayRow3, dest[1])
testutils.AssertJSON(t, dest[0], `
{
"ID": 2,
"BoolArray": [
false,
false,
true
],
"Int2ArrayPtr": [
"4",
"5",
"6"
],
"Int4Array": [
40,
50,
60
],
"Int8Array": [
400,
500,
600
],
"NumericArray": [
1.11,
2.22
],
"DecimalArray": [
1.11,
2.22
],
"RealArray": [
4.4,
5.5,
6.6,
7.7
],
"DoubleArray": [
40.04,
50.05,
60.06,
70.07
],
"TextArray": [
"john",
"doe"
],
"VarcharArray": [
"Andy",
"Bob"
],
"CharArray": [
"q",
"w",
"e"
],
"ByteaArray": [
"dGl0bGU=",
"bmFtZQ=="
],
"DateArray": [
"2010-02-03",
"2025-04-05"
],
"TimestampArray": [
"2025-02-03 00:10:20"
],
"TimestamptzArray": [
"2025-02-03 00:10:20+00"
],
"TimeArray": [
"12:15:45",
"02:30:40"
],
"TimetzArray": [
"12:15:45+00",
"02:30:40+00"
],
"IntervalArray": [
"1 day 00:03:00",
"2 years 30 days"
],
"UUIDArray": [
"a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"
],
"MoodEnumArray": [
"happy",
"sad"
]
}
`)
})
}
func TestArrayTableUpdate(t *testing.T) {
t.Run("using model", func(t *testing.T) {
sampleArrayRow1Clone := testutils.DeepCopy(t, sampleArrayRow0)
sampleArrayRow1Clone.RealArray = pq.Float32Array{100.11, 200.22, 300.33}
stmt := SampleArrays.UPDATE(SampleArrays.MutableColumns).
MODEL(sampleArrayRow1Clone).
WHERE(String("alpha").EQ(ANY(SampleArrays.TextArray))).
RETURNING(SampleArrays.AllColumns)
testutils.AssertDebugStatementSql(t, stmt, `
UPDATE test_sample.sample_arrays
SET (bool_array, int2_array_ptr, int4_array, int8_array, numeric_array, decimal_array, real_array, double_array, text_array, varchar_array, char_array, bytea_array, date_array, timestamp_array, timestamptz_array, time_array, timetz_array, interval_array, uuid_array, mood_enum_array) = ('{t,f,t}', '{"1","2","3","4"}', '{10,20,30,40}', '{100,200,300,400}', '{1.8881,2.8882,3.8883,4.8884}', '{1.0001,2.0002,3.0003,4.0004}', '{100.11,200.22,300.33}', '{11.11,22.22,33.33}', '{"alpha","beta","gama"}', '{"hello","world"}', '{"a","b","c"}', '{"\\x01020304","\\x11223344"}', '{"2024-11-01","2025-02-28"}', '{"2025-01-01 10:00:00","2025-02-01 10:00:00"}', '{"2025-01-01 09:00:00+00","2025-02-01 09:00:00+00"}', '{"12:00:00","13:00:00"}', '{"12:00:00+01","13:00:00+02"}', '{"1 day","02:00:00"}', '{"550e8400-e29b-41d4-a716-446655440000"}', '{"happy","ok"}')
WHERE 'alpha'::text = ANY(sample_arrays.text_array)
RETURNING sample_arrays.id AS "sample_arrays.id",
sample_arrays.bool_array AS "sample_arrays.bool_array",
sample_arrays.int2_array_ptr AS "sample_arrays.int2_array_ptr",
sample_arrays.int4_array AS "sample_arrays.int4_array",
sample_arrays.int8_array AS "sample_arrays.int8_array",
sample_arrays.numeric_array AS "sample_arrays.numeric_array",
sample_arrays.decimal_array AS "sample_arrays.decimal_array",
sample_arrays.real_array AS "sample_arrays.real_array",
sample_arrays.double_array AS "sample_arrays.double_array",
sample_arrays.text_array AS "sample_arrays.text_array",
sample_arrays.varchar_array AS "sample_arrays.varchar_array",
sample_arrays.char_array AS "sample_arrays.char_array",
sample_arrays.bytea_array AS "sample_arrays.bytea_array",
sample_arrays.date_array AS "sample_arrays.date_array",
sample_arrays.timestamp_array AS "sample_arrays.timestamp_array",
sample_arrays.timestamptz_array AS "sample_arrays.timestamptz_array",
sample_arrays.time_array AS "sample_arrays.time_array",
sample_arrays.timetz_array AS "sample_arrays.timetz_array",
sample_arrays.interval_array AS "sample_arrays.interval_array",
sample_arrays.uuid_array AS "sample_arrays.uuid_array",
sample_arrays.mood_enum_array AS "sample_arrays.mood_enum_array";
`)
testutils.ExecuteInTxAndRollback(t, db, func(tx qrm.DB) {
var dest []model.SampleArrays
err := stmt.Query(tx, &dest)
require.NoError(t, err)
require.Len(t, dest, 1)
testutils.AssertDeepEqual(t, sampleArrayRow1Clone, dest[0])
})
})
t.Run("update using SET", func(t *testing.T) {
stmt := SampleArrays.UPDATE().
SET(
SampleArrays.Int4Array.SET(ARRAY(Int32(-10), Int32(11))),
SampleArrays.Int8Array.SET(ARRAY(Int64(-1200), Int64(7800))),
).
WHERE(String("alpha").EQ(ANY(SampleArrays.TextArray))).
RETURNING(
SampleArrays.Int4Array,
SampleArrays.Int8Array,
)
testutils.AssertStatementSql(t, stmt, `
UPDATE test_sample.sample_arrays
SET int4_array = ARRAY[$1::integer,$2::integer],
int8_array = ARRAY[$3::bigint,$4::bigint]
WHERE $5::text = ANY(sample_arrays.text_array)
RETURNING sample_arrays.int4_array AS "sample_arrays.int4_array",
sample_arrays.int8_array AS "sample_arrays.int8_array";
`)
testutils.ExecuteInTxAndRollback(t, db, func(tx qrm.DB) {
var dest []model.SampleArrays
err := stmt.Query(tx, &dest)
require.NoError(t, err)
require.Len(t, dest, 1)
testutils.AssertDeepEqual(t, dest[0].Int4Array, pq.Int32Array{-10, 11})
testutils.AssertDeepEqual(t, dest[0].Int8Array, pq.Int64Array{-1200, 7800})
})
})
}
var sampleArrayRow0 = model.SampleArrays{
ID: 1,
BoolArray: ptr.Of(pq.BoolArray{true, false, true}),
Int2ArrayPtr: ptr.Of(pq.StringArray{"1", "2", "3", "4"}),
Int4Array: pq.Int32Array{10, 20, 30, 40},
Int8Array: pq.Int64Array{100, 200, 300, 400},
NumericArray: pq.Float64Array{1.8881, 2.8882, 3.8883, 4.8884},
DecimalArray: pq.Float64Array{1.0001, 2.0002, 3.0003, 4.0004},
RealArray: pq.Float32Array{1.0099999904632568, 2.0199999809265137, 3.0299999713897705, 4.039999961853027},
DoubleArray: pq.Float64Array{11.11, 22.22, 33.33},
TextArray: pq.StringArray{"alpha", "beta", "gama"},
CharArray: pq.StringArray{"a", "b", "c"},
VarcharArray: pq.StringArray{"hello", "world"},
ByteaArray: pq.ByteaArray{{0x01, 0x02, 0x03, 0x04}, {0x11, 0x22, 0x33, 0x44}},
DateArray: pq.StringArray{"2024-11-01", "2025-02-28"},
TimestampArray: &pq.StringArray{"2025-01-01 10:00:00", "2025-02-01 10:00:00"},
TimestamptzArray: pq.StringArray{"2025-01-01 09:00:00+00", "2025-02-01 09:00:00+00"},
TimeArray: pq.StringArray{"12:00:00", "13:00:00"},
TimetzArray: pq.StringArray{"12:00:00+01", "13:00:00+02"},
IntervalArray: pq.StringArray{"1 day", "02:00:00"},
UUIDArray: pq.StringArray{"550e8400-e29b-41d4-a716-446655440000"},
MoodEnumArray: pq.StringArray{"happy", "ok"},
}

View file

@ -450,7 +450,7 @@ func TestGeneratorTemplate_Model_ChangeFieldTypes(t *testing.T) {
require.Contains(t, data, `"github.com/google/uuid"`)
require.Contains(t, data, "Description sql.NullString")
require.Contains(t, data, "ReleaseYear sql.NullInt32")
require.Contains(t, data, "SpecialFeatures sql.NullString")
require.Contains(t, data, "SpecialFeatures *pq.StringArray")
require.Contains(t, data, "LastUpdate sql.Null[uuid.UUID]")
}

View file

@ -319,7 +319,7 @@ func TestGenerator_TableMetadata(t *testing.T) {
},
}
require.Equal(t, want, got)
require.Equal(t, metadata.ArrayType, specialFeatures.DataType.Kind)
require.Equal(t, 1, specialFeatures.DataType.Dimensions)
}
func TestGeneratorSpecialCharacters(t *testing.T) {
@ -765,13 +765,13 @@ func TestGeneratedAllTypesSQLBuilderFiles(t *testing.T) {
testutils.AssertFileNamesEqual(t, modelDir, "all_types.go", "all_types_view.go", "employee.go", "link.go",
"mood.go", "person.go", "person_phone.go", "weird_names_table.go", "level.go", "user.go", "floats.go", "people.go",
"components.go", "vulnerabilities.go", "all_types_materialized_view.go", "sample_ranges.go")
"components.go", "vulnerabilities.go", "all_types_materialized_view.go", "sample_ranges.go", "sample_arrays.go")
testutils.AssertFileContent(t, modelDir+"/all_types.go", allTypesModelContent)
testutils.AssertFileContent(t, modelDir+"/link.go", linkModelContent)
testutils.AssertFileNamesEqual(t, tableDir, "all_types.go", "employee.go", "link.go",
"person.go", "person_phone.go", "weird_names_table.go", "user.go", "floats.go", "people.go", "table_use_schema.go",
"components.go", "vulnerabilities.go", "sample_ranges.go")
"components.go", "vulnerabilities.go", "sample_ranges.go", "sample_arrays.go")
testutils.AssertFileContent(t, tableDir+"/all_types.go", allTypesTableContent)
testutils.AssertFileContent(t, tableDir+"/sample_ranges.go", sampleRangeTableContent)

View file

@ -53,8 +53,8 @@ func TestRangeTableSelect(t *testing.T) {
table.SampleRanges.TimestampzRange.DIFFERENCE(tstzRange).AS("sample.tstz_diff"),
table.SampleRanges.Int4Range.UPPER_BOUND().ADD(Int(5)).AS("sample.int4_upper"),
table.SampleRanges.Int8Range.LOWER_BOUND().SUB(Int(12)).AS("sample.int8_lower"),
LOWER_BOUND[DateExpression](table.SampleRanges.DateRange),
UPPER_BOUND[NumericExpression](table.SampleRanges.NumRange).AS("sample.num_upper"),
LOWER_BOUND(table.SampleRanges.DateRange),
UPPER_BOUND(table.SampleRanges.NumRange).AS("sample.num_upper"),
table.SampleRanges.TimestampRange.UPPER_BOUND(),
table.SampleRanges.DateRange.IS_EMPTY().AS("sample.date_empty"),
table.SampleRanges.TimestampRange.LOWER_INC().AS("sample.ts_low_inc"),

View file

@ -2,8 +2,8 @@ package postgres
import (
"context"
"github.com/lib/pq"
"github.com/go-jet/jet/v2/internal/utils/ptr"
"github.com/lib/pq"
"github.com/volatiletech/null/v8"
"testing"
"time"
@ -1007,7 +1007,6 @@ func TestScanIntoCustomBaseTypes(t *testing.T) {
type MyFloat32 float32
type MyFloat64 float64
type MyString string
type MyStringArray pq.StringArray
type MyTime = time.Time
type film struct {
@ -1022,13 +1021,12 @@ func TestScanIntoCustomBaseTypes(t *testing.T) {
ReplacementCost MyFloat64
Rating *model.MpaaRating
LastUpdate MyTime
SpecialFeatures MyStringArray
SpecialFeatures pq.StringArray
Fulltext MyString
}
// We'll skip special features, because it's a slice and it does not implement sql.Scanner
stmt := SELECT(
Film.AllColumns.Except(Film.SpecialFeatures),
Film.AllColumns,
).FROM(
Film,
).ORDER_BY(

View file

@ -358,8 +358,7 @@ func TestSelectQuickStartJSON(t *testing.T) {
Actor.ActorID, Actor.FirstName, Actor.LastName, Actor.LastUpdate,
SELECT_JSON_ARR(
Film.AllColumns.Except(Film.SpecialFeatures),
CAST(Film.SpecialFeatures).AS_TEXT().AS("SpecialFeatures"),
Film.AllColumns,
SELECT_JSON_OBJ(
Language.AllColumns,
@ -385,7 +384,11 @@ func TestSelectQuickStartJSON(t *testing.T) {
Film.
INNER_JOIN(FilmActor, FilmActor.FilmID.EQ(Film.FilmID)),
).WHERE(
FilmActor.ActorID.EQ(Actor.ActorID).AND(Film.Length.GT(Int32(180))),
AND(
FilmActor.ActorID.EQ(Actor.ActorID),
Film.Length.GT(Int32(180)),
String("Trailers").EQ(ANY(Film.SpecialFeatures)),
),
).ORDER_BY(
Film.FilmID.ASC(),
).AS("Films"),
@ -416,8 +419,8 @@ FROM (
film.replacement_cost AS "replacementCost",
film.rating AS "rating",
to_char(film.last_update, 'YYYY-MM-DD"T"HH24:MI:SS.USZ') AS "lastUpdate",
film.special_features AS "specialFeatures",
film.fulltext AS "fulltext",
film.special_features::text AS "SpecialFeatures",
(
SELECT row_to_json(language_records) AS "language_json"
FROM (
@ -441,7 +444,11 @@ FROM (
) AS "Categories"
FROM dvds.film
INNER JOIN dvds.film_actor ON (film_actor.film_id = film.film_id)
WHERE (film_actor.actor_id = actor.actor_id) AND (film.length > 180::integer)
WHERE (
(film_actor.actor_id = actor.actor_id)
AND (film.length > 180::integer)
AND ('Trailers'::text = ANY(film.special_features))
)
ORDER BY film.film_id ASC
) AS films_records
) AS "Films"
@ -469,8 +476,8 @@ FROM (
return // char[n] columns whitespaces are trimmed when returned as json in cockroachdb
}
//testutils.SaveJSONFile(dest, "./testdata/results/postgres/quick-start-json-dest2.json")
//testutils.AssertJSONFile(t, dest, "./testdata/results/postgres/quick-start-json-dest.json")
//testutils.SaveJSONFile(dest, "./testdata/results/postgres/quick-start-json-dest.json")
testutils.AssertJSONFile(t, dest, "./testdata/results/postgres/quick-start-json-dest.json")
}
func TestSelectJsonInReturning(t *testing.T) {

View file

@ -2710,7 +2710,32 @@ FOR UPDATE OF "myFilm";
func TestSelectQuickStart(t *testing.T) {
var expectedSQL = `
stmt := SELECT(
Actor.ActorID, Actor.FirstName, Actor.LastName, Actor.LastUpdate, // list of all actor columns (equivalent to Actor.AllColumns)
Film.AllColumns, // list of all film columns (equivalent to Film.FilmID, Film.Title, ...)
Language.AllColumns.Except(Language.LastUpdate),
Category.AllColumns,
).FROM(
Actor.
INNER_JOIN(FilmActor, Actor.ActorID.EQ(FilmActor.ActorID)). // INNER JOIN Actor with FilmActor on condition Actor.ActorID = FilmActor.ActorID
INNER_JOIN(Film, Film.FilmID.EQ(FilmActor.FilmID)). // then with Film, Language, FilmCategory and Category.
INNER_JOIN(Language, Language.LanguageID.EQ(Film.LanguageID)).
INNER_JOIN(FilmCategory, FilmCategory.FilmID.EQ(Film.FilmID)).
INNER_JOIN(Category, Category.CategoryID.EQ(FilmCategory.CategoryID)),
).WHERE(
AND(
Language.Name.EQ(Char(20)("English")), // String column Language.Name and Category.Name can be compared only with string expression
Category.Name.NOT_EQ(Text("Action")),
Film.Length.GT(Int32(180)), // Film.Length is integer column and can be compared only with integer expression
Film.Rating.NOT_EQ(enum.MpaaRating.R),
String("Trailers").EQ(ANY(Film.SpecialFeatures)), // arrays element type safety is also enforced
),
).ORDER_BY(
Actor.ActorID.ASC(),
Film.FilmID.ASC(),
)
testutils.AssertStatementSql(t, stmt, `
SELECT actor.actor_id AS "actor.actor_id",
actor.first_name AS "actor.first_name",
actor.last_name AS "actor.last_name",
@ -2730,7 +2755,6 @@ SELECT actor.actor_id AS "actor.actor_id",
film.fulltext AS "film.fulltext",
language.language_id AS "language.language_id",
language.name AS "language.name",
language.last_update AS "language.last_update",
category.category_id AS "category.category_id",
category.name AS "category.name",
category.last_update AS "category.last_update"
@ -2740,33 +2764,54 @@ FROM dvds.actor
INNER JOIN dvds.language ON (language.language_id = film.language_id)
INNER JOIN dvds.film_category ON (film_category.film_id = film.film_id)
INNER JOIN dvds.category ON (category.category_id = film_category.category_id)
WHERE (((language.name = 'English'::char(20)) AND (category.name != 'Action'::text)) AND (film.length > 180::integer)) AND (film.rating != 'R')
WHERE (
(language.name = $1::char(20))
AND (category.name != $2::text)
AND (film.length > $3::integer)
AND (film.rating != 'R')
AND ($4::text = ANY(film.special_features))
)
ORDER BY actor.actor_id ASC, film.film_id ASC;
`
`, "English", "Action", int32(180), "Trailers")
stmt := SELECT(
Actor.ActorID, Actor.FirstName, Actor.LastName, Actor.LastUpdate, // list of all actor columns (equivalent to Actor.AllColumns)
Film.AllColumns, // list of all film columns (equivalent to Film.FilmID, Film.Title, ...)
Language.AllColumns,
Category.AllColumns,
).FROM(
Actor.
INNER_JOIN(FilmActor, Actor.ActorID.EQ(FilmActor.ActorID)). // INNER JOIN Actor with FilmActor on condition Actor.ActorID = FilmActor.ActorID
INNER_JOIN(Film, Film.FilmID.EQ(FilmActor.FilmID)). // then with Film, Language, FilmCategory and Category.
INNER_JOIN(Language, Language.LanguageID.EQ(Film.LanguageID)).
INNER_JOIN(FilmCategory, FilmCategory.FilmID.EQ(Film.FilmID)).
INNER_JOIN(Category, Category.CategoryID.EQ(FilmCategory.CategoryID)),
).WHERE(
Language.Name.EQ(Char(20)("English")). // note that every column has type.
AND(Category.Name.NOT_EQ(Text("Action"))). // String column Language.Name and Category.Name can be compared only with string expression
AND(Film.Length.GT(Int32(180))). // Film.Length is integer column and can be compared only with integer expression
AND(Film.Rating.NOT_EQ(enum.MpaaRating.R)),
).ORDER_BY(
Actor.ActorID.ASC(),
Film.FilmID.ASC(),
)
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, "English", "Action", int32(180))
testutils.AssertDebugStatementSql(t, stmt, `
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",
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.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.last_update AS "film.last_update",
film.special_features AS "film.special_features",
film.fulltext AS "film.fulltext",
language.language_id AS "language.language_id",
language.name AS "language.name",
category.category_id AS "category.category_id",
category.name AS "category.name",
category.last_update AS "category.last_update"
FROM dvds.actor
INNER JOIN dvds.film_actor ON (actor.actor_id = film_actor.actor_id)
INNER JOIN dvds.film ON (film.film_id = film_actor.film_id)
INNER JOIN dvds.language ON (language.language_id = film.language_id)
INNER JOIN dvds.film_category ON (film_category.film_id = film.film_id)
INNER JOIN dvds.category ON (category.category_id = film_category.category_id)
WHERE (
(language.name = 'English'::char(20))
AND (category.name != 'Action'::text)
AND (film.length > 180::integer)
AND (film.rating != 'R')
AND ('Trailers'::text = ANY(film.special_features))
)
ORDER BY actor.actor_id ASC, film.film_id ASC;
`)
var dest []struct {
model.Actor
@ -2798,7 +2843,7 @@ ORDER BY actor.actor_id ASC, film.film_id ASC;
require.NoError(t, err)
})
//testutils.SaveJSONFile(dest, "./testdata/results/postgres/quick-start-dest2.json")
//testutils.SaveJSONFile(dest2, "./testdata/results/postgres/quick-start-dest2.json")
testutils.AssertJSONFile(t, dest2, "./testdata/results/postgres/quick-start-dest2.json")
}
@ -2806,7 +2851,11 @@ func TestSelectQuickStartWithSubQueries(t *testing.T) {
filmLogerThan180 := Film.
SELECT(Film.AllColumns).
WHERE(Film.Length.GT(Int(180)).AND(Film.Rating.NOT_EQ(enum.MpaaRating.R))).
WHERE(
Film.Length.GT(Int(180)).
AND(Film.Rating.NOT_EQ(enum.MpaaRating.R)).
AND(String("Trailers").EQ(ANY(Film.SpecialFeatures))),
).
AsTable("films")
filmID := Film.FilmID.From(filmLogerThan180)
@ -2822,7 +2871,7 @@ func TestSelectQuickStartWithSubQueries(t *testing.T) {
stmt := SELECT(
Actor.AllColumns,
filmLogerThan180.AllColumns(),
Language.AllColumns,
Language.AllColumns.Except(Language.LastUpdate),
categoriesNotAction.AllColumns(),
).FROM(
Actor.

View file

@ -172,7 +172,9 @@ ORDER BY film_values.title;
"ReplacementCost": 15.99,
"Rating": "R",
"LastUpdate": "2013-05-26T14:50:58.951Z",
"SpecialFeatures": "{Trailers}",
"SpecialFeatures": [
"Trailers"
],
"Fulltext": "'airport':1 'ancient':18 'confront':14 'epic':4 'girl':11 'india':19 'monkey':16 'moos':8 'must':13 'pollock':2 'tale':5"
},
"Title": "Airport Pollock",
@ -194,7 +196,9 @@ ORDER BY film_values.title;
"ReplacementCost": 12.99,
"Rating": "PG-13",
"LastUpdate": "2013-05-26T14:50:58.951Z",
"SpecialFeatures": "{Trailers}",
"SpecialFeatures": [
"Trailers"
],
"Fulltext": "'boat':20 'bright':1 'conquer':14 'encount':2 'fate':4 'feminist':11 'jet':19 'lumberjack':8 'must':13 'student':16 'yarn':5"
},
"Title": "Bright Encounters",

@ -1 +1 @@
Subproject commit 94f3504ef8245b8f76ca391f068705ba1375c03b
Subproject commit 0387785d9e9ceacba2247d477181436f27bf2068