Merge remote-tracking branch 'upstream/master' into stmt-cache2

# Conflicts:
#	tests/postgres/alltypes_test.go
#	tests/postgres/northwind_test.go
#	tests/postgres/sample_test.go
#	tests/postgres/update_test.go
#	tests/sqlite/insert_test.go
#	tests/sqlite/main_test.go
#	tests/sqlite/sample_test.go
#	tests/sqlite/update_test.go
This commit is contained in:
go-jet 2024-10-19 14:01:55 +02:00
commit 4bb9775134
97 changed files with 2306 additions and 537 deletions

View file

@ -6,6 +6,8 @@ setup: checkout-testdata docker-compose-up
checkout-testdata:
git submodule init
git submodule update
#
checkout-latest-testdata: checkout-testdata
cd ./testdata && git fetch && git checkout master && git pull
# docker-compose-up will download docker image for each of the databases listed in docker-compose.yaml file, and then it will initialize

View file

@ -13,7 +13,7 @@ services:
- ./testdata/init/postgres:/docker-entrypoint-initdb.d
mysql:
image: mysql:8.0.27
image: mysql:8.0
command: ['--default-authentication-plugin=mysql_native_password', '--log_bin_trust_function_creators=1']
restart: always
environment:

View file

@ -3,6 +3,7 @@ package main
import (
"context"
"database/sql"
"errors"
"flag"
"fmt"
"github.com/go-jet/jet/v2/generator/mysql"
@ -10,7 +11,6 @@ import (
"github.com/go-jet/jet/v2/generator/sqlite"
"github.com/go-jet/jet/v2/internal/utils/errfmt"
"github.com/go-jet/jet/v2/tests/internal/utils/repo"
"io/ioutil"
"os"
"os/exec"
"strings"
@ -125,7 +125,7 @@ func initMySQLDB(isMariaDB bool) error {
fmt.Println(cmdLine)
cmd := exec.Command("sh", "-c", cmdLine)
cmd := exec.Command("sh", "-c", cmdLine) // #nosec G204
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
@ -184,7 +184,7 @@ func initPostgresDB(dbType string, connectionString string) error {
}
func execFile(db *sql.DB, sqlFilePath string) error {
testSampleSql, err := ioutil.ReadFile(sqlFilePath)
testSampleSql, err := os.ReadFile(sqlFilePath) // #nosec G304
if err != nil {
return fmt.Errorf("failed to read sql file - %s: %w", sqlFilePath, err)
}
@ -211,7 +211,10 @@ func execInTx(db *sql.DB, f func(tx *sql.Tx) error) error {
err = f(tx)
if err != nil {
tx.Rollback()
rollBackError := tx.Rollback()
if rollBackError != nil {
return errors.Join(rollBackError, err)
}
return err
}

View file

@ -2,7 +2,6 @@ package file
import (
"github.com/stretchr/testify/require"
"io/ioutil"
"os"
"path"
"testing"
@ -11,7 +10,7 @@ import (
// Exists expects file to exist on path constructed from pathElems and returns content of the file
func Exists(t *testing.T, pathElems ...string) (fileContent string) {
modelFilePath := path.Join(pathElems...)
file, err := ioutil.ReadFile(modelFilePath)
file, err := os.ReadFile(modelFilePath) // #nosec G304
require.Nil(t, err)
require.NotEmpty(t, file)
return string(file)
@ -20,6 +19,6 @@ func Exists(t *testing.T, pathElems ...string) (fileContent string) {
// NotExists expects file not to exist on path constructed from pathElems
func NotExists(t *testing.T, pathElems ...string) {
modelFilePath := path.Join(pathElems...)
_, err := ioutil.ReadFile(modelFilePath)
_, err := os.ReadFile(modelFilePath) // #nosec G304
require.True(t, os.IsNotExist(err))
}

View file

@ -1,6 +1,7 @@
package mysql
import (
"github.com/go-jet/jet/v2/internal/utils/ptr"
"github.com/shopspring/decimal"
"github.com/stretchr/testify/require"
"strings"
@ -96,18 +97,18 @@ func TestExpressionOperators(t *testing.T) {
SELECT all_types.'integer' IS NULL AS "result.is_null",
all_types.date_ptr IS NOT NULL AS "result.is_not_null",
(all_types.small_int_ptr IN (?, ?)) AS "result.in",
(all_types.small_int_ptr IN (
(all_types.small_int_ptr IN ((
SELECT all_types.'integer' AS "all_types.integer"
FROM test_sample.all_types
)) AS "result.in_select",
))) AS "result.in_select",
(CURRENT_USER()) AS "result.raw",
(? + COALESCE(all_types.small_int_ptr, 0) + ?) AS "result.raw_arg",
(? + all_types.integer + ? + ? + ? + ?) AS "result.raw_arg2",
(all_types.small_int_ptr NOT IN (?, ?, NULL)) AS "result.not_in",
(all_types.small_int_ptr NOT IN (
(all_types.small_int_ptr NOT IN ((
SELECT all_types.'integer' AS "all_types.integer"
FROM test_sample.all_types
)) AS "result.not_in_select"
))) AS "result.not_in_select"
FROM test_sample.all_types
LIMIT ?;
`, "'", "`", -1), int64(11), int64(22), 78, 56, 11, 22, 11, 33, 44, int64(11), int64(22), int64(2))
@ -1067,7 +1068,7 @@ func TestAllTypesInsertOnDuplicateKeyUpdate(t *testing.T) {
var toInsert = model.AllTypes{
Boolean: false,
BooleanPtr: testutils.BoolPtr(true),
BooleanPtr: ptr.Of(true),
TinyInt: 1,
UTinyInt: 2,
SmallInt: 3,
@ -1078,53 +1079,53 @@ var toInsert = model.AllTypes{
UInteger: 8,
BigInt: 9,
UBigInt: 1122334455,
TinyIntPtr: testutils.Int8Ptr(11),
UTinyIntPtr: testutils.UInt8Ptr(22),
SmallIntPtr: testutils.Int16Ptr(33),
USmallIntPtr: testutils.UInt16Ptr(44),
MediumIntPtr: testutils.Int32Ptr(55),
UMediumIntPtr: testutils.UInt32Ptr(66),
IntegerPtr: testutils.Int32Ptr(77),
UIntegerPtr: testutils.UInt32Ptr(88),
BigIntPtr: testutils.Int64Ptr(99),
UBigIntPtr: testutils.UInt64Ptr(111),
TinyIntPtr: ptr.Of(int8(11)),
UTinyIntPtr: ptr.Of(uint8(22)),
SmallIntPtr: ptr.Of(int16(33)),
USmallIntPtr: ptr.Of(uint16(44)),
MediumIntPtr: ptr.Of(int32(55)),
UMediumIntPtr: ptr.Of(uint32(66)),
IntegerPtr: ptr.Of(int32(77)),
UIntegerPtr: ptr.Of(uint32(88)),
BigIntPtr: ptr.Of(int64(99)),
UBigIntPtr: ptr.Of(uint64(111)),
Decimal: 11.22,
DecimalPtr: testutils.Float64Ptr(33.44),
DecimalPtr: ptr.Of(33.44),
Numeric: 55.66,
NumericPtr: testutils.Float64Ptr(77.88),
NumericPtr: ptr.Of(77.88),
Float: 99.00,
FloatPtr: testutils.Float64Ptr(11.22),
FloatPtr: ptr.Of(11.22),
Double: 33.44,
DoublePtr: testutils.Float64Ptr(55.66),
DoublePtr: ptr.Of(55.66),
Real: 77.88,
RealPtr: testutils.Float64Ptr(99.00),
RealPtr: ptr.Of(99.00),
Bit: "1",
BitPtr: testutils.StringPtr("0"),
BitPtr: ptr.Of("0"),
Time: time.Date(1, 1, 1, 10, 11, 12, 100, &time.Location{}),
TimePtr: testutils.TimePtr(time.Date(1, 1, 1, 10, 11, 12, 100, time.UTC)),
TimePtr: ptr.Of(time.Date(1, 1, 1, 10, 11, 12, 100, time.UTC)),
Date: time.Now(),
DatePtr: testutils.TimePtr(time.Now()),
DatePtr: ptr.Of(time.Now()),
DateTime: time.Now(),
DateTimePtr: testutils.TimePtr(time.Now()),
DateTimePtr: ptr.Of(time.Now()),
Timestamp: time.Now(),
//TimestampPtr: testutils.TimePtr(time.Now()), // TODO: build fails for MariaDB
Year: 2000,
YearPtr: testutils.Int16Ptr(2001),
YearPtr: ptr.Of(int16(2001)),
Char: "abcd",
CharPtr: testutils.StringPtr("absd"),
CharPtr: ptr.Of("absd"),
VarChar: "abcd",
VarCharPtr: testutils.StringPtr("absd"),
VarCharPtr: ptr.Of("absd"),
Binary: []byte("1010"),
BinaryPtr: testutils.ByteArrayPtr([]byte("100001")),
BinaryPtr: ptr.Of([]byte("100001")),
VarBinary: []byte("1010"),
VarBinaryPtr: testutils.ByteArrayPtr([]byte("100001")),
VarBinaryPtr: ptr.Of([]byte("100001")),
Blob: []byte("large file"),
BlobPtr: testutils.ByteArrayPtr([]byte("very large file")),
BlobPtr: ptr.Of([]byte("very large file")),
Text: "some text",
TextPtr: testutils.StringPtr("text"),
TextPtr: ptr.Of("text"),
Enum: model.AllTypesEnum_Value1,
JSON: "{}",
JSONPtr: testutils.StringPtr(`{"a": 1}`),
JSONPtr: ptr.Of(`{"a": 1}`),
}
var allTypesJson = `
@ -1358,17 +1359,17 @@ func TestExactDecimals(t *testing.T) {
Floats: model.Floats{
// overwritten by wrapped(floats) scope
Numeric: 0.1,
NumericPtr: testutils.Float64Ptr(0.1),
NumericPtr: ptr.Of(0.1),
Decimal: 0.1,
DecimalPtr: testutils.Float64Ptr(0.1),
DecimalPtr: ptr.Of(0.1),
// not overwritten
Float: 0.2,
FloatPtr: testutils.Float64Ptr(0.22),
FloatPtr: ptr.Of(0.22),
Double: 0.3,
DoublePtr: testutils.Float64Ptr(0.33),
DoublePtr: ptr.Of(0.33),
Real: 0.4,
RealPtr: testutils.Float64Ptr(0.44),
RealPtr: ptr.Of(0.44),
},
Numeric: decimal.RequireFromString("12.35"),
NumericPtr: decimal.RequireFromString("56.79"),
@ -1403,3 +1404,34 @@ VALUES ('91.23', '45.67', '12.35', '56.79', 0.2, 0.22, 0.3, 0.33, 0.4, 0.44);
require.Equal(t, 45.67, *result.Floats.DecimalPtr)
})
}
func TestRowExpression(t *testing.T) {
now := time.Now()
nowAddHour := time.Now().Add(time.Hour)
stmt := SELECT(
ROW(Bool(false), DateT(now)).EQ(ROW(Bool(true), DateT(now))),
ROW(Bool(false), DateT(now)).NOT_EQ(ROW(Bool(true), DateT(now))),
ROW(TimestampT(nowAddHour), String("txt")).IS_DISTINCT_FROM(RowExp(Raw("row(NOW(), 'png')"))),
ROW(TimestampT(now), DateTimeT(nowAddHour)).GT(ROW(TimestampT(now), DateTimeT(now))),
ROW(DateTimeT(nowAddHour), Int(1)).GT_EQ(ROW(DateTimeT(now), Int(2))),
ROW(TimestampT(now), DateTimeT(nowAddHour)).LT(ROW(TimestampT(now), DateTimeT(now))),
ROW(DateTimeT(nowAddHour), Float(1.22)).LT_EQ(ROW(DateTimeT(now), Float(2.33))),
)
//fmt.Println(stmt.Sql())
//fmt.Println(stmt.DebugSql())
testutils.AssertStatementSql(t, stmt, `
SELECT ROW(?, CAST(? AS DATE)) = ROW(?, CAST(? AS DATE)),
ROW(?, CAST(? AS DATE)) != ROW(?, CAST(? AS DATE)),
NOT(ROW(TIMESTAMP(?), ?) <=> (row(NOW(), 'png'))),
ROW(TIMESTAMP(?), CAST(? AS DATETIME)) > ROW(TIMESTAMP(?), CAST(? AS DATETIME)),
ROW(CAST(? AS DATETIME), ?) >= ROW(CAST(? AS DATETIME), ?),
ROW(TIMESTAMP(?), CAST(? AS DATETIME)) < ROW(TIMESTAMP(?), CAST(? AS DATETIME)),
ROW(CAST(? AS DATETIME), ?) <= ROW(CAST(? AS DATETIME), ?);
`)
err := stmt.Query(db, &struct{}{})
require.NoError(t, err)
}

View file

@ -8,8 +8,11 @@ import (
"github.com/stretchr/testify/require"
"github.com/go-jet/jet/v2/generator/metadata"
"github.com/go-jet/jet/v2/generator/mysql"
"github.com/go-jet/jet/v2/generator/template"
"github.com/go-jet/jet/v2/internal/testutils"
mysql2 "github.com/go-jet/jet/v2/mysql"
"github.com/go-jet/jet/v2/tests/dbconfig"
)
@ -39,6 +42,39 @@ func TestGenerator(t *testing.T) {
require.NoError(t, err)
}
func TestGenerator_TableMetadata(t *testing.T) {
var schema metadata.Schema
err := mysql.Generate(genTestDir3, dbConnection("dvds"),
template.Default(mysql2.Dialect).UseSchema(func(m metadata.Schema) template.Schema {
schema = m
return template.DefaultSchema(m)
}))
require.NoError(t, err)
// Spot check the actor table and assert that the emitted
// properties are as expected.
var got metadata.Table
for _, table := range schema.TablesMetaData {
if table.Name == "actor" {
got = table
}
}
want := metadata.Table{
Name: "actor",
Columns: []metadata.Column{
{Name: "actor_id", IsPrimaryKey: true, IsNullable: false, IsGenerated: false, HasDefault: false, DataType: metadata.DataType{Name: "smallint", Kind: "base", IsUnsigned: true}, Comment: ""},
{Name: "first_name", IsPrimaryKey: false, IsNullable: false, IsGenerated: false, HasDefault: false, DataType: metadata.DataType{Name: "varchar", Kind: "base", IsUnsigned: false}, Comment: ""},
{Name: "last_name", IsPrimaryKey: false, IsNullable: false, IsGenerated: false, HasDefault: false, DataType: metadata.DataType{Name: "varchar", Kind: "base", IsUnsigned: false}, Comment: ""},
{Name: "last_update", IsPrimaryKey: false, IsNullable: false, IsGenerated: false, HasDefault: true, DataType: metadata.DataType{Name: "timestamp", Kind: "base", IsUnsigned: false}, Comment: ""},
},
}
require.Equal(t, want, got)
err = os.RemoveAll(genTestDirRoot)
require.NoError(t, err)
}
func TestCmdGenerator(t *testing.T) {
err := os.RemoveAll(genTestDir3)
require.NoError(t, err)

View file

@ -3,10 +3,12 @@ package mysql
import (
"context"
"github.com/go-jet/jet/v2/internal/testutils"
"github.com/go-jet/jet/v2/internal/utils/ptr"
. "github.com/go-jet/jet/v2/mysql"
"github.com/go-jet/jet/v2/qrm"
"github.com/go-jet/jet/v2/tests/.gentestdata/mysql/test_sample/model"
. "github.com/go-jet/jet/v2/tests/.gentestdata/mysql/test_sample/table"
"github.com/stretchr/testify/require"
"math/rand"
"testing"
@ -300,7 +302,7 @@ func TestInsertOnDuplicateKeyUpdateNEW(t *testing.T) {
ID: randId,
URL: "https://www.yahoo.com",
Name: "Yahoo",
Description: testutils.StringPtr("web portal and search engine"),
Description: ptr.Of("web portal and search engine"),
},
}).AS_NEW().
ON_DUPLICATE_KEY_UPDATE(
@ -337,7 +339,7 @@ ON DUPLICATE KEY UPDATE id = (link.id + ?),
ID: randId + 11,
URL: "https://www.yahoo.com",
Name: "Yahoo",
Description: testutils.StringPtr("web portal and search engine"),
Description: ptr.Of("web portal and search engine"),
})
})
}

View file

@ -6,12 +6,9 @@ import (
jetmysql "github.com/go-jet/jet/v2/mysql"
"github.com/go-jet/jet/v2/postgres"
"github.com/go-jet/jet/v2/tests/dbconfig"
"github.com/stretchr/testify/require"
"math/rand"
"runtime"
"time"
_ "github.com/go-sql-driver/mysql"
"github.com/stretchr/testify/require"
"runtime"
"github.com/pkg/profile"
"os"
@ -33,7 +30,6 @@ func sourceIsMariaDB() bool {
}
func TestMain(m *testing.M) {
rand.Seed(time.Now().Unix())
defer profile.Start().Stop()
var err error
@ -101,3 +97,9 @@ func skipForMariaDB(t *testing.T) {
t.SkipNow()
}
}
func onlyMariaDB(t *testing.T) {
if !sourceIsMariaDB() {
t.SkipNow()
}
}

347
tests/mysql/values_test.go Normal file
View file

@ -0,0 +1,347 @@
package mysql
import (
"github.com/go-jet/jet/v2/internal/testutils"
"github.com/stretchr/testify/require"
"strings"
"testing"
"time"
. "github.com/go-jet/jet/v2/mysql"
"github.com/go-jet/jet/v2/tests/.gentestdata/mysql/dvds/model"
. "github.com/go-jet/jet/v2/tests/.gentestdata/mysql/dvds/table"
)
func TestVALUES(t *testing.T) {
skipForMariaDB(t)
valuesTable := VALUES(
ROW(Int32(1), Int32(2), Float(4.666), Bool(false), String("txt")),
ROW(Int32(11).ADD(Int32(2)), Int32(22), Float(33.222), Bool(true), String("png")),
ROW(Int32(11), Int32(22), Float(33.222), Bool(true), NULL),
).AS("values_table")
stmt := SELECT(
valuesTable.AllColumns(),
).FROM(
valuesTable,
)
testutils.AssertStatementSql(t, stmt, `
SELECT values_table.column_0 AS "column_0",
values_table.column_1 AS "column_1",
values_table.column_2 AS "column_2",
values_table.column_3 AS "column_3",
values_table.column_4 AS "column_4"
FROM (
VALUES ROW(?, ?, ?, ?, ?),
ROW(? + ?, ?, ?, ?, ?),
ROW(?, ?, ?, ?, NULL)
) AS values_table;
`)
var dest []struct {
Column0 int
Column1 int
Column2 float32
Column3 bool
Column4 *string
}
err := stmt.Query(db, &dest)
require.NoError(t, err)
testutils.AssertJSON(t, dest, `
[
{
"Column0": 1,
"Column1": 2,
"Column2": 4.666,
"Column3": false,
"Column4": "txt"
},
{
"Column0": 13,
"Column1": 22,
"Column2": 33.222,
"Column3": true,
"Column4": "png"
},
{
"Column0": 11,
"Column1": 22,
"Column2": 33.222,
"Column3": true,
"Column4": null
}
]
`)
}
func TestVALUES_Join(t *testing.T) {
skipForMariaDB(t)
title := StringColumn("title")
releaseYear := IntegerColumn("ReleaseYear")
rentalRate := FloatColumn("rental_rate")
lastUpdate := Timestamp(2007, time.February, 11, 12, 0, 0)
films := VALUES(
ROW(String("Chamber Italian"), Int64(117), Int32(2005), Float(5.82), lastUpdate),
ROW(String("Grosse Wonderful"), Int64(49), Int32(2004), Float(6.242), lastUpdate.ADD(INTERVAL(1, HOUR))),
ROW(String("Airport Pollock"), Int64(54), Int32(2001), Float(7.22), NULL),
ROW(String("Bright Encounters"), Int64(73), Int32(2002), Float(8.25), NULL),
ROW(String("Academy Dinosaur"), Int64(83), Int32(2010), Float(9.22), lastUpdate.SUB(INTERVAL(2, MINUTE))),
).AS("film_values",
title, IntegerColumn("length"), releaseYear, rentalRate, TimestampColumn("last_update"))
stmt := SELECT(
Film.AllColumns,
films.AllColumns(),
).FROM(
Film.
INNER_JOIN(films, title.EQ(Film.Title)),
).WHERE(AND(
Film.ReleaseYear.GT(releaseYear),
Film.RentalRate.LT(rentalRate),
)).ORDER_BY(
title,
)
testutils.AssertDebugStatementSql(t, stmt, strings.ReplaceAll(`
SELECT film.film_id AS "film.film_id",
film.title AS "film.title",
film.description AS "film.description",
film.release_year AS "film.release_year",
film.language_id AS "film.language_id",
film.original_language_id AS "film.original_language_id",
film.rental_duration AS "film.rental_duration",
film.rental_rate AS "film.rental_rate",
film.length AS "film.length",
film.replacement_cost AS "film.replacement_cost",
film.rating AS "film.rating",
film.special_features AS "film.special_features",
film.last_update AS "film.last_update",
film_values.title AS "title",
film_values.length AS "length",
film_values.''ReleaseYear'' AS "ReleaseYear",
film_values.rental_rate AS "rental_rate",
film_values.last_update AS "last_update"
FROM dvds.film
INNER JOIN (
VALUES ROW('Chamber Italian', 117, 2005, 5.82, TIMESTAMP('2007-02-11 12:00:00')),
ROW('Grosse Wonderful', 49, 2004, 6.242, TIMESTAMP('2007-02-11 12:00:00') + INTERVAL 1 HOUR),
ROW('Airport Pollock', 54, 2001, 7.22, NULL),
ROW('Bright Encounters', 73, 2002, 8.25, NULL),
ROW('Academy Dinosaur', 83, 2010, 9.22, TIMESTAMP('2007-02-11 12:00:00') - INTERVAL 2 MINUTE)
) AS film_values (title, length, ''ReleaseYear'', rental_rate, last_update) ON (film_values.title = film.title)
WHERE (
(film.release_year > film_values.''ReleaseYear'')
AND (film.rental_rate < film_values.rental_rate)
)
ORDER BY film_values.title;
`, "''", "`"))
var dest []struct {
Film model.Film
Title string
Length int
ReleaseYear int
RentalRate float32
LastUpdate *time.Time
}
err := stmt.Query(db, &dest)
require.NoError(t, err)
require.Len(t, dest, 4)
testutils.AssertJSON(t, dest[0:2], `
[
{
"Film": {
"FilmID": 8,
"Title": "AIRPORT POLLOCK",
"Description": "A Epic Tale of a Moose And a Girl who must Confront a Monkey in Ancient India",
"ReleaseYear": 2006,
"LanguageID": 1,
"OriginalLanguageID": null,
"RentalDuration": 6,
"RentalRate": 4.99,
"Length": 54,
"ReplacementCost": 15.99,
"Rating": "R",
"SpecialFeatures": "Trailers",
"LastUpdate": "2006-02-15T05:03:42Z"
},
"Title": "Airport Pollock",
"Length": 54,
"ReleaseYear": 2001,
"RentalRate": 7.22,
"LastUpdate": null
},
{
"Film": {
"FilmID": 98,
"Title": "BRIGHT ENCOUNTERS",
"Description": "A Fateful Yarn of a Lumberjack And a Feminist who must Conquer a Student in A Jet Boat",
"ReleaseYear": 2006,
"LanguageID": 1,
"OriginalLanguageID": null,
"RentalDuration": 4,
"RentalRate": 4.99,
"Length": 73,
"ReplacementCost": 12.99,
"Rating": "PG-13",
"SpecialFeatures": "Trailers",
"LastUpdate": "2006-02-15T05:03:42Z"
},
"Title": "Bright Encounters",
"Length": 73,
"ReleaseYear": 2002,
"RentalRate": 8.25,
"LastUpdate": null
}
]
`)
}
func TestVALUES_CTE_Update(t *testing.T) {
skipForMariaDB(t)
paymentID := IntegerColumn("payment_id")
increase := FloatColumn("increase")
paymentsToUpdate := CTE("values_cte", paymentID, increase)
stmt := WITH(
paymentsToUpdate.AS(
VALUES(
ROW(Int32(204), Float(1.21)),
ROW(Int32(207), Float(1.02)),
ROW(Int32(200), Float(1.34)),
ROW(Int32(203), Float(1.72)),
),
),
)(
Payment.INNER_JOIN(paymentsToUpdate, paymentID.EQ(Payment.PaymentID)).
UPDATE().
SET(
Payment.Amount.SET(Payment.Amount.MUL(increase)),
).WHERE(Bool(true)),
)
testutils.AssertStatementSql(t, stmt, `
WITH values_cte (payment_id, increase) AS (
VALUES ROW(?, ?),
ROW(?, ?),
ROW(?, ?),
ROW(?, ?)
)
UPDATE dvds.payment
INNER JOIN values_cte ON (values_cte.payment_id = payment.payment_id)
SET amount = (payment.amount * values_cte.increase)
WHERE ?;
`)
testutils.AssertExecAndRollback(t, stmt, db, 4)
}
func TestVALUES_MariaDB(t *testing.T) {
onlyMariaDB(t) // mariadb won't accept values rows if all the elements are placeholders, so we have to use raw statement
paymentID := IntegerColumn("payment_id")
increase := FloatColumn("increase")
paymentsToUpdate := CTE("values_cte", paymentID, increase)
stmt := WITH(
paymentsToUpdate.AS(
RawStatement(`
VALUES (204, 1.21),
(207, 1.02),
(200, 1.34),
(203, 1.72)
`),
),
)(
SELECT(
Payment.AllColumns,
paymentsToUpdate.AllColumns(),
).FROM(
Payment.
INNER_JOIN(paymentsToUpdate, paymentID.EQ(Payment.PaymentID)),
).WHERE(
increase.GT(Float(1.03)),
).ORDER_BY(
increase,
),
)
testutils.AssertStatementSql(t, stmt, `
WITH values_cte (payment_id, increase) AS (
VALUES (204, 1.21),
(207, 1.02),
(200, 1.34),
(203, 1.72)
)
SELECT payment.payment_id AS "payment.payment_id",
payment.customer_id AS "payment.customer_id",
payment.staff_id AS "payment.staff_id",
payment.rental_id AS "payment.rental_id",
payment.amount AS "payment.amount",
payment.payment_date AS "payment.payment_date",
payment.last_update AS "payment.last_update",
values_cte.payment_id AS "payment_id",
values_cte.increase AS "increase"
FROM dvds.payment
INNER JOIN values_cte ON (values_cte.payment_id = payment.payment_id)
WHERE values_cte.increase > ?
ORDER BY values_cte.increase;
`)
var dest []struct {
model.Payment
Increase float64
}
err := stmt.Query(db, &dest)
require.NoError(t, err)
testutils.AssertJSON(t, dest, `
[
{
"PaymentID": 204,
"CustomerID": 7,
"StaffID": 1,
"RentalID": 13476,
"Amount": 2.99,
"PaymentDate": "2005-08-20T01:06:04Z",
"LastUpdate": "2006-02-15T22:12:31Z",
"Increase": 1.21
},
{
"PaymentID": 200,
"CustomerID": 7,
"StaffID": 2,
"RentalID": 11542,
"Amount": 7.99,
"PaymentDate": "2005-08-17T00:51:32Z",
"LastUpdate": "2006-02-15T22:12:31Z",
"Increase": 1.34
},
{
"PaymentID": 203,
"CustomerID": 7,
"StaffID": 2,
"RentalID": 13373,
"Amount": 2.99,
"PaymentDate": "2005-08-19T21:23:31Z",
"LastUpdate": "2006-02-15T22:12:31Z",
"Increase": 1.72
}
]
`)
}

View file

@ -164,10 +164,10 @@ WITH payments_to_delete AS (
WHERE payment.amount < 0.5
)
DELETE FROM dvds.payment
WHERE payment.payment_id IN (
WHERE payment.payment_id IN ((
SELECT payments_to_delete.''payment.payment_id'' AS "payment.payment_id"
FROM payments_to_delete
);
));
`, "''", "`"))
tx, err := db.Begin()

View file

@ -1,6 +1,10 @@
package postgres
import (
"database/sql"
"github.com/go-jet/jet/v2/internal/utils/ptr"
"github.com/stretchr/testify/assert"
"github.com/go-jet/jet/v2/qrm"
"testing"
"time"
@ -344,24 +348,22 @@ func TestExpressionOperators(t *testing.T) {
AllTypes.SmallIntPtr.NOT_IN(AllTypes.SELECT(AllTypes.Integer)).AS("result.not_in_select"),
).LIMIT(2)
//fmt.Println(query.Sql())
testutils.AssertStatementSql(t, query, `
SELECT all_types.integer IS NULL AS "result.is_null",
all_types.date_ptr IS NOT NULL AS "result.is_not_null",
(all_types.small_int_ptr IN ($1::smallint, $2::smallint)) AS "result.in",
(all_types.small_int_ptr IN (
(all_types.small_int_ptr IN ((
SELECT all_types.integer AS "all_types.integer"
FROM test_sample.all_types
)) AS "result.in_select",
))) AS "result.in_select",
(CURRENT_USER) AS "result.raw",
($3 + COALESCE(all_types.small_int_ptr, 0) + $4) AS "result.raw_arg",
($5 + all_types.integer + $6 + $5 + $7 + $8) AS "result.raw_arg2",
(all_types.small_int_ptr NOT IN ($9, $10::smallint, NULL)) AS "result.not_in",
(all_types.small_int_ptr NOT IN (
(all_types.small_int_ptr NOT IN ((
SELECT all_types.integer AS "all_types.integer"
FROM test_sample.all_types
)) AS "result.not_in_select"
))) AS "result.not_in_select"
FROM test_sample.all_types
LIMIT $11;
`, int8(11), int8(22), 78, 56, 11, 22, 33, 44, int64(11), int16(22), int64(2))
@ -373,9 +375,6 @@ LIMIT $11;
err := query.Query(db, &dest)
require.NoError(t, err)
//testutils.PrintJson(dest)
testutils.AssertJSON(t, dest, `
[
{
@ -930,6 +929,68 @@ func TestTimeExpression(t *testing.T) {
require.NoError(t, err)
}
func TestIntervalSetFunctionality(t *testing.T) {
t.Run("updateQueryIntervalTest", func(t *testing.T) {
expectedQuery := `
UPDATE test_sample.employee
SET pto_accrual = INTERVAL '3 HOUR'
WHERE employee.employee_id = $1
RETURNING 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",
employee.pto_accrual AS "employee.pto_accrual";
`
testutils.ExecuteInTxAndRollback(t, db, func(tx *sql.Tx) {
var windy model.Employee
windy.PtoAccrual = ptr.Of("3h")
stmt := Employee.UPDATE(Employee.PtoAccrual).SET(
Employee.PtoAccrual.SET(INTERVAL(3, HOUR)),
).WHERE(Employee.EmployeeID.EQ(Int(1))).RETURNING(Employee.AllColumns)
testutils.AssertStatementSql(t, stmt, expectedQuery)
err := stmt.Query(tx, &windy)
assert.Nil(t, err)
assert.Equal(t, *windy.PtoAccrual, "03:00:00")
})
})
t.Run("upsertQueryIntervalTest", func(t *testing.T) {
expectedQuery := `
INSERT INTO test_sample.employee (employee_id, first_name, last_name, employment_date, manager_id, pto_accrual)
VALUES ($1, $2, $3, $4, $5, $6)
ON CONFLICT (employee_id) DO UPDATE
SET pto_accrual = excluded.pto_accrual
RETURNING 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",
employee.pto_accrual AS "employee.pto_accrual";
`
testutils.ExecuteInTxAndRollback(t, db, func(tx *sql.Tx) {
var employee model.Employee
employee.PtoAccrual = ptr.Of("5h")
stmt := Employee.INSERT(Employee.AllColumns).
MODEL(employee).
ON_CONFLICT(Employee.EmployeeID).
DO_UPDATE(SET(
Employee.PtoAccrual.SET(Employee.EXCLUDED.PtoAccrual),
)).RETURNING(Employee.AllColumns)
testutils.AssertStatementSql(t, stmt, expectedQuery)
err := stmt.Query(tx, &employee)
assert.Nil(t, err)
assert.Equal(t, *employee.PtoAccrual, "05:00:00")
})
})
}
func TestInterval(t *testing.T) {
skipForCockroachDB(t)
@ -1046,6 +1107,46 @@ FROM test_sample.all_types;
require.NoError(t, err)
}
func TestRowExpression(t *testing.T) {
now := time.Now()
nowAddHour := time.Now().Add(time.Hour)
stmt := SELECT(
ROW(Int32(1), Float32(11.22), String("john")).AS("row"),
WRAP(Int64(1), Float64(11.22), String("john")).AS("wrap"),
ROW(Bool(false), DateT(now)).EQ(ROW(Bool(true), DateT(now))),
WRAP(Bool(false), DateT(now)).NOT_EQ(WRAP(Bool(true), DateT(now))),
ROW(TimeT(nowAddHour)).IS_DISTINCT_FROM(RowExp(Raw("row(NOW()::time)"))),
ROW().IS_NOT_DISTINCT_FROM(ROW()),
ROW(TimestampT(now), TimestampzT(nowAddHour)).GT(WRAP(TimestampT(now), TimestampzT(now))),
ROW(TimestampzT(nowAddHour)).GT_EQ(ROW(TimestampzT(now))),
WRAP(TimestampT(now), TimestampzT(nowAddHour)).LT(ROW(TimestampT(now), TimestampzT(now))),
ROW(TimestampzT(nowAddHour)).LT_EQ(ROW(TimestampzT(now))),
)
//fmt.Println(stmt.Sql())
//fmt.Println(stmt.DebugSql())
testutils.AssertStatementSql(t, stmt, `
SELECT ROW($1::integer, $2::real, $3::text) AS "row",
($4::bigint, $5::double precision, $6::text) AS "wrap",
ROW($7::boolean, $8::date) = ROW($9::boolean, $10::date),
($11::boolean, $12::date) != ($13::boolean, $14::date),
ROW($15::time without time zone) IS DISTINCT FROM (row(NOW()::time)),
ROW() IS NOT DISTINCT FROM ROW(),
ROW($16::timestamp without time zone, $17::timestamp with time zone) > ($18::timestamp without time zone, $19::timestamp with time zone),
ROW($20::timestamp with time zone) >= ROW($21::timestamp with time zone),
($22::timestamp without time zone, $23::timestamp with time zone) < ROW($24::timestamp without time zone, $25::timestamp with time zone),
ROW($26::timestamp with time zone) <= ROW($27::timestamp with time zone);
`)
err := stmt.Query(db, &struct{}{})
require.NoError(t, err)
}
func TestSubQueryColumnReference(t *testing.T) {
type expected struct {
sql string
@ -1305,32 +1406,32 @@ RETURNING all_types.json AS "all_types.json";
var moodSad = model.Mood_Sad
var allTypesRow0 = model.AllTypes{
SmallIntPtr: testutils.Int16Ptr(14),
SmallIntPtr: ptr.Of(int16(14)),
SmallInt: 14,
IntegerPtr: testutils.Int32Ptr(300),
IntegerPtr: ptr.Of(int32(300)),
Integer: 300,
BigIntPtr: testutils.Int64Ptr(50000),
BigIntPtr: ptr.Of(int64(50000)),
BigInt: 5000,
DecimalPtr: testutils.Float64Ptr(1.11),
DecimalPtr: ptr.Of(1.11),
Decimal: 1.11,
NumericPtr: testutils.Float64Ptr(2.22),
NumericPtr: ptr.Of(2.22),
Numeric: 2.22,
RealPtr: testutils.Float32Ptr(5.55),
RealPtr: ptr.Of(float32(5.55)),
Real: 5.55,
DoublePrecisionPtr: testutils.Float64Ptr(11111111.22),
DoublePrecisionPtr: ptr.Of(11111111.22),
DoublePrecision: 11111111.22,
Smallserial: 1,
Serial: 1,
Bigserial: 1,
//MoneyPtr: nil,
//Money:
VarCharPtr: testutils.StringPtr("ABBA"),
VarCharPtr: ptr.Of("ABBA"),
VarChar: "ABBA",
CharPtr: testutils.StringPtr("JOHN "),
CharPtr: ptr.Of("JOHN "),
Char: "JOHN ",
TextPtr: testutils.StringPtr("Some text"),
TextPtr: ptr.Of("Some text"),
Text: "Some text",
ByteaPtr: testutils.ByteArrayPtr([]byte("bytea")),
ByteaPtr: ptr.Of([]byte("bytea")),
Bytea: []byte("bytea"),
TimestampzPtr: testutils.TimestampWithTimeZone("1999-01-08 13:05:06 +0100 CET", 0),
Timestampz: *testutils.TimestampWithTimeZone("1999-01-08 13:05:06 +0100 CET", 0),
@ -1342,31 +1443,31 @@ var allTypesRow0 = model.AllTypes{
Timez: *testutils.TimeWithTimeZone("04:05:06 -0800"),
TimePtr: testutils.TimeWithoutTimeZone("04:05:06"),
Time: *testutils.TimeWithoutTimeZone("04:05:06"),
IntervalPtr: testutils.StringPtr("3 days 04:05:06"),
IntervalPtr: ptr.Of("3 days 04:05:06"),
Interval: "3 days 04:05:06",
BooleanPtr: testutils.BoolPtr(true),
BooleanPtr: ptr.Of(true),
Boolean: false,
PointPtr: testutils.StringPtr("(2,3)"),
BitPtr: testutils.StringPtr("101"),
PointPtr: ptr.Of("(2,3)"),
BitPtr: ptr.Of("101"),
Bit: "101",
BitVaryingPtr: testutils.StringPtr("101111"),
BitVaryingPtr: ptr.Of("101111"),
BitVarying: "101111",
TsvectorPtr: testutils.StringPtr("'supernova':1"),
TsvectorPtr: ptr.Of("'supernova':1"),
Tsvector: "'supernova':1",
UUIDPtr: testutils.UUIDPtr("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"),
UUID: uuid.MustParse("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"),
XMLPtr: testutils.StringPtr("<Sub>abc</Sub>"),
XMLPtr: ptr.Of("<Sub>abc</Sub>"),
XML: "<Sub>abc</Sub>",
JSONPtr: testutils.StringPtr(`{"a": 1, "b": 3}`),
JSONPtr: ptr.Of(`{"a": 1, "b": 3}`),
JSON: `{"a": 1, "b": 3}`,
JsonbPtr: testutils.StringPtr(`{"a": 1, "b": 3}`),
JsonbPtr: ptr.Of(`{"a": 1, "b": 3}`),
Jsonb: `{"a": 1, "b": 3}`,
IntegerArrayPtr: testutils.StringPtr("{1,2,3}"),
IntegerArrayPtr: ptr.Of("{1,2,3}"),
IntegerArray: "{1,2,3}",
TextArrayPtr: testutils.StringPtr("{breakfast,consulting}"),
TextArrayPtr: ptr.Of("{breakfast,consulting}"),
TextArray: "{breakfast,consulting}",
JsonbArray: `{"{\"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

@ -3,6 +3,7 @@ package postgres
import (
"context"
"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/tests/.gentestdata/jetdb/chinook/model"
. "github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/chinook/table"
@ -455,7 +456,7 @@ FROM (
require.Len(t, dest, 275)
require.Equal(t, dest[0].Artist1.Artist, model.Artist{
ArtistId: 1,
Name: testutils.StringPtr("AC/DC"),
Name: ptr.Of("AC/DC"),
})
require.Equal(t, dest[0].Artist1.CustomColumn1, "custom_column_1")
require.Equal(t, dest[0].Artist1.CustomColumn2, "custom_column_2")

View file

@ -3,6 +3,9 @@ package postgres
import (
"database/sql"
"fmt"
"path"
"testing"
"github.com/go-jet/jet/v2/generator/metadata"
"github.com/go-jet/jet/v2/generator/postgres"
"github.com/go-jet/jet/v2/generator/template"
@ -13,8 +16,6 @@ import (
"github.com/go-jet/jet/v2/tests/dbconfig"
file2 "github.com/go-jet/jet/v2/tests/internal/utils/file"
"github.com/stretchr/testify/require"
"path"
"testing"
)
const tempTestDir = "./.tempTestDir"
@ -170,6 +171,7 @@ func TestGeneratorTemplate_Model_RenameFilesAndTypes(t *testing.T) {
mpaaRating := file2.Exists(t, defaultModelPath, "mpaa_rating_enum.go")
require.Contains(t, mpaaRating, "type MpaaRatingEnum string")
require.Contains(t, mpaaRating, "MpaaRatingEnumAllValues")
}
func TestGeneratorTemplate_Model_SkipTableAndEnum(t *testing.T) {
@ -267,7 +269,6 @@ func UseSchema(schema string) {
FilmList = FilmList.FromSchema(schema)
}
`)
}
func TestGeneratorTemplate_SQLBuilder_ChangeTypeAndFileName(t *testing.T) {
@ -365,7 +366,6 @@ func TestGeneratorTemplate_SQLBuilder_DefaultAlias(t *testing.T) {
}
func TestGeneratorTemplate_Model_AddTags(t *testing.T) {
err := postgres.Generate(
tempTestDir,
dbConnection,

View file

@ -2,7 +2,6 @@ package postgres
import (
"fmt"
"github.com/go-jet/jet/v2/tests/internal/utils/file"
"os"
"os/exec"
"path/filepath"
@ -12,11 +11,14 @@ import (
"github.com/stretchr/testify/require"
"github.com/go-jet/jet/v2/generator/metadata"
"github.com/go-jet/jet/v2/generator/postgres"
"github.com/go-jet/jet/v2/generator/template"
"github.com/go-jet/jet/v2/internal/testutils"
"github.com/go-jet/jet/v2/tests/dbconfig"
postgres2 "github.com/go-jet/jet/v2/postgres"
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/dvds/model"
"github.com/go-jet/jet/v2/tests/dbconfig"
"github.com/go-jet/jet/v2/tests/internal/utils/file"
)
func dsn(host string, port int, dbName, user, password string) string {
@ -208,6 +210,45 @@ func TestGenerator(t *testing.T) {
require.NoError(t, err)
}
func TestGenerator_TableMetadata(t *testing.T) {
var schema metadata.Schema
err := postgres.GenerateDSN(defaultDSN(), "dvds", genTestDir2,
template.Default(postgres2.Dialect).UseSchema(func(m metadata.Schema) template.Schema {
schema = m
return template.DefaultSchema(m)
}))
require.NoError(t, err)
// Spot check the actor table and assert that the emitted
// properties are as expected.
var got metadata.Table
var specialFeatures metadata.Column
for _, table := range schema.TablesMetaData {
if table.Name == "actor" {
got = table
}
if table.Name == "film" {
for _, column := range table.Columns {
if column.Name == "special_features" {
specialFeatures = column
}
}
}
}
want := metadata.Table{
Name: "actor",
Columns: []metadata.Column{
{Name: "actor_id", IsPrimaryKey: true, IsNullable: false, IsGenerated: false, HasDefault: true, DataType: metadata.DataType{Name: "int4", Kind: "base", IsUnsigned: false}, Comment: ""},
{Name: "first_name", IsPrimaryKey: false, IsNullable: false, IsGenerated: false, HasDefault: false, DataType: metadata.DataType{Name: "varchar", Kind: "base", IsUnsigned: false}, Comment: ""},
{Name: "last_name", IsPrimaryKey: false, IsNullable: false, IsGenerated: false, HasDefault: false, DataType: metadata.DataType{Name: "varchar", Kind: "base", IsUnsigned: false}, Comment: ""},
{Name: "last_update", IsPrimaryKey: false, IsNullable: false, IsGenerated: false, HasDefault: false, DataType: metadata.DataType{Name: "timestamp", Kind: "base", IsUnsigned: false}, Comment: ""},
},
}
require.Equal(t, want, got)
require.Equal(t, metadata.ArrayType, specialFeatures.DataType.Kind)
}
func TestGeneratorSpecialCharacters(t *testing.T) {
t.SkipNow()
err := postgres.Generate(genTestDir2, postgres.DBConnection{
@ -563,6 +604,7 @@ func TestGeneratedAllTypesSQLBuilderFiles(t *testing.T) {
"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")
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",
@ -570,6 +612,8 @@ func TestGeneratedAllTypesSQLBuilderFiles(t *testing.T) {
testutils.AssertFileContent(t, tableDir+"/all_types.go", allTypesTableContent)
testutils.AssertFileContent(t, tableDir+"/sample_ranges.go", sampleRangeTableContent)
testutils.AssertFileContent(t, tableDir+"/link.go", linkTableContent)
testutils.AssertFileNamesEqual(t, viewDir, "all_types_materialized_view.go", "all_types_view.go",
"view_use_schema.go")
}
@ -609,6 +653,7 @@ package enum
import "github.com/go-jet/jet/v2/postgres"
// Level enum
var Level = &struct {
Level1 postgres.StringExpression
Level2 postgres.StringExpression
@ -706,6 +751,25 @@ type AllTypes struct {
}
`
var linkModelContent = `
//
// Code generated by go-jet DO NOT EDIT.
//
// WARNING: Changes to this file may cause incorrect behavior
// and will be lost if the code is regenerated
//
package model
// Link table
type Link struct {
ID int64 ` + "`sql:\"primary_key\"`" + ` // this is link id
URL string // link url
Name string // Unicode characters comment ₲鬼佬℧⇄↻
Description *string // '"Z\%_
}
`
var allTypesTableContent = `
//
// Code generated by go-jet DO NOT EDIT.
@ -1062,3 +1126,91 @@ func newSampleRangesTableImpl(schemaName, tableName, alias string) sampleRangesT
}
}
`
var linkTableContent = `
//
// Code generated by go-jet DO NOT EDIT.
//
// WARNING: Changes to this file may cause incorrect behavior
// and will be lost if the code is regenerated
//
package table
import (
"github.com/go-jet/jet/v2/postgres"
)
var Link = newLinkTable("test_sample", "link", "")
// Link table
type linkTable struct {
postgres.Table
// Columns
ID postgres.ColumnInteger // this is link id
URL postgres.ColumnString // link url
Name postgres.ColumnString // Unicode characters comment ₲鬼佬℧⇄↻
Description postgres.ColumnString // '"Z\%_
AllColumns postgres.ColumnList
MutableColumns postgres.ColumnList
}
type LinkTable struct {
linkTable
EXCLUDED linkTable
}
// AS creates new LinkTable with assigned alias
func (a LinkTable) AS(alias string) *LinkTable {
return newLinkTable(a.SchemaName(), a.TableName(), alias)
}
// Schema creates new LinkTable with assigned schema name
func (a LinkTable) FromSchema(schemaName string) *LinkTable {
return newLinkTable(schemaName, a.TableName(), a.Alias())
}
// WithPrefix creates new LinkTable with assigned table prefix
func (a LinkTable) WithPrefix(prefix string) *LinkTable {
return newLinkTable(a.SchemaName(), prefix+a.TableName(), a.TableName())
}
// WithSuffix creates new LinkTable with assigned table suffix
func (a LinkTable) WithSuffix(suffix string) *LinkTable {
return newLinkTable(a.SchemaName(), a.TableName()+suffix, a.TableName())
}
func newLinkTable(schemaName, tableName, alias string) *LinkTable {
return &LinkTable{
linkTable: newLinkTableImpl(schemaName, tableName, alias),
EXCLUDED: newLinkTableImpl("", "excluded", ""),
}
}
func newLinkTableImpl(schemaName, tableName, alias string) linkTable {
var (
IDColumn = postgres.IntegerColumn("id")
URLColumn = postgres.StringColumn("url")
NameColumn = postgres.StringColumn("name")
DescriptionColumn = postgres.StringColumn("description")
allColumns = postgres.ColumnList{IDColumn, URLColumn, NameColumn, DescriptionColumn}
mutableColumns = postgres.ColumnList{URLColumn, NameColumn, DescriptionColumn}
)
return linkTable{
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
//Columns
ID: IDColumn,
URL: URLColumn,
Name: NameColumn,
Description: DescriptionColumn,
AllColumns: allColumns,
MutableColumns: mutableColumns,
}
}
`

View file

@ -93,9 +93,9 @@ func TestInsertOnConflict(t *testing.T) {
ON_CONFLICT().DO_NOTHING()
testutils.AssertStatementSql(t, stmt, `
INSERT INTO test_sample.employee (employee_id, first_name, last_name, employment_date, manager_id)
VALUES ($1, $2, $3, $4, $5),
($6, $7, $8, $9, $10)
INSERT INTO test_sample.employee (employee_id, first_name, last_name, employment_date, manager_id, pto_accrual)
VALUES ($1, $2, $3, $4, $5, $6),
($7, $8, $9, $10, $11, $12)
ON CONFLICT DO NOTHING;
`)
testutils.AssertExecAndRollback(t, stmt, db, 1)
@ -111,9 +111,9 @@ ON CONFLICT DO NOTHING;
ON_CONFLICT(Employee.EmployeeID).DO_NOTHING()
testutils.AssertStatementSql(t, stmt, `
INSERT INTO test_sample.employee (employee_id, first_name, last_name, employment_date, manager_id)
VALUES ($1, $2, $3, $4, $5),
($6, $7, $8, $9, $10)
INSERT INTO test_sample.employee (employee_id, first_name, last_name, employment_date, manager_id, pto_accrual)
VALUES ($1, $2, $3, $4, $5, $6),
($7, $8, $9, $10, $11, $12)
ON CONFLICT (employee_id) DO NOTHING;
`)
testutils.AssertExecAndRollback(t, stmt, db, 1)
@ -130,9 +130,9 @@ ON CONFLICT (employee_id) DO NOTHING;
ON_CONFLICT().ON_CONSTRAINT("employee_pkey").DO_NOTHING()
testutils.AssertStatementSql(t, stmt, `
INSERT INTO test_sample.employee (employee_id, first_name, last_name, employment_date, manager_id)
VALUES ($1, $2, $3, $4, $5),
($6, $7, $8, $9, $10)
INSERT INTO test_sample.employee (employee_id, first_name, last_name, employment_date, manager_id, pto_accrual)
VALUES ($1, $2, $3, $4, $5, $6),
($7, $8, $9, $10, $11, $12)
ON CONFLICT ON CONSTRAINT employee_pkey DO NOTHING;
`)
testutils.AssertExecAndRollback(t, stmt, db, 1)
@ -234,8 +234,8 @@ ON CONFLICT (id) WHERE (id * 2) > 10 DO UPDATE
ON_CONFLICT().DO_UPDATE(nil)
testutils.AssertStatementSql(t, stmt, `
INSERT INTO test_sample.employee (employee_id, first_name, last_name, employment_date, manager_id)
VALUES ($1, $2, $3, $4, $5);
INSERT INTO test_sample.employee (employee_id, first_name, last_name, employment_date, manager_id, pto_accrual)
VALUES ($1, $2, $3, $4, $5, $6);
`)
testutils.AssertExecAndRollback(t, stmt, db, 1)
requireLogged(t, stmt)

View file

@ -5,13 +5,10 @@ import (
"database/sql"
"fmt"
"github.com/go-jet/jet/v2/tests/internal/utils/repo"
"math/rand"
"github.com/jackc/pgx/v4/stdlib"
"os"
"runtime"
"testing"
"time"
"github.com/jackc/pgx/v4/stdlib"
"github.com/go-jet/jet/v2/postgres"
"github.com/go-jet/jet/v2/tests/dbconfig"
@ -44,7 +41,6 @@ func skipForCockroachDB(t *testing.T) {
}
func TestMain(m *testing.M) {
rand.Seed(time.Now().Unix())
defer profile.Start().Stop()
setTestRoot()

View file

@ -11,34 +11,31 @@ import (
func TestNorthwindJoinEverything(t *testing.T) {
stmt := SELECT(
Customers.AllColumns,
CustomerDemographics.AllColumns,
Orders.AllColumns,
Shippers.AllColumns,
OrderDetails.AllColumns,
Products.AllColumns,
Categories.AllColumns,
Suppliers.AllColumns,
).FROM(
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)),
).ORDER_BY(
Customers.CustomerID,
Orders.OrderID,
Products.ProductID,
)
stmt :=
SELECT(
Customers.AllColumns,
CustomerDemographics.AllColumns,
Orders.AllColumns,
Shippers.AllColumns,
OrderDetails.AllColumns,
Products.AllColumns,
Categories.AllColumns,
Suppliers.AllColumns,
).FROM(
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)),
).ORDER_BY(Customers.CustomerID, Orders.OrderID, Products.ProductID)
var dest []struct {
model.Customers

View file

@ -2,6 +2,7 @@ package postgres
import (
"github.com/go-jet/jet/v2/qrm"
"github.com/go-jet/jet/v2/internal/utils/ptr"
"github.com/google/uuid"
"testing"
@ -63,15 +64,15 @@ func TestExactDecimals(t *testing.T) {
Floats: model.Floats{
// overwritten by wrapped(floats) scope
Numeric: 0.1,
NumericPtr: testutils.Float64Ptr(0.1),
NumericPtr: ptr.Of(0.1),
Decimal: 0.1,
DecimalPtr: testutils.Float64Ptr(0.1),
DecimalPtr: ptr.Of(0.1),
// not overwritten
Real: 0.4,
RealPtr: testutils.Float32Ptr(0.44),
RealPtr: ptr.Of(float32(0.44)),
Double: 0.3,
DoublePtr: testutils.Float64Ptr(0.33),
DoublePtr: ptr.Of(0.33),
},
Numeric: decimal.RequireFromString("0.1234567890123456789"),
NumericPtr: decimal.RequireFromString("1.1111111111111111111"),
@ -330,11 +331,13 @@ SELECT employee.employee_id AS "employee.employee_id",
employee.last_name AS "employee.last_name",
employee.employment_date AS "employee.employment_date",
employee.manager_id AS "employee.manager_id",
employee.pto_accrual AS "employee.pto_accrual",
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"
manager.manager_id AS "manager.manager_id",
manager.pto_accrual AS "manager.pto_accrual"
FROM test_sample.employee
LEFT JOIN test_sample.employee AS manager ON (manager.employee_id = employee.manager_id)
ORDER BY employee.employee_id;
@ -369,6 +372,7 @@ ORDER BY employee.employee_id;
LastName: "Hays",
EmploymentDate: testutils.TimestampWithTimeZone("1999-01-08 04:05:06.1 +0100 CET", 1),
ManagerID: nil,
PtoAccrual: ptr.Of("22:00:00"),
})
require.True(t, dest[0].Manager == nil)
@ -378,7 +382,7 @@ ORDER BY employee.employee_id;
FirstName: "Salley",
LastName: "Lester",
EmploymentDate: testutils.TimestampWithTimeZone("1999-01-08 04:05:06 +0100 CET", 1),
ManagerID: testutils.Int32Ptr(3),
ManagerID: ptr.Of(int32(3)),
})
}
@ -420,7 +424,7 @@ FROM test_sample."WEIRD NAMES TABLE";
WeirdColumnName5: "Doe",
WeirdColumnName6: "Doe",
WeirdColumnName7: "Doe",
Weirdcolumnname8: testutils.StringPtr("Doe"),
Weirdcolumnname8: ptr.Of("Doe"),
WeirdColName9: "Doe",
WeirdColuName10: "Doe",
WeirdColuName11: "Doe",
@ -518,7 +522,7 @@ func TestMutableColumnsExcludeGeneratedColumn(t *testing.T) {
).MODEL(
model.People{
PeopleName: "Dario",
PeopleHeightCm: testutils.Float64Ptr(120),
PeopleHeightCm: ptr.Of(120.0),
},
).RETURNING(
People.MutableColumns,

View file

@ -2,6 +2,7 @@ package postgres
import (
"context"
"github.com/go-jet/jet/v2/internal/utils/ptr"
"github.com/volatiletech/null/v8"
"testing"
"time"
@ -93,7 +94,7 @@ func TestScanToValidDestination(t *testing.T) {
err := oneInventoryQuery.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, dest[0], testutils.Int32Ptr(1))
require.Equal(t, dest[0], ptr.Of(int32(1)))
})
t.Run("NULL to integer", func(t *testing.T) {
@ -530,10 +531,10 @@ func TestScanToSlice(t *testing.T) {
require.NoError(t, err)
require.Equal(t, len(dest), 2)
testutils.AssertDeepEqual(t, dest[0].Film, film1)
testutils.AssertDeepEqual(t, dest[0].IDs, []*int32{testutils.Int32Ptr(1), testutils.Int32Ptr(2), testutils.Int32Ptr(3), testutils.Int32Ptr(4),
testutils.Int32Ptr(5), testutils.Int32Ptr(6), testutils.Int32Ptr(7), testutils.Int32Ptr(8)})
testutils.AssertDeepEqual(t, dest[0].IDs, []*int32{ptr.Of(int32(1)), ptr.Of(int32(2)), ptr.Of(int32(3)), ptr.Of(int32(4)),
ptr.Of(int32(5)), ptr.Of(int32(6)), ptr.Of(int32(7)), ptr.Of(int32(8))})
testutils.AssertDeepEqual(t, dest[1].Film, film2)
testutils.AssertDeepEqual(t, dest[1].IDs, []*int32{testutils.Int32Ptr(9), testutils.Int32Ptr(10)})
testutils.AssertDeepEqual(t, dest[1].IDs, []*int32{ptr.Of(int32(9)), ptr.Of(int32(10))})
})
t.Run("complex struct 1", func(t *testing.T) {
@ -1076,10 +1077,10 @@ VALUES (1234, 0, 'Joe', '', NULL, 1, TRUE, '2020-02-02 10:00:00Z', NULL, 1);
var address256 = model.Address{
AddressID: 256,
Address: "1497 Yuzhou Drive",
Address2: testutils.StringPtr(""),
Address2: ptr.Of(""),
District: "England",
CityID: 312,
PostalCode: testutils.StringPtr("3433"),
PostalCode: ptr.Of("3433"),
Phone: "246810237916",
LastUpdate: *testutils.TimestampWithoutTimeZone("2006-02-15 09:45:30", 0),
}
@ -1087,10 +1088,10 @@ var address256 = model.Address{
var addres517 = model.Address{
AddressID: 517,
Address: "548 Uruapan Street",
Address2: testutils.StringPtr(""),
Address2: ptr.Of(""),
District: "Ontario",
CityID: 312,
PostalCode: testutils.StringPtr("35653"),
PostalCode: ptr.Of("35653"),
Phone: "879347453467",
LastUpdate: *testutils.TimestampWithoutTimeZone("2006-02-15 09:45:30", 0),
}
@ -1100,12 +1101,12 @@ var customer256 = model.Customer{
StoreID: 2,
FirstName: "Mattie",
LastName: "Hoffman",
Email: testutils.StringPtr("mattie.hoffman@sakilacustomer.org"),
Email: ptr.Of("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: testutils.Int32Ptr(1),
Active: ptr.Of(int32(1)),
}
var customer512 = model.Customer{
@ -1113,12 +1114,12 @@ var customer512 = model.Customer{
StoreID: 1,
FirstName: "Cecil",
LastName: "Vines",
Email: testutils.StringPtr("cecil.vines@sakilacustomer.org"),
Email: ptr.Of("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: testutils.Int32Ptr(1),
Active: ptr.Of(int32(1)),
}
var countryUk = model.Country{
@ -1151,32 +1152,32 @@ var inventory2 = model.Inventory{
var film1 = model.Film{
FilmID: 1,
Title: "Academy Dinosaur",
Description: testutils.StringPtr("A Epic Drama of a Feminist And a Mad Scientist who must Battle a Teacher in The Canadian Rockies"),
ReleaseYear: testutils.Int32Ptr(2006),
Description: ptr.Of("A Epic Drama of a Feminist And a Mad Scientist who must Battle a Teacher in The Canadian Rockies"),
ReleaseYear: ptr.Of(int32(2006)),
LanguageID: 1,
RentalDuration: 6,
RentalRate: 0.99,
Length: testutils.Int16Ptr(86),
Length: ptr.Of(int16(86)),
ReplacementCost: 20.99,
Rating: &pgRating,
LastUpdate: *testutils.TimestampWithoutTimeZone("2013-05-26 14:50:58.951", 3),
SpecialFeatures: testutils.StringPtr("{\"Deleted Scenes\",\"Behind the Scenes\"}"),
SpecialFeatures: ptr.Of("{\"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: testutils.StringPtr("A Astounding Epistle of a Database Administrator And a Explorer who must Find a Car in Ancient China"),
ReleaseYear: testutils.Int32Ptr(2006),
Description: ptr.Of("A Astounding Epistle of a Database Administrator And a Explorer who must Find a Car in Ancient China"),
ReleaseYear: ptr.Of(int32(2006)),
LanguageID: 1,
RentalDuration: 3,
RentalRate: 4.99,
Length: testutils.Int16Ptr(48),
Length: ptr.Of(int16(48)),
ReplacementCost: 12.99,
Rating: &gRating,
LastUpdate: *testutils.TimestampWithoutTimeZone("2013-05-26 14:50:58.951", 3),
SpecialFeatures: testutils.StringPtr(`{Trailers,"Deleted Scenes"}`),
SpecialFeatures: ptr.Of(`{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`,
}

View file

@ -3,6 +3,7 @@ package postgres
import (
"context"
"database/sql"
"github.com/go-jet/jet/v2/internal/utils/ptr"
"testing"
"time"
@ -1828,16 +1829,16 @@ ORDER BY film.film_id ASC;
testutils.AssertDeepEqual(t, maxRentalRateFilms[0], model.Film{
FilmID: 2,
Title: "Ace Goldfinger",
Description: testutils.StringPtr("A Astounding Epistle of a Database Administrator And a Explorer who must Find a Car in Ancient China"),
ReleaseYear: testutils.Int32Ptr(2006),
Description: ptr.Of("A Astounding Epistle of a Database Administrator And a Explorer who must Find a Car in Ancient China"),
ReleaseYear: ptr.Of(int32(2006)),
LanguageID: 1,
RentalRate: 4.99,
Length: testutils.Int16Ptr(48),
Length: ptr.Of(int16(48)),
ReplacementCost: 12.99,
Rating: &gRating,
RentalDuration: 3,
LastUpdate: *testutils.TimestampWithoutTimeZone("2013-05-26 14:50:58.951", 3),
SpecialFeatures: testutils.StringPtr("{Trailers,\"Deleted Scenes\"}"),
SpecialFeatures: ptr.Of("{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",
})
}
@ -2286,11 +2287,11 @@ ORDER BY customer_payment_sum.amount_sum ASC;
FirstName: "Brian",
LastName: "Wyman",
AddressID: 323,
Email: testutils.StringPtr("brian.wyman@sakilacustomer.org"),
Email: ptr.Of("brian.wyman@sakilacustomer.org"),
Activebool: true,
CreateDate: *testutils.TimestampWithoutTimeZone("2006-02-14 00:00:00", 0),
LastUpdate: testutils.TimestampWithoutTimeZone("2013-05-26 14:49:45.738", 3),
Active: testutils.Int32Ptr(1),
Active: ptr.Of(int32(1)),
})
require.Equal(t, customersWithAmounts[0].AmountSum, 27.93)
@ -3110,8 +3111,8 @@ func TestSelectDynamicCondition(t *testing.T) {
Active *bool
}
request.CustomerID = testutils.Int64Ptr(1)
request.Active = testutils.BoolPtr(true)
request.CustomerID = ptr.Of(int64(1))
request.Active = ptr.Of(true)
// ...
@ -3871,12 +3872,12 @@ var customer0 = model.Customer{
StoreID: 1,
FirstName: "Mary",
LastName: "Smith",
Email: testutils.StringPtr("mary.smith@sakilacustomer.org"),
Email: ptr.Of("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: testutils.Int32Ptr(1),
Active: ptr.Of(int32(1)),
}
var customer1 = model.Customer{
@ -3884,12 +3885,12 @@ var customer1 = model.Customer{
StoreID: 1,
FirstName: "Patricia",
LastName: "Johnson",
Email: testutils.StringPtr("patricia.johnson@sakilacustomer.org"),
Email: ptr.Of("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: testutils.Int32Ptr(1),
Active: ptr.Of(int32(1)),
}
var lastCustomer = model.Customer{
@ -3897,10 +3898,10 @@ var lastCustomer = model.Customer{
StoreID: 2,
FirstName: "Austin",
LastName: "Cintron",
Email: testutils.StringPtr("austin.cintron@sakilacustomer.org"),
Email: ptr.Of("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: testutils.Int32Ptr(1),
Active: ptr.Of(int32(1)),
}

View file

@ -0,0 +1,284 @@
package postgres
import (
"database/sql"
"github.com/go-jet/jet/v2/internal/testutils"
. "github.com/go-jet/jet/v2/postgres"
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/dvds/model"
. "github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/dvds/table"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"testing"
"time"
)
func TestVALUES(t *testing.T) {
values := VALUES(
WRAP(Int32(1), Int32(2), Float32(4.666), Bool(false), String("txt")),
WRAP(Int32(11).ADD(Int32(2)), Int32(22), Float32(33.222), Bool(true), String("png")),
WRAP(Int32(11), Int32(22), Float32(33.222), Bool(true), NULL),
).AS("values_table")
stmt := SELECT(
values.AllColumns(),
).FROM(
values,
)
testutils.AssertStatementSql(t, stmt, `
SELECT values_table.column1 AS "column1",
values_table.column2 AS "column2",
values_table.column3 AS "column3",
values_table.column4 AS "column4",
values_table.column5 AS "column5"
FROM (
VALUES ($1::integer, $2::integer, $3::real, $4::boolean, $5::text),
($6::integer + $7::integer, $8::integer, $9::real, $10::boolean, $11::text),
($12::integer, $13::integer, $14::real, $15::boolean, NULL)
) AS values_table;
`)
var dest []struct {
Column1 int
Column2 int
Column3 float32
Column4 bool
Column5 *string
}
err := stmt.Query(db, &dest)
require.NoError(t, err)
testutils.AssertJSON(t, dest, `
[
{
"Column1": 1,
"Column2": 2,
"Column3": 4.666,
"Column4": false,
"Column5": "txt"
},
{
"Column1": 13,
"Column2": 22,
"Column3": 33.222,
"Column4": true,
"Column5": "png"
},
{
"Column1": 11,
"Column2": 22,
"Column3": 33.222,
"Column4": true,
"Column5": null
}
]
`)
}
func TestVALUES_Join(t *testing.T) {
title := StringColumn("title")
releaseYear := IntegerColumn("ReleaseYear")
rentalRate := FloatColumn("rental_rate")
lastUpdate := Timestamp(2007, time.February, 11, 12, 0, 0)
filmValues := VALUES(
WRAP(String("Chamber Italian"), Int64(117), Int32(2005), Float32(5.82), lastUpdate),
WRAP(String("Grosse Wonderful"), Int64(49), Int32(2004), Float32(6.242), lastUpdate.ADD(INTERVAL(1, HOUR))),
WRAP(String("Airport Pollock"), Int64(54), Int32(2001), Float32(7.22), NULL),
WRAP(String("Bright Encounters"), Int64(73), Int32(2002), Float32(8.25), NULL),
WRAP(String("Academy Dinosaur"), Int64(83), Int32(2010), Float32(9.22), lastUpdate.SUB(INTERVAL(2, MINUTE))),
).AS("film_values",
title, IntegerColumn("length"), releaseYear, rentalRate, TimestampColumn("update_date"))
stmt := SELECT(
Film.AllColumns,
filmValues.AllColumns(),
).FROM(
Film.
INNER_JOIN(filmValues, title.EQ(Film.Title)),
).WHERE(AND(
Film.ReleaseYear.GT(releaseYear),
Film.RentalRate.LT(rentalRate),
)).ORDER_BY(
title,
)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT 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",
film_values.title AS "title",
film_values.length AS "length",
film_values."ReleaseYear" AS "ReleaseYear",
film_values.rental_rate AS "rental_rate",
film_values.update_date AS "update_date"
FROM dvds.film
INNER JOIN (
VALUES ('Chamber Italian'::text, 117::bigint, 2005::integer, 5.820000171661377::real, '2007-02-11 12:00:00'::timestamp without time zone),
('Grosse Wonderful'::text, 49::bigint, 2004::integer, 6.242000102996826::real, '2007-02-11 12:00:00'::timestamp without time zone + INTERVAL '1 HOUR'),
('Airport Pollock'::text, 54::bigint, 2001::integer, 7.21999979019165::real, NULL),
('Bright Encounters'::text, 73::bigint, 2002::integer, 8.25::real, NULL),
('Academy Dinosaur'::text, 83::bigint, 2010::integer, 9.220000267028809::real, '2007-02-11 12:00:00'::timestamp without time zone - INTERVAL '2 MINUTE')
) AS film_values (title, length, "ReleaseYear", rental_rate, update_date) ON (film_values.title = film.title)
WHERE (
(film.release_year > film_values."ReleaseYear")
AND (film.rental_rate < film_values.rental_rate)
)
ORDER BY film_values.title;
`)
//fmt.Println(stmt.DebugSql())
var dest []struct {
Film model.Film
Title string
Length int
ReleaseYear int
RentalRate float32
UpdateDate *time.Time
}
err := stmt.Query(db, &dest)
require.NoError(t, err)
assert.Len(t, dest, 4)
testutils.AssertJSON(t, dest[0:2], `
[
{
"Film": {
"FilmID": 8,
"Title": "Airport Pollock",
"Description": "A Epic Tale of a Moose And a Girl who must Confront a Monkey in Ancient India",
"ReleaseYear": 2006,
"LanguageID": 1,
"RentalDuration": 6,
"RentalRate": 4.99,
"Length": 54,
"ReplacementCost": 15.99,
"Rating": "R",
"LastUpdate": "2013-05-26T14:50:58.951Z",
"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",
"Length": 54,
"ReleaseYear": 2001,
"RentalRate": 7.22,
"UpdateDate": null
},
{
"Film": {
"FilmID": 98,
"Title": "Bright Encounters",
"Description": "A Fateful Yarn of a Lumberjack And a Feminist who must Conquer a Student in A Jet Boat",
"ReleaseYear": 2006,
"LanguageID": 1,
"RentalDuration": 4,
"RentalRate": 4.99,
"Length": 73,
"ReplacementCost": 12.99,
"Rating": "PG-13",
"LastUpdate": "2013-05-26T14:50:58.951Z",
"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",
"Length": 73,
"ReleaseYear": 2002,
"RentalRate": 8.25,
"UpdateDate": null
}
]
`)
}
func TestVALUES_CTE_Update(t *testing.T) {
paymentID := IntegerColumn("payment_ID")
increase := FloatColumn("increase")
paymentsToUpdate := CTE("values_cte", paymentID, increase)
stmt := WITH(
paymentsToUpdate.AS(
VALUES(
WRAP(Int32(20564), Float32(1.21)),
WRAP(Int32(20567), Float32(1.02)),
WRAP(Int32(20570), Float32(1.34)),
WRAP(Int32(20573), Float32(1.72)),
),
),
)(
Payment.UPDATE().
SET(
Payment.Amount.SET(Payment.Amount.MUL(CAST(increase).AS_DECIMAL())),
).
FROM(paymentsToUpdate).
WHERE(Payment.PaymentID.EQ(paymentID)).
RETURNING(Payment.AllColumns),
)
testutils.AssertDebugStatementSql(t, stmt, `
WITH values_cte ("payment_ID", increase) AS (
VALUES (20564::integer, 1.2100000381469727::real),
(20567::integer, 1.0199999809265137::real),
(20570::integer, 1.340000033378601::real),
(20573::integer, 1.7200000286102295::real)
)
UPDATE dvds.payment
SET amount = (payment.amount * values_cte.increase::decimal)
FROM values_cte
WHERE payment.payment_id = values_cte."payment_ID"
RETURNING payment.payment_id AS "payment.payment_id",
payment.customer_id AS "payment.customer_id",
payment.staff_id AS "payment.staff_id",
payment.rental_id AS "payment.rental_id",
payment.amount AS "payment.amount",
payment.payment_date AS "payment.payment_date";
`)
testutils.ExecuteInTxAndRollback(t, db, func(tx *sql.Tx) {
var payments []model.Payment
err := stmt.Query(tx, &payments)
require.NoError(t, err)
assert.Len(t, payments, 4)
testutils.AssertJSON(t, payments[0:2], `
[
{
"PaymentID": 20564,
"CustomerID": 379,
"StaffID": 2,
"RentalID": 11457,
"Amount": 4.83,
"PaymentDate": "2007-03-02T19:42:42.996577Z"
},
{
"PaymentID": 20567,
"CustomerID": 379,
"StaffID": 2,
"RentalID": 13397,
"Amount": 8.15,
"PaymentDate": "2007-03-19T20:35:01.996577Z"
}
]
`)
})
}

View file

@ -83,10 +83,10 @@ SELECT orders.ship_region AS "orders.ship_region",
SUM(order_details.quantity) AS "product_sales"
FROM northwind.orders
INNER JOIN northwind.order_details ON (orders.order_id = order_details.order_id)
WHERE orders.ship_region IN (
WHERE orders.ship_region IN ((
SELECT top_region."orders.ship_region" AS "orders.ship_region"
FROM top_region
)
))
GROUP BY orders.ship_region, order_details.product_id
ORDER BY SUM(order_details.quantity) DESC;
`)
@ -157,19 +157,19 @@ func TestWithStatementDeleteAndInsert(t *testing.T) {
testutils.AssertStatementSql(t, stmt, `
WITH remove_discontinued_orders AS (
DELETE FROM northwind.order_details
WHERE order_details.product_id IN (
WHERE order_details.product_id IN ((
SELECT products.product_id AS "products.product_id"
FROM northwind.products
WHERE products.discontinued = $1
)
))
RETURNING order_details.product_id AS "order_details.product_id"
),update_discontinued_price AS (
UPDATE northwind.products
SET unit_price = $2
WHERE products.product_id IN (
WHERE products.product_id IN ((
SELECT remove_discontinued_orders."order_details.product_id" AS "order_details.product_id"
FROM remove_discontinued_orders
)
))
RETURNING products.product_id AS "products.product_id",
products.product_name AS "products.product_name",
products.supplier_id AS "products.supplier_id",

View file

@ -2,6 +2,7 @@ package sqlite
import (
"github.com/go-jet/jet/v2/internal/testutils"
"github.com/go-jet/jet/v2/internal/utils/ptr"
. "github.com/go-jet/jet/v2/sqlite"
"github.com/go-jet/jet/v2/tests/.gentestdata/sqlite/test_sample/model"
. "github.com/go-jet/jet/v2/tests/.gentestdata/sqlite/test_sample/table"
@ -153,43 +154,43 @@ func TestAllTypesInsert(t *testing.T) {
var toInsert = model.AllTypes{
Boolean: false,
BooleanPtr: testutils.BoolPtr(true),
BooleanPtr: ptr.Of(true),
TinyInt: 1,
SmallInt: 3,
MediumInt: 5,
Integer: 7,
BigInt: 9,
TinyIntPtr: testutils.Int8Ptr(11),
SmallIntPtr: testutils.Int16Ptr(33),
MediumIntPtr: testutils.Int32Ptr(55),
IntegerPtr: testutils.Int32Ptr(77),
BigIntPtr: testutils.Int64Ptr(99),
TinyIntPtr: ptr.Of(int8(11)),
SmallIntPtr: ptr.Of(int16(33)),
MediumIntPtr: ptr.Of(int32(55)),
IntegerPtr: ptr.Of(int32(77)),
BigIntPtr: ptr.Of(int64(99)),
Decimal: 11.22,
DecimalPtr: testutils.Float64Ptr(33.44),
DecimalPtr: ptr.Of(33.44),
Numeric: 55.66,
NumericPtr: testutils.Float64Ptr(77.88),
NumericPtr: ptr.Of(77.88),
Float: 99.00,
FloatPtr: testutils.Float64Ptr(11.22),
FloatPtr: ptr.Of(11.22),
Double: 33.44,
DoublePtr: testutils.Float64Ptr(55.66),
DoublePtr: ptr.Of(55.66),
Real: 77.88,
RealPtr: testutils.Float32Ptr(99.00),
RealPtr: ptr.Of(float32(99.00)),
Time: time.Date(1, 1, 1, 1, 1, 1, 10, time.UTC),
TimePtr: testutils.TimePtr(time.Date(2, 2, 2, 2, 2, 2, 200, time.UTC)),
TimePtr: ptr.Of(time.Date(2, 2, 2, 2, 2, 2, 200, time.UTC)),
Date: time.Now(),
DatePtr: testutils.TimePtr(time.Now()),
DatePtr: ptr.Of(time.Now()),
DateTime: time.Now(),
DateTimePtr: testutils.TimePtr(time.Now()),
DateTimePtr: ptr.Of(time.Now()),
Timestamp: time.Now(),
TimestampPtr: testutils.TimePtr(time.Now()),
TimestampPtr: ptr.Of(time.Now()),
Char: "abcd",
CharPtr: testutils.StringPtr("absd"),
CharPtr: ptr.Of("absd"),
VarChar: "abcd",
VarCharPtr: testutils.StringPtr("absd"),
VarCharPtr: ptr.Of("absd"),
Blob: []byte("large file"),
BlobPtr: testutils.ByteArrayPtr([]byte("very large file")),
BlobPtr: ptr.Of([]byte("very large file")),
Text: "some text",
TextPtr: testutils.StringPtr("text"),
TextPtr: ptr.Of("text"),
}
func TestUUID(t *testing.T) {
@ -233,18 +234,18 @@ func TestExpressionOperators(t *testing.T) {
SELECT all_types.integer IS NULL AS "result.is_null",
all_types.date_ptr IS NOT NULL AS "result.is_not_null",
(all_types.small_int_ptr IN (?, ?)) AS "result.in",
(all_types.small_int_ptr IN (
(all_types.small_int_ptr IN ((
SELECT all_types.integer AS "all_types.integer"
FROM all_types
)) AS "result.in_select",
))) AS "result.in_select",
(length(121232459)) AS "result.raw",
(? + COALESCE(all_types.small_int_ptr, 0) + ?) AS "result.raw_arg",
(? + all_types.integer + ? + ? + ? + ?) AS "result.raw_arg2",
(all_types.small_int_ptr NOT IN (?, ?, NULL)) AS "result.not_in",
(all_types.small_int_ptr NOT IN (
(all_types.small_int_ptr NOT IN ((
SELECT all_types.integer AS "all_types.integer"
FROM all_types
)) AS "result.not_in_select"
))) AS "result.not_in_select"
FROM all_types
LIMIT ?;
`, "'", "`", -1), int64(11), int64(22), 78, 56, 11, 22, 11, 33, 44, int64(11), int64(22), int64(2))
@ -659,7 +660,7 @@ func TestExactDecimals(t *testing.T) {
// not overwritten
Numeric: "6.7",
NumericPtr: testutils.StringPtr("7.7"),
NumericPtr: ptr.Of("7.7"),
},
Decimal: decimal.RequireFromString("91.23"),
DecimalPtr: decimal.RequireFromString("45.67"),
@ -899,3 +900,36 @@ func TestDateTimeExpressions(t *testing.T) {
require.Equal(t, dest.JulianDay, 2.4551543576232754e+06)
require.Equal(t, dest.StrfTime, "20:34")
}
func TestRowExpression(t *testing.T) {
date := Date(2000, 9, 9)
time := Time(11, 22, 11)
dateTime := DateTime(2008, 11, 22, 10, 12, 40)
dateTime2 := DateTime(2011, 1, 2, 5, 12, 40)
stmt := SELECT(
ROW(Bool(false), date).EQ(ROW(Bool(true), date)),
ROW(Bool(false), time).NOT_EQ(ROW(Bool(true), time)),
ROW(time).IS_DISTINCT_FROM(RowExp(Raw("(time('now'))"))),
ROW(dateTime, dateTime2).GT(ROW(dateTime, dateTime2)),
ROW(dateTime2).GT_EQ(ROW(dateTime)),
ROW(dateTime, dateTime2).LT(ROW(dateTime, dateTime2)),
ROW(dateTime2).LT_EQ(ROW(dateTime2)),
)
//fmt.Println(stmt.Sql())
//fmt.Println(stmt.DebugSql())
testutils.AssertDebugStatementSql(t, stmt, `
SELECT (FALSE, DATE('2000-09-09')) = (TRUE, DATE('2000-09-09')),
(FALSE, TIME('11:22:11')) != (TRUE, TIME('11:22:11')),
(TIME('11:22:11')) IS NOT ((time('now'))),
(DATETIME('2008-11-22 10:12:40'), DATETIME('2011-01-02 05:12:40')) > (DATETIME('2008-11-22 10:12:40'), DATETIME('2011-01-02 05:12:40')),
(DATETIME('2011-01-02 05:12:40')) >= (DATETIME('2008-11-22 10:12:40')),
(DATETIME('2008-11-22 10:12:40'), DATETIME('2011-01-02 05:12:40')) < (DATETIME('2008-11-22 10:12:40'), DATETIME('2011-01-02 05:12:40')),
(DATETIME('2011-01-02 05:12:40')) <= (DATETIME('2011-01-02 05:12:40'));
`)
err := stmt.Query(db, &struct{}{})
require.NoError(t, err)
}

View file

@ -8,8 +8,11 @@ import (
"github.com/stretchr/testify/require"
"github.com/go-jet/jet/v2/generator/metadata"
"github.com/go-jet/jet/v2/generator/sqlite"
"github.com/go-jet/jet/v2/generator/template"
"github.com/go-jet/jet/v2/internal/testutils"
sqlite2 "github.com/go-jet/jet/v2/sqlite"
"github.com/go-jet/jet/v2/tests/.gentestdata/sqlite/sakila/model"
"github.com/go-jet/jet/v2/tests/internal/utils/repo"
)
@ -58,6 +61,36 @@ func TestGenerator(t *testing.T) {
require.NoError(t, err)
}
func TestGenerator_TableMetadata(t *testing.T) {
var schema metadata.Schema
err := sqlite.GenerateDSN(testDatabaseFilePath, genDestDir,
template.Default(sqlite2.Dialect).UseSchema(func(m metadata.Schema) template.Schema {
schema = m
return template.DefaultSchema(m)
}))
require.NoError(t, err)
// Spot check the actor table and assert that the emitted
// properties are as expected.
var got metadata.Table
for _, table := range schema.TablesMetaData {
if table.Name == "actor" {
got = table
}
}
want := metadata.Table{
Name: "actor",
Columns: []metadata.Column{
{Name: "actor_id", IsPrimaryKey: true, IsNullable: false, IsGenerated: false, HasDefault: false, DataType: metadata.DataType{Name: "INTEGER", Kind: "base", IsUnsigned: false}, Comment: ""},
{Name: "first_name", IsPrimaryKey: false, IsNullable: false, IsGenerated: false, HasDefault: false, DataType: metadata.DataType{Name: "VARCHAR", Kind: "base", IsUnsigned: false}, Comment: ""},
{Name: "last_name", IsPrimaryKey: false, IsNullable: false, IsGenerated: false, HasDefault: false, DataType: metadata.DataType{Name: "VARCHAR", Kind: "base", IsUnsigned: false}, Comment: ""},
{Name: "last_update", IsPrimaryKey: false, IsNullable: false, IsGenerated: false, HasDefault: true, DataType: metadata.DataType{Name: "TIMESTAMP", Kind: "base", IsUnsigned: false}, Comment: ""},
},
}
require.Equal(t, want, got)
}
func TestCmdGenerator(t *testing.T) {
cmd := exec.Command("jet", "-source=SQLite", "-dsn=file://"+testDatabaseFilePath, "-path="+genDestDir)

View file

@ -3,6 +3,8 @@ package sqlite
import (
"context"
"github.com/go-jet/jet/v2/qrm"
"database/sql"
"github.com/go-jet/jet/v2/internal/utils/ptr"
"math/rand"
"testing"
@ -49,7 +51,7 @@ VALUES (?, ?, ?, ?),
ID: 101,
URL: "http://www.google.com",
Name: "Google",
Description: testutils.StringPtr("Search engine"),
Description: ptr.Of("Search engine"),
})
testutils.AssertDeepEqual(t, insertedLinks[2], model.Link{
ID: 102,

View file

@ -8,16 +8,11 @@ import (
"github.com/go-jet/jet/v2/postgres"
"github.com/go-jet/jet/v2/sqlite"
"github.com/go-jet/jet/v2/tests/dbconfig"
"github.com/stretchr/testify/require"
"math/rand"
"os"
"os/exec"
"runtime"
"strings"
"testing"
"time"
"github.com/pkg/profile"
"github.com/stretchr/testify/require"
"os"
"runtime"
"testing"
_ "github.com/mattn/go-sqlite3"
)
@ -27,11 +22,8 @@ var sampleDB *sqlite.DB
var testRoot string
func TestMain(m *testing.M) {
rand.Seed(time.Now().Unix())
defer profile.Start().Stop()
setTestRoot()
sqlDB, err := sql.Open("sqlite3", "file:"+dbconfig.SakilaDBPath)
throw.OnError(err)
db = sqlite.NewDB(sqlDB).WithStatementsCaching(true)
@ -59,16 +51,6 @@ func TestMain(m *testing.M) {
}
}
func setTestRoot() {
cmd := exec.Command("git", "rev-parse", "--show-toplevel")
byteArr, err := cmd.Output()
if err != nil {
panic(err)
}
testRoot = strings.TrimSpace(string(byteArr)) + "/tests/"
}
var loggedSQL string
var loggedSQLArgs []interface{}
var loggedDebugSQL string

View file

@ -3,6 +3,7 @@ package sqlite
import (
"github.com/go-jet/jet/v2/internal/testutils"
"github.com/go-jet/jet/v2/qrm"
"github.com/go-jet/jet/v2/internal/utils/ptr"
"github.com/stretchr/testify/require"
"testing"
@ -54,7 +55,7 @@ WHERE people.people_id = ?;
).MODEL(
model.People{
PeopleName: "Dario",
PeopleHeightCm: testutils.Float64Ptr(190),
PeopleHeightCm: ptr.Of(190.0),
},
).RETURNING(
People.AllColumns,

View file

@ -2,6 +2,7 @@ package sqlite
import (
"context"
"github.com/go-jet/jet/v2/internal/utils/ptr"
model2 "github.com/go-jet/jet/v2/tests/.gentestdata/sqlite/chinook/model"
"github.com/go-jet/jet/v2/tests/.gentestdata/sqlite/chinook/table"
"strings"
@ -846,15 +847,15 @@ func TestSimpleView(t *testing.T) {
require.Equal(t, len(dest), 10)
require.Equal(t, dest[2], model.CustomerList{
ID: testutils.Int32Ptr(3),
Name: testutils.StringPtr("LINDA WILLIAMS"),
Address: testutils.StringPtr("692 Joliet Street"),
ZipCode: testutils.StringPtr("83579"),
Phone: testutils.StringPtr(" "),
City: testutils.StringPtr("Athenai"),
Country: testutils.StringPtr("Greece"),
Notes: testutils.StringPtr("active"),
Sid: testutils.Int32Ptr(1),
ID: ptr.Of(int32(3)),
Name: ptr.Of("LINDA WILLIAMS"),
Address: ptr.Of("692 Joliet Street"),
ZipCode: ptr.Of("83579"),
Phone: ptr.Of(" "),
City: ptr.Of("Athenai"),
Country: ptr.Of("Greece"),
Notes: ptr.Of("active"),
Sid: ptr.Of(int32(1)),
})
}

344
tests/sqlite/values_test.go Normal file
View file

@ -0,0 +1,344 @@
package sqlite
import (
"database/sql"
"github.com/go-jet/jet/v2/internal/testutils"
"github.com/stretchr/testify/require"
"strings"
"testing"
"time"
. "github.com/go-jet/jet/v2/sqlite"
"github.com/go-jet/jet/v2/tests/.gentestdata/sqlite/sakila/model"
. "github.com/go-jet/jet/v2/tests/.gentestdata/sqlite/sakila/table"
)
func TestVALUES(t *testing.T) {
values := VALUES(
ROW(Int32(1), Int32(2), Float(4.666), Bool(false), String("txt")),
ROW(Int32(11).ADD(Int32(2)), Int32(22), Float(33.222), Bool(true), String("png")),
ROW(Int32(11), Int32(22), Float(33.222), Bool(true), NULL),
).AS("values_table")
stmt := SELECT(
values.AllColumns(),
).FROM(
values,
)
testutils.AssertStatementSql(t, stmt, `
SELECT values_table.column1 AS "column1",
values_table.column2 AS "column2",
values_table.column3 AS "column3",
values_table.column4 AS "column4",
values_table.column5 AS "column5"
FROM (
VALUES (?, ?, ?, ?, ?),
(? + ?, ?, ?, ?, ?),
(?, ?, ?, ?, NULL)
) AS values_table;
`)
var dest []struct {
Column1 int
Column2 int
Column3 float32
Column4 bool
Column5 *string
}
err := stmt.Query(db, &dest)
require.NoError(t, err)
testutils.AssertJSON(t, dest, `
[
{
"Column1": 1,
"Column2": 2,
"Column3": 4.666,
"Column4": false,
"Column5": "txt"
},
{
"Column1": 13,
"Column2": 22,
"Column3": 33.222,
"Column4": true,
"Column5": "png"
},
{
"Column1": 11,
"Column2": 22,
"Column3": 33.222,
"Column4": true,
"Column5": null
}
]
`)
}
func TestVALUES_Join(t *testing.T) {
lastUpdate := DateTime(2007, time.February, 11, 12, 0, 0)
films := VALUES(
ROW(String("Chamber Italian"), Int64(117), Int32(2005), Float(5.82), lastUpdate),
ROW(String("Grosse Wonderful"), Int64(49), Int32(2004), Float(6.242), lastUpdate),
ROW(String("Airport Pollock"), Int64(54), Int32(2001), Float(7.22), NULL),
ROW(String("Bright Encounters"), Int64(73), Int32(2002), Float(8.25), NULL),
ROW(String("Academy Dinosaur"), Int64(83), Int32(2010), Float(9.22), DATETIME(lastUpdate, YEARS(2))),
).AS("film_values")
title := StringColumn("column1").From(films)
releaseYear := IntegerColumn("column3").From(films)
rentalRate := FloatColumn("column4").From(films)
stmt := SELECT(
Film.AllColumns,
films.AllColumns(),
).FROM(
Film.
INNER_JOIN(films, LOWER(title).EQ(LOWER(Film.Title))),
).WHERE(AND(
CAST(Film.ReleaseYear).AS_INTEGER().GT(releaseYear),
Film.RentalRate.LT(rentalRate),
)).ORDER_BY(
title,
)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT film.film_id AS "film.film_id",
film.title AS "film.title",
film.description AS "film.description",
film.release_year AS "film.release_year",
film.language_id AS "film.language_id",
film.original_language_id AS "film.original_language_id",
film.rental_duration AS "film.rental_duration",
film.rental_rate AS "film.rental_rate",
film.length AS "film.length",
film.replacement_cost AS "film.replacement_cost",
film.rating AS "film.rating",
film.special_features AS "film.special_features",
film.last_update AS "film.last_update",
film_values.column1 AS "column1",
film_values.column2 AS "column2",
film_values.column3 AS "column3",
film_values.column4 AS "column4",
film_values.column5 AS "column5"
FROM film
INNER JOIN (
VALUES ('Chamber Italian', 117, 2005, 5.82, DATETIME('2007-02-11 12:00:00')),
('Grosse Wonderful', 49, 2004, 6.242, DATETIME('2007-02-11 12:00:00')),
('Airport Pollock', 54, 2001, 7.22, NULL),
('Bright Encounters', 73, 2002, 8.25, NULL),
('Academy Dinosaur', 83, 2010, 9.22, DATETIME(DATETIME('2007-02-11 12:00:00'), '2 YEARS'))
) AS film_values ON (LOWER(film_values.column1) = LOWER(film.title))
WHERE (
(CAST(film.release_year AS INTEGER) > film_values.column3)
AND (film.rental_rate < film_values.column4)
)
ORDER BY film_values.column1;
`)
var dest []struct {
Film model.Film
Column1 string
Column2 int
Column3 int
Column4 float32
Column5 *time.Time
}
err := stmt.Query(db, &dest)
require.NoError(t, err)
testutils.AssertJSON(t, dest, `
[
{
"Film": {
"FilmID": 8,
"Title": "AIRPORT POLLOCK",
"Description": "A Epic Tale of a Moose And a Girl who must Confront a Monkey in Ancient India",
"ReleaseYear": "2006",
"LanguageID": 1,
"OriginalLanguageID": null,
"RentalDuration": 6,
"RentalRate": 4.99,
"Length": 54,
"ReplacementCost": 15.99,
"Rating": "R",
"SpecialFeatures": "Trailers",
"LastUpdate": "2019-04-11T18:11:48Z"
},
"Column1": "Airport Pollock",
"Column2": 54,
"Column3": 2001,
"Column4": 7.22,
"Column5": null
},
{
"Film": {
"FilmID": 98,
"Title": "BRIGHT ENCOUNTERS",
"Description": "A Fateful Yarn of a Lumberjack And a Feminist who must Conquer a Student in A Jet Boat",
"ReleaseYear": "2006",
"LanguageID": 1,
"OriginalLanguageID": null,
"RentalDuration": 4,
"RentalRate": 4.99,
"Length": 73,
"ReplacementCost": 12.99,
"Rating": "PG-13",
"SpecialFeatures": "Trailers",
"LastUpdate": "2019-04-11T18:11:48Z"
},
"Column1": "Bright Encounters",
"Column2": 73,
"Column3": 2002,
"Column4": 8.25,
"Column5": null
},
{
"Film": {
"FilmID": 133,
"Title": "CHAMBER ITALIAN",
"Description": "A Fateful Reflection of a Moose And a Husband who must Overcome a Monkey in Nigeria",
"ReleaseYear": "2006",
"LanguageID": 1,
"OriginalLanguageID": null,
"RentalDuration": 7,
"RentalRate": 4.99,
"Length": 117,
"ReplacementCost": 14.99,
"Rating": "NC-17",
"SpecialFeatures": "Trailers",
"LastUpdate": "2019-04-11T18:11:48Z"
},
"Column1": "Chamber Italian",
"Column2": 117,
"Column3": 2005,
"Column4": 5.82,
"Column5": "2007-02-11T12:00:00Z"
},
{
"Film": {
"FilmID": 384,
"Title": "GROSSE WONDERFUL",
"Description": "A Epic Drama of a Cat And a Explorer who must Redeem a Moose in Australia",
"ReleaseYear": "2006",
"LanguageID": 1,
"OriginalLanguageID": null,
"RentalDuration": 5,
"RentalRate": 4.99,
"Length": 49,
"ReplacementCost": 19.99,
"Rating": "R",
"SpecialFeatures": "Behind the Scenes",
"LastUpdate": "2019-04-11T18:11:48Z"
},
"Column1": "Grosse Wonderful",
"Column2": 49,
"Column3": 2004,
"Column4": 6.242,
"Column5": "2007-02-11T12:00:00Z"
}
]
`)
}
func TestVALUES_CTE_Update(t *testing.T) {
paymentID := IntegerColumn("payment_ID")
increase := FloatColumn("increase")
paymentsToUpdate := CTE("values_cte", paymentID, increase)
stmt := WITH(
paymentsToUpdate.AS(
VALUES(
ROW(Int32(204), Float(1.21)),
ROW(Int32(207), Float(1.02)),
ROW(Int32(200), Float(1.34)),
ROW(Int32(203), Float(1.72)),
),
),
)(
Payment.UPDATE().
SET(
Payment.Amount.SET(Payment.Amount.MUL(increase)),
).
FROM(paymentsToUpdate).
WHERE(Payment.PaymentID.EQ(paymentID)).
RETURNING(Payment.AllColumns),
)
testutils.AssertStatementSql(t, stmt, strings.ReplaceAll(`
WITH values_cte (''payment_ID'', increase) AS (
VALUES (?, ?),
(?, ?),
(?, ?),
(?, ?)
)
UPDATE payment
SET amount = (payment.amount * values_cte.increase)
FROM values_cte
WHERE payment.payment_id = values_cte.''payment_ID''
RETURNING payment.payment_id AS "payment.payment_id",
payment.customer_id AS "payment.customer_id",
payment.staff_id AS "payment.staff_id",
payment.rental_id AS "payment.rental_id",
payment.amount AS "payment.amount",
payment.payment_date AS "payment.payment_date",
payment.last_update AS "payment.last_update";
`, "''", "`"))
testutils.ExecuteInTxAndRollback(t, db, func(tx *sql.Tx) {
var payments []model.Payment
err := stmt.Query(tx, &payments)
require.NoError(t, err)
testutils.AssertJSON(t, payments, `
[
{
"PaymentID": 200,
"CustomerID": 7,
"StaffID": 2,
"RentalID": 11542,
"Amount": 10.706600000000002,
"PaymentDate": "2005-08-17T00:51:32Z",
"LastUpdate": "2019-04-11T18:11:50Z"
},
{
"PaymentID": 203,
"CustomerID": 7,
"StaffID": 2,
"RentalID": 13373,
"Amount": 5.1428,
"PaymentDate": "2005-08-19T21:23:31Z",
"LastUpdate": "2019-04-11T18:11:50Z"
},
{
"PaymentID": 204,
"CustomerID": 7,
"StaffID": 1,
"RentalID": 13476,
"Amount": 3.6179,
"PaymentDate": "2005-08-20T01:06:04Z",
"LastUpdate": "2019-04-11T18:11:50Z"
},
{
"PaymentID": 207,
"CustomerID": 8,
"StaffID": 2,
"RentalID": 866,
"Amount": 7.1298,
"PaymentDate": "2005-05-30T03:43:54Z",
"LastUpdate": "2019-04-11T18:11:50Z"
}
]
`)
})
}

View file

@ -153,10 +153,10 @@ WITH payments_to_update AS (
)
UPDATE payment
SET amount = 0
WHERE payment.payment_id IN (
WHERE payment.payment_id IN ((
SELECT payments_to_update.''payment.payment_id'' AS "payment.payment_id"
FROM payments_to_update
);
));
`, "''", "`", -1))
tx := beginDBTx(t)
@ -205,10 +205,10 @@ WITH payments_to_delete AS (
WHERE payment.amount < 0.5
)
DELETE FROM payment
WHERE payment.payment_id IN (
WHERE payment.payment_id IN ((
SELECT payments_to_delete.''payment.payment_id'' AS "payment.payment_id"
FROM payments_to_delete
);
));
`, "''", "`", -1))
tx := beginDBTx(t)

@ -1 +1 @@
Subproject commit 915bdc16b723d89becc577c780949baef861a6ae
Subproject commit 6a397747d310938b41d3950d68009578180d3dd5