jet/tests/postgres/array_test.go

728 lines
26 KiB
Go
Raw Normal View History

package postgres
import (
"testing"
"time"
"source.gleipnir.technology/Gleipnir/jet/v2/internal/testutils"
"source.gleipnir.technology/Gleipnir/jet/v2/internal/utils/ptr"
. "source.gleipnir.technology/Gleipnir/jet/v2/postgres"
"source.gleipnir.technology/Gleipnir/jet/v2/qrm"
"source.gleipnir.technology/Gleipnir/jet/v2/tests/.gentestdata/jetdb/test_sample/enum"
"source.gleipnir.technology/Gleipnir/jet/v2/tests/.gentestdata/jetdb/test_sample/model"
. "source.gleipnir.technology/Gleipnir/jet/v2/tests/.gentestdata/jetdb/test_sample/table"
"github.com/google/uuid"
"github.com/lib/pq"
"github.com/stretchr/testify/require"
)
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"),
2025-10-17 13:41:08 +02:00
// ARRAY_LOWER(SampleArrays.UUIDArray).AS("lower"),
ARRAY_POSITION(SampleArrays.Int4Array, Int32(30)).AS("position"),
2025-10-17 14:12:13 +02:00
//ARRAY_POSITION(SampleArrays.DoubleArray, Float(33.33), Int(1)).AS("position_from"),
2025-10-17 13:41:08 +02:00
ARRAY_POSITIONS(stringArray, String("text")).AS("positions"),
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",
2025-10-17 13:41:08 +02:00
ARRAY_POSITION(sample_arrays.int4_array, $37::integer) AS "position",
2025-10-17 14:12:13 +02:00
ARRAY_POSITIONS($38::text[], $39::text) AS "positions",
ARRAY_PREPEND($40::text, sample_arrays.text_array) AS "prepend",
ARRAY_REMOVE($41::boolean[], $42::boolean) AS "remove",
ARRAY_REPLACE(sample_arrays.varchar_array, $43::text, $44::text) AS "replace",
ARRAY_TO_STRING(sample_arrays.mood_enum_array, $45::text) AS "to_string",
ARRAY_UPPER(sample_arrays.int8_array, $46) AS "upper",
CARDINALITY(sample_arrays.double_array) AS "cardinality"
FROM test_sample.sample_arrays
2025-10-17 14:12:13 +02:00
WHERE sample_arrays.bool_array @> $47::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
2025-10-17 13:41:08 +02:00
Append pq.StringArray
Cat pq.StringArray
Dims string
Length int32
Lower int32
NDims int32
Position *int32
PositionFrom *int32
Positions 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,
2025-10-17 13:41:08 +02:00
"Position": 3,
2025-10-17 14:12:13 +02:00
"PositionFrom": null,
2025-10-17 13:41:08 +02:00
"Positions": [
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"},
}