Add support for VALUES statement.

This commit is contained in:
go-jet 2024-10-17 14:12:21 +02:00
parent 3fcbbec427
commit 8d112f7db8
41 changed files with 1296 additions and 131 deletions

View file

@ -92,3 +92,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

@ -4,7 +4,7 @@ import (
"database/sql"
"github.com/go-jet/jet/v2/internal/utils/ptr"
"github.com/stretchr/testify/assert"
"log/slog"
"testing"
"time"
@ -347,8 +347,6 @@ 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",
@ -376,9 +374,6 @@ LIMIT $11;
err := query.Query(db, &dest)
require.NoError(t, err)
//testutils.PrintJson(dest)
testutils.AssertJSON(t, dest, `
[
{
@ -936,7 +931,7 @@ func TestTimeExpression(t *testing.T) {
func TestIntervalSetFunctionality(t *testing.T) {
t.Run("updateQueryIntervalTest", func(t *testing.T) {
slog.Info("Running test", slog.Any("test", t.Name()))
expectedQuery := `
UPDATE test_sample.employee
SET pto_accrual = INTERVAL '3 HOUR'

View file

@ -2,6 +2,7 @@ package postgres
import (
"github.com/go-jet/jet/v2/internal/testutils"
. "github.com/go-jet/jet/v2/postgres"
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/northwind/model"
. "github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/northwind/table"
"github.com/stretchr/testify/require"
@ -10,19 +11,7 @@ import (
func TestNorthwindJoinEverything(t *testing.T) {
stmt := Customers.
LEFT_JOIN(CustomerCustomerDemo, Customers.CustomerID.EQ(CustomerCustomerDemo.CustomerID)).
LEFT_JOIN(CustomerDemographics, CustomerCustomerDemo.CustomerTypeID.EQ(CustomerDemographics.CustomerTypeID)).
LEFT_JOIN(Orders, Orders.CustomerID.EQ(Customers.CustomerID)).
LEFT_JOIN(Shippers, Orders.ShipVia.EQ(Shippers.ShipperID)).
LEFT_JOIN(OrderDetails, Orders.OrderID.EQ(OrderDetails.OrderID)).
LEFT_JOIN(Products, OrderDetails.ProductID.EQ(Products.ProductID)).
LEFT_JOIN(Categories, Products.CategoryID.EQ(Categories.CategoryID)).
LEFT_JOIN(Suppliers, Products.SupplierID.EQ(Suppliers.SupplierID)).
LEFT_JOIN(Employees, Orders.EmployeeID.EQ(Employees.EmployeeID)).
LEFT_JOIN(EmployeeTerritories, EmployeeTerritories.EmployeeID.EQ(Employees.EmployeeID)).
LEFT_JOIN(Territories, EmployeeTerritories.TerritoryID.EQ(Territories.TerritoryID)).
LEFT_JOIN(Region, Territories.RegionID.EQ(Region.RegionID)).
stmt :=
SELECT(
Customers.AllColumns,
CustomerDemographics.AllColumns,
@ -32,8 +21,21 @@ func TestNorthwindJoinEverything(t *testing.T) {
Products.AllColumns,
Categories.AllColumns,
Suppliers.AllColumns,
).
ORDER_BY(Customers.CustomerID, Orders.OrderID, Products.ProductID)
).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

@ -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

@ -283,7 +283,7 @@ func TestUpdateContextDeadlineExceeded(t *testing.T) {
time.Sleep(10 * time.Millisecond)
dest := []model.Link{}
var dest []model.Link
err := updateStmt.QueryContext(ctx, tx, &dest)
require.Error(t, err, "context deadline exceeded")

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"
}
]
`)
})
}