jet/tests/postgres/select_test.go
2025-03-16 12:54:32 +01:00

4000 lines
104 KiB
Go

package postgres
import (
"context"
"database/sql"
"github.com/go-jet/jet/v2/internal/utils/ptr"
"testing"
"time"
"github.com/go-jet/jet/v2/qrm"
"gopkg.in/guregu/null.v4"
"github.com/stretchr/testify/require"
"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/enum"
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/dvds/model"
. "github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/dvds/table"
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/dvds/view"
)
func TestSelect_ScanToStruct(t *testing.T) {
t.Run("standard", func(t *testing.T) {
stmt := SELECT(Actor.AllColumns).
DISTINCT().
FROM(Actor).
WHERE(Actor.ActorID.EQ(Int(2)))
testutils.AssertDebugStatementSql(t, stmt, `
SELECT DISTINCT actor.actor_id AS "actor.actor_id",
actor.first_name AS "actor.first_name",
actor.last_name AS "actor.last_name",
actor.last_update AS "actor.last_update"
FROM dvds.actor
WHERE actor.actor_id = 2;
`, int64(2))
var dest model.Actor
err := stmt.Query(db, &dest)
require.NoError(t, err)
testutils.AssertDeepEqual(t, dest, actor2)
requireLogged(t, stmt)
})
}
var actor2 = model.Actor{
ActorID: 2,
FirstName: "Nick",
LastName: "Wahlberg",
LastUpdate: *testutils.TimestampWithoutTimeZone("2013-05-26 14:47:57.62", 2),
}
func TestSelectDistinctOn(t *testing.T) {
stmt := SELECT(
Rental.StaffID,
Rental.CustomerID,
Rental.RentalID,
).DISTINCT(
Rental.StaffID,
Rental.CustomerID,
).FROM(
Rental,
).WHERE(
Rental.CustomerID.LT(Int(2)),
).ORDER_BY(
Rental.StaffID.ASC(),
Rental.CustomerID.ASC(),
Rental.RentalID.ASC(),
)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT DISTINCT ON (rental.staff_id, rental.customer_id) rental.staff_id AS "rental.staff_id",
rental.customer_id AS "rental.customer_id",
rental.rental_id AS "rental.rental_id"
FROM dvds.rental
WHERE rental.customer_id < 2
ORDER BY rental.staff_id ASC, rental.customer_id ASC, rental.rental_id ASC;
`)
var dest []model.Rental
err := stmt.Query(db, &dest)
require.NoError(t, err)
testutils.AssertJSON(t, dest, `
[
{
"RentalID": 573,
"RentalDate": "0001-01-01T00:00:00Z",
"InventoryID": 0,
"CustomerID": 1,
"ReturnDate": null,
"StaffID": 1,
"LastUpdate": "0001-01-01T00:00:00Z"
},
{
"RentalID": 76,
"RentalDate": "0001-01-01T00:00:00Z",
"InventoryID": 0,
"CustomerID": 1,
"ReturnDate": null,
"StaffID": 2,
"LastUpdate": "0001-01-01T00:00:00Z"
}
]
`)
}
func TestSelectClassic(t *testing.T) {
expectedSQL := `
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",
customer.customer_id AS "customer.customer_id",
customer.store_id AS "customer.store_id",
customer.first_name AS "customer.first_name",
customer.last_name AS "customer.last_name",
customer.email AS "customer.email",
customer.address_id AS "customer.address_id",
customer.activebool AS "customer.activebool",
customer.create_date AS "customer.create_date",
customer.last_update AS "customer.last_update",
customer.active AS "customer.active"
FROM dvds.payment
INNER JOIN dvds.customer ON (payment.customer_id = customer.customer_id)
ORDER BY payment.payment_id ASC
LIMIT 30;
`
query := SELECT(
Payment.AllColumns,
Customer.AllColumns,
).FROM(
Payment.
INNER_JOIN(Customer, Payment.CustomerID.EQ(Customer.CustomerID)),
).ORDER_BY(
Payment.PaymentID.ASC(),
).LIMIT(30)
testutils.AssertDebugStatementSql(t, query, expectedSQL, int64(30))
var dest []struct {
model.Payment
Customer model.Customer
}
err := query.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 30)
requireLogged(t, query)
}
func TestSelect_ScanToSlice(t *testing.T) {
expectedSQL := `
SELECT customer.customer_id AS "customer.customer_id",
customer.store_id AS "customer.store_id",
customer.first_name AS "customer.first_name",
customer.last_name AS "customer.last_name",
customer.email AS "customer.email",
customer.address_id AS "customer.address_id",
customer.activebool AS "customer.activebool",
customer.create_date AS "customer.create_date",
customer.last_update AS "customer.last_update",
customer.active AS "customer.active"
FROM dvds.customer
ORDER BY customer.customer_id ASC;
`
var customers []model.Customer
query := Customer.SELECT(Customer.AllColumns).ORDER_BY(Customer.CustomerID.ASC())
testutils.AssertDebugStatementSql(t, query, expectedSQL)
err := query.Query(db, &customers)
require.NoError(t, err)
require.Equal(t, len(customers), 599)
testutils.AssertDeepEqual(t, customer0, customers[0])
testutils.AssertDeepEqual(t, customer1, customers[1])
testutils.AssertDeepEqual(t, lastCustomer, customers[598])
requireLogged(t, query)
t.Run("select json", func(t *testing.T) {
stmt := SELECT_JSON_ARR(
Customer.AllColumns,
).FROM(
Customer,
).ORDER_BY(Customer.CustomerID.ASC())
var dest []model.Customer
err := stmt.QueryContext(ctx, db, &dest)
require.NoError(t, err)
testutils.AssertDeepEqual(t, customers, dest)
})
}
func TestSelectAndUnionInProjection(t *testing.T) {
expectedSQL := `
SELECT payment.payment_id AS "payment.payment_id",
(
SELECT customer.customer_id AS "customer.customer_id"
FROM dvds.customer
LIMIT 1
),
(
(
SELECT payment.payment_id AS "payment.payment_id"
FROM dvds.payment
LIMIT 1
OFFSET 10
)
UNION
(
SELECT payment.payment_id AS "payment.payment_id"
FROM dvds.payment
LIMIT 1
OFFSET 2
)
LIMIT 1
)
FROM dvds.payment
LIMIT 12;
`
query := SELECT(
Payment.PaymentID,
Customer.SELECT(Customer.CustomerID).LIMIT(1),
UNION(
Payment.SELECT(Payment.PaymentID).LIMIT(1).OFFSET(10),
Payment.SELECT(Payment.PaymentID).LIMIT(1).OFFSET(2),
).LIMIT(1),
).FROM(Payment).
LIMIT(12)
//fmt.Println(query.DebugSql())
testutils.AssertDebugStatementSql(t, query, expectedSQL, int64(1), int64(1), int64(10), int64(1), int64(2), int64(1), int64(12))
var dest []struct{}
allowUnusedColumns(func() {
err := query.Query(db, &dest)
require.NoError(t, err)
})
}
func TestSelectFetchFirst(t *testing.T) {
t.Run("rows only", func(t *testing.T) {
stmt := SELECT(Actor.AllColumns).
FROM(Actor).
ORDER_BY(Actor.ActorID).
OFFSET(2).
FETCH_FIRST(Int(3)).ROWS_ONLY()
testutils.AssertStatementSql(t, stmt, `
SELECT actor.actor_id AS "actor.actor_id",
actor.first_name AS "actor.first_name",
actor.last_name AS "actor.last_name",
actor.last_update AS "actor.last_update"
FROM dvds.actor
ORDER BY actor.actor_id
OFFSET $1
FETCH FIRST $2 ROWS ONLY;
`)
var dest []model.Actor
err := stmt.Query(db, &dest)
require.NoError(t, err)
require.Len(t, dest, 3)
require.Equal(t, dest[0].ActorID, int32(3))
require.Equal(t, dest[2].ActorID, int32(5))
})
t.Run("rows with ties", func(t *testing.T) {
skipForCockroachDB(t) // ROWS_WITH_TIES is not supported on cockroachdb
stmt := SELECT(Actor.AllColumns).
FROM(Actor).
ORDER_BY(Actor.LastUpdate).
FETCH_FIRST(Int(3)).ROWS_WITH_TIES()
testutils.AssertStatementSql(t, stmt, `
SELECT actor.actor_id AS "actor.actor_id",
actor.first_name AS "actor.first_name",
actor.last_name AS "actor.last_name",
actor.last_update AS "actor.last_update"
FROM dvds.actor
ORDER BY actor.last_update
FETCH FIRST $1 ROWS WITH TIES;
`)
var dest []model.Actor
err := stmt.Query(db, &dest)
require.NoError(t, err)
require.Len(t, dest, 200)
})
t.Run("complex expression", func(t *testing.T) {
stmt := SELECT(Actor.AllColumns).
FROM(Actor).
ORDER_BY(Actor.LastUpdate).
FETCH_FIRST(IntExp(
SELECT(MAX(Store.StoreID)).
FROM(Store),
)).ROWS_ONLY()
testutils.AssertDebugStatementSql(t, stmt, `
SELECT actor.actor_id AS "actor.actor_id",
actor.first_name AS "actor.first_name",
actor.last_name AS "actor.last_name",
actor.last_update AS "actor.last_update"
FROM dvds.actor
ORDER BY actor.last_update
FETCH FIRST (
SELECT MAX(store.store_id)
FROM dvds.store
) ROWS ONLY;
`)
var dest []model.Actor
err := stmt.Query(db, &dest)
require.NoError(t, err)
require.Len(t, dest, 2)
})
}
func TestSelectOffsetExpression(t *testing.T) {
stmt := SELECT(Actor.AllColumns).
FROM(Actor).
ORDER_BY(Actor.ActorID).
OFFSET_e(IntExp(
SELECT(MAX(Store.StoreID)).
FROM(Store),
)).LIMIT(10)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT actor.actor_id AS "actor.actor_id",
actor.first_name AS "actor.first_name",
actor.last_name AS "actor.last_name",
actor.last_update AS "actor.last_update"
FROM dvds.actor
ORDER BY actor.actor_id
LIMIT 10
OFFSET (
SELECT MAX(store.store_id)
FROM dvds.store
);
`)
var dest []model.Actor
err := stmt.Query(db, &dest)
require.NoError(t, err)
require.Len(t, dest, 10)
require.Equal(t, dest[0].ActorID, int32(3))
}
func TestSelectJoinQueryStruct(t *testing.T) {
expectedSQL := `
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",
language.language_id AS "language.language_id",
language.name AS "language.name",
language.last_update AS "language.last_update",
actor.actor_id AS "actor.actor_id",
actor.first_name AS "actor.first_name",
actor.last_name AS "actor.last_name",
actor.last_update AS "actor.last_update",
inventory.inventory_id AS "inventory.inventory_id",
inventory.film_id AS "inventory.film_id",
inventory.store_id AS "inventory.store_id",
inventory.last_update AS "inventory.last_update",
rental.rental_id AS "rental.rental_id",
rental.rental_date AS "rental.rental_date",
rental.inventory_id AS "rental.inventory_id",
rental.customer_id AS "rental.customer_id",
rental.return_date AS "rental.return_date",
rental.staff_id AS "rental.staff_id",
rental.last_update AS "rental.last_update"
FROM dvds.film_actor
INNER JOIN dvds.actor ON (film_actor.actor_id = actor.actor_id)
INNER JOIN dvds.film ON (film_actor.film_id = film.film_id)
INNER JOIN dvds.language ON (film.language_id = language.language_id)
INNER JOIN dvds.inventory ON (inventory.film_id = film.film_id)
INNER JOIN dvds.rental ON (rental.inventory_id = inventory.inventory_id)
ORDER BY film.film_id ASC
LIMIT 1000;
`
for i := 0; i < 2; i++ {
query := FilmActor.
INNER_JOIN(Actor, FilmActor.ActorID.EQ(Actor.ActorID)).
INNER_JOIN(Film, FilmActor.FilmID.EQ(Film.FilmID)).
INNER_JOIN(Language, Film.LanguageID.EQ(Language.LanguageID)).
INNER_JOIN(Inventory, Inventory.FilmID.EQ(Film.FilmID)).
INNER_JOIN(Rental, Rental.InventoryID.EQ(Inventory.InventoryID)).
SELECT(
Film.AllColumns,
Language.AllColumns,
Actor.AllColumns,
Inventory.AllColumns,
Rental.AllColumns,
).
//WHERE(FilmActor.ActorID.GtEqL(1).AND(FilmActor.ActorID.LtEqL(2))).
ORDER_BY(Film.FilmID.ASC()).
LIMIT(1000)
testutils.AssertDebugStatementSql(t, query, expectedSQL, int64(1000))
var languageActorFilm []struct {
model.Language
Films []struct {
model.Film
Actors []struct {
model.Actor
}
Inventory []struct {
model.Inventory
Rental []model.Rental
}
}
}
err := query.Query(db, &languageActorFilm)
require.NoError(t, err)
require.Equal(t, len(languageActorFilm), 1)
require.Equal(t, len(languageActorFilm[0].Films), 10)
require.Equal(t, len(languageActorFilm[0].Films[0].Actors), 10)
}
}
func TestSelectJoinQuerySlice(t *testing.T) {
expectedSQL := `
SELECT language.language_id AS "language.language_id",
language.name AS "language.name",
language.last_update AS "language.last_update",
film.film_id AS "film.film_id",
film.title AS "film.title",
film.description AS "film.description",
film.release_year AS "film.release_year",
film.language_id AS "film.language_id",
film.rental_duration AS "film.rental_duration",
film.rental_rate AS "film.rental_rate",
film.length AS "film.length",
film.replacement_cost AS "film.replacement_cost",
film.rating AS "film.rating",
film.last_update AS "film.last_update",
film.special_features AS "film.special_features",
film.fulltext AS "film.fulltext"
FROM dvds.film
INNER JOIN dvds.language ON (film.language_id = language.language_id)
WHERE film.rating = 'NC-17'
LIMIT 15;
`
type FilmsPerLanguage struct {
Language *model.Language
Film []model.Film
}
var filmsPerLanguage []FilmsPerLanguage
limit := 15
query := Film.
INNER_JOIN(Language, Film.LanguageID.EQ(Language.LanguageID)).
SELECT(Language.AllColumns, Film.AllColumns).
WHERE(Film.Rating.EQ(enum.MpaaRating.Nc17)).
LIMIT(15)
testutils.AssertDebugStatementSql(t, query, expectedSQL, int64(15))
err := query.Query(db, &filmsPerLanguage)
require.NoError(t, err)
require.Equal(t, len(filmsPerLanguage), 1)
require.Equal(t, len(filmsPerLanguage[0].Film), limit)
englishFilms := filmsPerLanguage[0]
require.Equal(t, *englishFilms.Film[0].Rating, model.MpaaRating_Nc17)
filmsPerLanguageWithPtrs := []*FilmsPerLanguage{}
err = query.Query(db, &filmsPerLanguageWithPtrs)
require.NoError(t, err)
require.Equal(t, len(filmsPerLanguage), 1)
require.Equal(t, len(filmsPerLanguage[0].Film), limit)
}
// https://github.com/go-jet/jet/issues/226
func TestSelectDuplicateSlicesInDestination(t *testing.T) {
type Staffs struct {
StaffList []model.Staff
}
type MyStore struct {
model.Store
StaffList []model.Staff
StaffList2 []model.Staff
Staffs Staffs
}
stmt := SELECT(
Store.AllColumns,
Staff.AllColumns,
).FROM(
Store.INNER_JOIN(
Staff,
Staff.StoreID.EQ(Store.StoreID),
),
)
var dest []MyStore
err := stmt.Query(db, &dest)
require.NoError(t, err)
testutils.AssertJSON(t, dest, `
[
{
"StoreID": 1,
"ManagerStaffID": 1,
"AddressID": 1,
"LastUpdate": "2006-02-15T09:57:12Z",
"StaffList": [
{
"StaffID": 1,
"FirstName": "Mike",
"LastName": "Hillyer",
"AddressID": 3,
"Email": "Mike.Hillyer@sakilastaff.com",
"StoreID": 1,
"Active": true,
"Username": "Mike",
"Password": "8cb2237d0679ca88db6464eac60da96345513964",
"LastUpdate": "2006-05-16T16:13:11.79328Z",
"Picture": "iVBORw0KWgo="
}
],
"StaffList2": [
{
"StaffID": 1,
"FirstName": "Mike",
"LastName": "Hillyer",
"AddressID": 3,
"Email": "Mike.Hillyer@sakilastaff.com",
"StoreID": 1,
"Active": true,
"Username": "Mike",
"Password": "8cb2237d0679ca88db6464eac60da96345513964",
"LastUpdate": "2006-05-16T16:13:11.79328Z",
"Picture": "iVBORw0KWgo="
}
],
"Staffs": {
"StaffList": [
{
"StaffID": 1,
"FirstName": "Mike",
"LastName": "Hillyer",
"AddressID": 3,
"Email": "Mike.Hillyer@sakilastaff.com",
"StoreID": 1,
"Active": true,
"Username": "Mike",
"Password": "8cb2237d0679ca88db6464eac60da96345513964",
"LastUpdate": "2006-05-16T16:13:11.79328Z",
"Picture": "iVBORw0KWgo="
}
]
}
},
{
"StoreID": 2,
"ManagerStaffID": 2,
"AddressID": 2,
"LastUpdate": "2006-02-15T09:57:12Z",
"StaffList": [
{
"StaffID": 2,
"FirstName": "Jon",
"LastName": "Stephens",
"AddressID": 4,
"Email": "Jon.Stephens@sakilastaff.com",
"StoreID": 2,
"Active": true,
"Username": "Jon",
"Password": "8cb2237d0679ca88db6464eac60da96345513964",
"LastUpdate": "2006-05-16T16:13:11.79328Z",
"Picture": null
}
],
"StaffList2": [
{
"StaffID": 2,
"FirstName": "Jon",
"LastName": "Stephens",
"AddressID": 4,
"Email": "Jon.Stephens@sakilastaff.com",
"StoreID": 2,
"Active": true,
"Username": "Jon",
"Password": "8cb2237d0679ca88db6464eac60da96345513964",
"LastUpdate": "2006-05-16T16:13:11.79328Z",
"Picture": null
}
],
"Staffs": {
"StaffList": [
{
"StaffID": 2,
"FirstName": "Jon",
"LastName": "Stephens",
"AddressID": 4,
"Email": "Jon.Stephens@sakilastaff.com",
"StoreID": 2,
"Active": true,
"Username": "Jon",
"Password": "8cb2237d0679ca88db6464eac60da96345513964",
"LastUpdate": "2006-05-16T16:13:11.79328Z",
"Picture": null
}
]
}
}
]
`)
}
func TestSelectExecution1(t *testing.T) {
stmt := City.
INNER_JOIN(Address, Address.CityID.EQ(City.CityID)).
INNER_JOIN(Customer, Customer.AddressID.EQ(Address.AddressID)).
SELECT(
City.CityID,
City.City,
Address.AddressID,
Address.Address,
Customer.CustomerID,
Customer.LastName,
).
WHERE(
OR(
City.City.EQ(Text("London")),
City.City.EQ(Text("York")),
),
).
ORDER_BY(
City.CityID, Address.AddressID, Customer.CustomerID,
)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT city.city_id AS "city.city_id",
city.city AS "city.city",
address.address_id AS "address.address_id",
address.address AS "address.address",
customer.customer_id AS "customer.customer_id",
customer.last_name AS "customer.last_name"
FROM dvds.city
INNER JOIN dvds.address ON (address.city_id = city.city_id)
INNER JOIN dvds.customer ON (customer.address_id = address.address_id)
WHERE (
(city.city = 'London'::text)
OR (city.city = 'York'::text)
)
ORDER BY city.city_id, address.address_id, customer.customer_id;
`, "London", "York")
var dest []struct {
model.City
Customers []struct {
model.Customer
Address model.Address
}
}
err := stmt.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 2)
require.Equal(t, dest[0].City.City, "London")
require.Equal(t, dest[1].City.City, "York")
require.Equal(t, len(dest[0].Customers), 2)
require.Equal(t, dest[0].Customers[0].LastName, "Hoffman")
require.Equal(t, dest[0].Customers[1].LastName, "Vines")
}
func TestSelectExecution2(t *testing.T) {
type MyAddress struct {
ID int32 `sql:"primary_key"`
AddressLine string
}
type MyCustomer struct {
ID int32 `sql:"primary_key"`
LastName *string
Address MyAddress
}
type MyCity struct {
ID int32 `sql:"primary_key"`
Name string
Customers []MyCustomer
}
dest := []MyCity{}
stmt := City.
INNER_JOIN(Address, Address.CityID.EQ(City.CityID)).
INNER_JOIN(Customer, Customer.AddressID.EQ(Address.AddressID)).
SELECT(
City.CityID.AS("my_city.id"),
City.City.AS("myCity.Name"),
Address.AddressID.AS("My_Address.id"),
Address.Address.AS("my address.address line"),
Customer.CustomerID.AS("my_customer.id"),
Customer.LastName.AS("my_customer.last_name"),
).
WHERE(City.City.EQ(VarChar()("London")).OR(City.City.EQ(VarChar()("York")))).
ORDER_BY(City.CityID, Address.AddressID, Customer.CustomerID)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT city.city_id AS "my_city.id",
city.city AS "myCity.Name",
address.address_id AS "My_Address.id",
address.address AS "my address.address line",
customer.customer_id AS "my_customer.id",
customer.last_name AS "my_customer.last_name"
FROM dvds.city
INNER JOIN dvds.address ON (address.city_id = city.city_id)
INNER JOIN dvds.customer ON (customer.address_id = address.address_id)
WHERE (city.city = 'London'::varchar) OR (city.city = 'York'::varchar)
ORDER BY city.city_id, address.address_id, customer.customer_id;
`, "London", "York")
err := stmt.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 2)
require.Equal(t, dest[0].Name, "London")
require.Equal(t, dest[1].Name, "York")
require.Equal(t, len(dest[0].Customers), 2)
require.Equal(t, *dest[0].Customers[0].LastName, "Hoffman")
require.Equal(t, *dest[0].Customers[1].LastName, "Vines")
}
func TestSelectExecution3(t *testing.T) {
var dest []struct {
CityID int32 `sql:"primary_key"`
CityName string
Customers []struct {
CustomerID int32 `sql:"primary_key"`
LastName *string
Address struct {
AddressID int32 `sql:"primary_key"`
AddressLine string
}
}
}
stmt := City.
INNER_JOIN(Address, Address.CityID.EQ(City.CityID)).
INNER_JOIN(Customer, Customer.AddressID.EQ(Address.AddressID)).
SELECT(
City.CityID.AS("city_id"),
City.City.AS("city_name"),
Customer.CustomerID.AS("customer_id"),
Customer.LastName.AS("last_name"),
Address.AddressID.AS("address_id"),
Address.Address.AS("address_line"),
).
WHERE(City.City.EQ(VarChar(20)("London")).OR(City.City.EQ(VarChar(20)("York")))).
ORDER_BY(City.CityID, Address.AddressID, Customer.CustomerID)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT city.city_id AS "city_id",
city.city AS "city_name",
customer.customer_id AS "customer_id",
customer.last_name AS "last_name",
address.address_id AS "address_id",
address.address AS "address_line"
FROM dvds.city
INNER JOIN dvds.address ON (address.city_id = city.city_id)
INNER JOIN dvds.customer ON (customer.address_id = address.address_id)
WHERE (city.city = 'London'::varchar(20)) OR (city.city = 'York'::varchar(20))
ORDER BY city.city_id, address.address_id, customer.customer_id;
`, "London", "York")
err := stmt.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 2)
require.Equal(t, dest[0].CityName, "London")
require.Equal(t, dest[1].CityName, "York")
require.Equal(t, len(dest[0].Customers), 2)
require.Equal(t, *dest[0].Customers[0].LastName, "Hoffman")
require.Equal(t, *dest[0].Customers[1].LastName, "Vines")
}
func TestSelectExecution4(t *testing.T) {
var dest []struct {
CityID int32 `sql:"primary_key" alias:"city.city_id"`
CityName string `alias:"city.city"`
Customers []struct {
CustomerID int32 `sql:"primary_key" alias:"customer_id"`
LastName *string `alias:"last_name"`
Address struct {
AddressID int32 `sql:"primary_key" alias:"AddressId"`
AddressLine string `alias:"address.address"`
} `alias:"address.*"`
} `alias:"customer"`
}
stmt := City.
INNER_JOIN(Address, Address.CityID.EQ(City.CityID)).
INNER_JOIN(Customer, Customer.AddressID.EQ(Address.AddressID)).
SELECT(
City.CityID,
City.City,
Customer.CustomerID,
Customer.LastName,
Address.AddressID,
Address.Address,
).
WHERE(City.City.EQ(String("London")).OR(City.City.EQ(String("York")))).
ORDER_BY(City.CityID, Address.AddressID, Customer.CustomerID)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT city.city_id AS "city.city_id",
city.city AS "city.city",
customer.customer_id AS "customer.customer_id",
customer.last_name AS "customer.last_name",
address.address_id AS "address.address_id",
address.address AS "address.address"
FROM dvds.city
INNER JOIN dvds.address ON (address.city_id = city.city_id)
INNER JOIN dvds.customer ON (customer.address_id = address.address_id)
WHERE (city.city = 'London'::text) OR (city.city = 'York'::text)
ORDER BY city.city_id, address.address_id, customer.customer_id;
`, "London", "York")
err := stmt.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 2)
testutils.AssertJSON(t, dest, `
[
{
"CityID": 312,
"CityName": "London",
"Customers": [
{
"CustomerID": 252,
"LastName": "Hoffman",
"Address": {
"AddressID": 256,
"AddressLine": "1497 Yuzhou Drive"
}
},
{
"CustomerID": 512,
"LastName": "Vines",
"Address": {
"AddressID": 517,
"AddressLine": "548 Uruapan Street"
}
}
]
},
{
"CityID": 589,
"CityName": "York",
"Customers": [
{
"CustomerID": 497,
"LastName": "Sledge",
"Address": {
"AddressID": 502,
"AddressLine": "1515 Korla Way"
}
}
]
}
]
`)
}
// Test join with custom primary keys (sql.NullInt64)
func TestSelectExecutionCustomPKTypes1(t *testing.T) {
var dest []struct {
CityID sql.NullInt64 `sql:"primary_key" alias:"city.city_id"`
CityName string `alias:"city.city"`
Customers []struct {
CustomerID sql.NullInt64 `sql:"primary_key" alias:"customer_id"`
LastName *string `alias:"last_name"`
Address struct {
AddressID sql.NullInt64 `sql:"primary_key" alias:"AddressId"`
AddressLine string `alias:"address.address"`
} `alias:"address.*"`
} `alias:"customer"`
}
stmt := SELECT(
City.CityID,
City.City,
Customer.CustomerID,
Customer.LastName,
Address.AddressID,
Address.Address,
).FROM(
City.
INNER_JOIN(Address, Address.CityID.EQ(City.CityID)).
INNER_JOIN(Customer, Customer.AddressID.EQ(Address.AddressID)),
).WHERE(
City.City.EQ(String("London")).OR(City.City.EQ(String("York"))),
).ORDER_BY(
City.CityID,
Address.AddressID,
Customer.CustomerID,
)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT city.city_id AS "city.city_id",
city.city AS "city.city",
customer.customer_id AS "customer.customer_id",
customer.last_name AS "customer.last_name",
address.address_id AS "address.address_id",
address.address AS "address.address"
FROM dvds.city
INNER JOIN dvds.address ON (address.city_id = city.city_id)
INNER JOIN dvds.customer ON (customer.address_id = address.address_id)
WHERE (city.city = 'London'::text) OR (city.city = 'York'::text)
ORDER BY city.city_id, address.address_id, customer.customer_id;
`, "London", "York")
err := stmt.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 2)
testutils.AssertJSON(t, dest, `
[
{
"CityID": {
"Int64": 312,
"Valid": true
},
"CityName": "London",
"Customers": [
{
"CustomerID": {
"Int64": 252,
"Valid": true
},
"LastName": "Hoffman",
"Address": {
"AddressID": {
"Int64": 256,
"Valid": true
},
"AddressLine": "1497 Yuzhou Drive"
}
},
{
"CustomerID": {
"Int64": 512,
"Valid": true
},
"LastName": "Vines",
"Address": {
"AddressID": {
"Int64": 517,
"Valid": true
},
"AddressLine": "548 Uruapan Street"
}
}
]
},
{
"CityID": {
"Int64": 589,
"Valid": true
},
"CityName": "York",
"Customers": [
{
"CustomerID": {
"Int64": 497,
"Valid": true
},
"LastName": "Sledge",
"Address": {
"AddressID": {
"Int64": 502,
"Valid": true
},
"AddressLine": "1515 Korla Way"
}
}
]
}
]
`)
}
// Test join with custom primary keys (null.Int)
func TestSelectExecutionCustomPKTypes2(t *testing.T) {
var dest []struct {
CityID null.Int `sql:"primary_key" alias:"city.city_id"`
CityName string `alias:"city.city"`
Customers []struct {
CustomerID null.Int `sql:"primary_key" alias:"customer_id"`
LastName *string `alias:"last_name"`
Address struct {
AddressID null.Int `sql:"primary_key" alias:"AddressId"`
AddressLine string `alias:"address.address"`
} `alias:"address.*"`
} `alias:"customer"`
}
stmt := SELECT(
City.CityID,
City.City,
Customer.CustomerID,
Customer.LastName,
Address.AddressID,
Address.Address,
).FROM(
City.
INNER_JOIN(Address, Address.CityID.EQ(City.CityID)).
INNER_JOIN(Customer, Customer.AddressID.EQ(Address.AddressID)),
).WHERE(
City.City.EQ(String("London")).OR(City.City.EQ(String("York"))),
).ORDER_BY(
City.CityID,
Address.AddressID,
Customer.CustomerID,
)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT city.city_id AS "city.city_id",
city.city AS "city.city",
customer.customer_id AS "customer.customer_id",
customer.last_name AS "customer.last_name",
address.address_id AS "address.address_id",
address.address AS "address.address"
FROM dvds.city
INNER JOIN dvds.address ON (address.city_id = city.city_id)
INNER JOIN dvds.customer ON (customer.address_id = address.address_id)
WHERE (city.city = 'London'::text) OR (city.city = 'York'::text)
ORDER BY city.city_id, address.address_id, customer.customer_id;
`, "London", "York")
err := stmt.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 2)
testutils.AssertJSON(t, dest, `
[
{
"CityID": 312,
"CityName": "London",
"Customers": [
{
"CustomerID": 252,
"LastName": "Hoffman",
"Address": {
"AddressID": 256,
"AddressLine": "1497 Yuzhou Drive"
}
},
{
"CustomerID": 512,
"LastName": "Vines",
"Address": {
"AddressID": 517,
"AddressLine": "548 Uruapan Street"
}
}
]
},
{
"CityID": 589,
"CityName": "York",
"Customers": [
{
"CustomerID": 497,
"LastName": "Sledge",
"Address": {
"AddressID": 502,
"AddressLine": "1515 Korla Way"
}
}
]
}
]
`)
}
func TestSelectJoinQuerySliceWithPtrs(t *testing.T) {
type FilmsPerLanguage struct {
Language model.Language
Film *[]*model.Film
}
query := SELECT(
Language.AllColumns,
Film.AllColumns,
).FROM(
Film.
INNER_JOIN(Language, Film.LanguageID.EQ(Language.LanguageID)),
).LIMIT(
int64(3),
)
var filmsPerLanguageWithPtrs []*FilmsPerLanguage
err := query.Query(db, &filmsPerLanguageWithPtrs)
require.NoError(t, err)
require.Equal(t, len(filmsPerLanguageWithPtrs), 1)
require.Equal(t, len(*filmsPerLanguageWithPtrs[0].Film), 3)
}
func TestSelect_WithoutUniqueColumnSelected(t *testing.T) {
query := Customer.SELECT(Customer.FirstName, Customer.LastName, Customer.Email).ORDER_BY(Customer.Email)
var customers []model.Customer
err := query.Query(db, &customers)
require.NoError(t, err)
require.Equal(t, len(customers), 599)
}
func TestSelectOrderByAscDesc(t *testing.T) {
var customersAsc []model.Customer
err := SELECT(Customer.CustomerID, Customer.FirstName, Customer.LastName).
FROM(Customer).
ORDER_BY(Customer.FirstName.ASC()).
Query(db, &customersAsc)
require.NoError(t, err)
firstCustomerAsc := customersAsc[0]
lastCustomerAsc := customersAsc[len(customersAsc)-1]
var customersDesc []model.Customer
err = Customer.SELECT(Customer.CustomerID, Customer.FirstName, Customer.LastName).
ORDER_BY(Customer.FirstName.DESC()).
Query(db, &customersDesc)
require.NoError(t, err)
firstCustomerDesc := customersDesc[0]
lastCustomerDesc := customersDesc[len(customersAsc)-1]
testutils.AssertDeepEqual(t, firstCustomerAsc, lastCustomerDesc)
testutils.AssertDeepEqual(t, lastCustomerAsc, firstCustomerDesc)
var customersAscDesc []model.Customer
err = Customer.SELECT(Customer.CustomerID, Customer.FirstName, Customer.LastName).
ORDER_BY(Customer.FirstName.ASC(), Customer.LastName.DESC()).
Query(db, &customersAscDesc)
require.NoError(t, err)
customerAscDesc326 := model.Customer{
CustomerID: 67,
FirstName: "Kelly",
LastName: "Torres",
}
customerAscDesc327 := model.Customer{
CustomerID: 546,
FirstName: "Kelly",
LastName: "Knott",
}
testutils.AssertDeepEqual(t, customerAscDesc326, customersAscDesc[326])
testutils.AssertDeepEqual(t, customerAscDesc327, customersAscDesc[327])
}
func TestSelectOrderBy(t *testing.T) {
var destRentals []model.Rental
t.Run("default", func(t *testing.T) {
stmt := SELECT(
Rental.AllColumns,
).FROM(
Rental,
).ORDER_BY(
Rental.ReturnDate,
).LIMIT(200)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT rental.rental_id AS "rental.rental_id",
rental.rental_date AS "rental.rental_date",
rental.inventory_id AS "rental.inventory_id",
rental.customer_id AS "rental.customer_id",
rental.return_date AS "rental.return_date",
rental.staff_id AS "rental.staff_id",
rental.last_update AS "rental.last_update"
FROM dvds.rental
ORDER BY rental.return_date
LIMIT 200;
`)
require.NoError(t, stmt.Query(db, &destRentals))
})
t.Run("NULLS FIRST", func(t *testing.T) {
stmt := SELECT(
Rental.AllColumns,
).FROM(
Rental,
).ORDER_BY(
Rental.ReturnDate.NULLS_FIRST(),
).LIMIT(200)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT rental.rental_id AS "rental.rental_id",
rental.rental_date AS "rental.rental_date",
rental.inventory_id AS "rental.inventory_id",
rental.customer_id AS "rental.customer_id",
rental.return_date AS "rental.return_date",
rental.staff_id AS "rental.staff_id",
rental.last_update AS "rental.last_update"
FROM dvds.rental
ORDER BY rental.return_date NULLS FIRST
LIMIT 200;
`)
require.NoError(t, stmt.Query(db, &destRentals))
})
t.Run("NULLS LAST", func(t *testing.T) {
stmt := SELECT(
Rental.AllColumns,
).FROM(
Rental,
).ORDER_BY(
Rental.ReturnDate.NULLS_LAST(),
).LIMIT(200)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT rental.rental_id AS "rental.rental_id",
rental.rental_date AS "rental.rental_date",
rental.inventory_id AS "rental.inventory_id",
rental.customer_id AS "rental.customer_id",
rental.return_date AS "rental.return_date",
rental.staff_id AS "rental.staff_id",
rental.last_update AS "rental.last_update"
FROM dvds.rental
ORDER BY rental.return_date NULLS LAST
LIMIT 200;
`)
require.NoError(t, stmt.Query(db, &destRentals))
})
t.Run("ASC", func(t *testing.T) {
stmt := SELECT(
Rental.AllColumns,
).FROM(
Rental,
).ORDER_BY(
Rental.ReturnDate.ASC(),
).LIMIT(200)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT rental.rental_id AS "rental.rental_id",
rental.rental_date AS "rental.rental_date",
rental.inventory_id AS "rental.inventory_id",
rental.customer_id AS "rental.customer_id",
rental.return_date AS "rental.return_date",
rental.staff_id AS "rental.staff_id",
rental.last_update AS "rental.last_update"
FROM dvds.rental
ORDER BY rental.return_date ASC
LIMIT 200;
`)
require.NoError(t, stmt.Query(db, &destRentals))
})
t.Run("ASC NULLS FIRST", func(t *testing.T) {
stmt := SELECT(
Rental.AllColumns,
).FROM(
Rental,
).ORDER_BY(
Rental.ReturnDate.ASC().NULLS_FIRST(),
).LIMIT(200)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT rental.rental_id AS "rental.rental_id",
rental.rental_date AS "rental.rental_date",
rental.inventory_id AS "rental.inventory_id",
rental.customer_id AS "rental.customer_id",
rental.return_date AS "rental.return_date",
rental.staff_id AS "rental.staff_id",
rental.last_update AS "rental.last_update"
FROM dvds.rental
ORDER BY rental.return_date ASC NULLS FIRST
LIMIT 200;
`)
require.NoError(t, stmt.Query(db, &destRentals))
})
t.Run("ASC NULLS LAST", func(t *testing.T) {
stmt := SELECT(
Rental.AllColumns,
).FROM(
Rental,
).ORDER_BY(
Rental.ReturnDate.ASC().NULLS_LAST(),
).LIMIT(200).OFFSET(15800)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT rental.rental_id AS "rental.rental_id",
rental.rental_date AS "rental.rental_date",
rental.inventory_id AS "rental.inventory_id",
rental.customer_id AS "rental.customer_id",
rental.return_date AS "rental.return_date",
rental.staff_id AS "rental.staff_id",
rental.last_update AS "rental.last_update"
FROM dvds.rental
ORDER BY rental.return_date ASC NULLS LAST
LIMIT 200
OFFSET 15800;
`)
require.NoError(t, stmt.Query(db, &destRentals))
})
t.Run("DESC", func(t *testing.T) {
stmt := SELECT(
Rental.AllColumns,
).FROM(
Rental,
).ORDER_BY(
Rental.ReturnDate.DESC(),
).LIMIT(200).OFFSET(15800)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT rental.rental_id AS "rental.rental_id",
rental.rental_date AS "rental.rental_date",
rental.inventory_id AS "rental.inventory_id",
rental.customer_id AS "rental.customer_id",
rental.return_date AS "rental.return_date",
rental.staff_id AS "rental.staff_id",
rental.last_update AS "rental.last_update"
FROM dvds.rental
ORDER BY rental.return_date DESC
LIMIT 200
OFFSET 15800;
`)
require.NoError(t, stmt.Query(db, &destRentals))
})
t.Run("DESC NULLS LAST", func(t *testing.T) {
stmt := SELECT(
Rental.AllColumns,
).FROM(
Rental,
).ORDER_BY(
Rental.ReturnDate.DESC().NULLS_LAST(),
).LIMIT(200).OFFSET(15800)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT rental.rental_id AS "rental.rental_id",
rental.rental_date AS "rental.rental_date",
rental.inventory_id AS "rental.inventory_id",
rental.customer_id AS "rental.customer_id",
rental.return_date AS "rental.return_date",
rental.staff_id AS "rental.staff_id",
rental.last_update AS "rental.last_update"
FROM dvds.rental
ORDER BY rental.return_date DESC NULLS LAST
LIMIT 200
OFFSET 15800;
`)
require.NoError(t, stmt.Query(db, &destRentals))
})
t.Run("DESC NULLS FIRST", func(t *testing.T) {
stmt := SELECT(
Rental.AllColumns,
).FROM(
Rental,
).ORDER_BY(
Rental.ReturnDate.DESC().NULLS_FIRST(),
).LIMIT(200)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT rental.rental_id AS "rental.rental_id",
rental.rental_date AS "rental.rental_date",
rental.inventory_id AS "rental.inventory_id",
rental.customer_id AS "rental.customer_id",
rental.return_date AS "rental.return_date",
rental.staff_id AS "rental.staff_id",
rental.last_update AS "rental.last_update"
FROM dvds.rental
ORDER BY rental.return_date DESC NULLS FIRST
LIMIT 200;
`)
require.NoError(t, stmt.Query(db, &destRentals))
})
}
func TestSelectFullJoin(t *testing.T) {
expectedSQL := `
SELECT customer.customer_id AS "customer.customer_id",
customer.store_id AS "customer.store_id",
customer.first_name AS "customer.first_name",
customer.last_name AS "customer.last_name",
customer.email AS "customer.email",
customer.address_id AS "customer.address_id",
customer.activebool AS "customer.activebool",
customer.create_date AS "customer.create_date",
customer.last_update AS "customer.last_update",
customer.active AS "customer.active",
address.address_id AS "address.address_id",
address.address AS "address.address",
address.address2 AS "address.address2",
address.district AS "address.district",
address.city_id AS "address.city_id",
address.postal_code AS "address.postal_code",
address.phone AS "address.phone",
address.last_update AS "address.last_update"
FROM dvds.customer
FULL JOIN dvds.address ON (customer.address_id = address.address_id)
ORDER BY customer.customer_id ASC;
`
query := Customer.
FULL_JOIN(Address, Customer.AddressID.EQ(Address.AddressID)).
SELECT(Customer.AllColumns, Address.AllColumns).
ORDER_BY(Customer.CustomerID.ASC())
testutils.AssertDebugStatementSql(t, query, expectedSQL)
var allCustomersAndAddress []struct {
Address *model.Address
Customer *model.Customer
}
err := query.Query(db, &allCustomersAndAddress)
require.NoError(t, err)
require.Equal(t, len(allCustomersAndAddress), 603)
if sourceIsCockroachDB() {
nullsFirst := allCustomersAndAddress[0]
require.True(t, nullsFirst.Customer == nil)
require.True(t, nullsFirst.Address != nil)
testutils.AssertDeepEqual(t, allCustomersAndAddress[4].Customer, &customer0)
require.True(t, allCustomersAndAddress[0].Address != nil)
} else { // postgres
testutils.AssertDeepEqual(t, allCustomersAndAddress[0].Customer, &customer0)
require.True(t, allCustomersAndAddress[0].Address != nil)
nullsLast := allCustomersAndAddress[len(allCustomersAndAddress)-1]
require.True(t, nullsLast.Customer == nil)
require.True(t, nullsLast.Address != nil)
}
}
func TestSelectCrossJoin(t *testing.T) {
expectedSQL := `
SELECT customer.customer_id AS "customer.customer_id",
customer.store_id AS "customer.store_id",
customer.first_name AS "customer.first_name",
customer.last_name AS "customer.last_name",
customer.email AS "customer.email",
customer.address_id AS "customer.address_id",
customer.activebool AS "customer.activebool",
customer.create_date AS "customer.create_date",
customer.last_update AS "customer.last_update",
customer.active AS "customer.active",
address.address_id AS "address.address_id",
address.address AS "address.address",
address.address2 AS "address.address2",
address.district AS "address.district",
address.city_id AS "address.city_id",
address.postal_code AS "address.postal_code",
address.phone AS "address.phone",
address.last_update AS "address.last_update"
FROM dvds.customer
CROSS JOIN dvds.address
ORDER BY customer.customer_id ASC
LIMIT 1000;
`
query := Customer.
CROSS_JOIN(Address).
SELECT(Customer.AllColumns, Address.AllColumns).
ORDER_BY(Customer.CustomerID.ASC()).
LIMIT(1000)
testutils.AssertDebugStatementSql(t, query, expectedSQL, int64(1000))
var customerAddersCrossJoined []struct {
model.Customer
model.Address
}
err := query.Query(db, &customerAddersCrossJoined)
require.Equal(t, len(customerAddersCrossJoined), 1000)
require.NoError(t, err)
}
func TestSelectSelfJoin(t *testing.T) {
expectedSQL := `
SELECT f1.film_id AS "f1.film_id",
f1.title AS "f1.title",
f1.description AS "f1.description",
f1.release_year AS "f1.release_year",
f1.language_id AS "f1.language_id",
f1.rental_duration AS "f1.rental_duration",
f1.rental_rate AS "f1.rental_rate",
f1.length AS "f1.length",
f1.replacement_cost AS "f1.replacement_cost",
f1.rating AS "f1.rating",
f1.last_update AS "f1.last_update",
f1.special_features AS "f1.special_features",
f1.fulltext AS "f1.fulltext",
f2.film_id AS "f2.film_id",
f2.title AS "f2.title",
f2.description AS "f2.description",
f2.release_year AS "f2.release_year",
f2.language_id AS "f2.language_id",
f2.rental_duration AS "f2.rental_duration",
f2.rental_rate AS "f2.rental_rate",
f2.length AS "f2.length",
f2.replacement_cost AS "f2.replacement_cost",
f2.rating AS "f2.rating",
f2.last_update AS "f2.last_update",
f2.special_features AS "f2.special_features",
f2.fulltext AS "f2.fulltext"
FROM dvds.film AS f1
INNER JOIN dvds.film AS f2 ON ((f1.film_id < f2.film_id) AND (f1.length = f2.length))
ORDER BY f1.film_id ASC;
`
f1 := Film.AS("f1")
f2 := Film.AS("f2")
query := f1.
INNER_JOIN(f2, f1.FilmID.LT(f2.FilmID).AND(f1.Length.EQ(f2.Length))).
SELECT(f1.AllColumns, f2.AllColumns).
ORDER_BY(f1.FilmID.ASC())
testutils.AssertDebugStatementSql(t, query, expectedSQL)
type F1 model.Film
type F2 model.Film
var theSameLengthFilms []struct {
F1 F1
F2 F2
}
err := query.Query(db, &theSameLengthFilms)
require.NoError(t, err)
//spew.Dump(theSameLengthFilms)
//require.Equal(t, len(theSameLengthFilms), 100)
}
func TestSelectAliasColumn(t *testing.T) {
expectedSQL := `
SELECT f1.title AS "thesame_length_films.title1",
f2.title AS "thesame_length_films.title2",
f1.length AS "thesame_length_films.length"
FROM dvds.film AS f1
INNER JOIN dvds.film AS f2 ON ((f1.film_id != f2.film_id) AND (f1.length = f2.length))
ORDER BY f1.length ASC, f1.title ASC, f2.title ASC
LIMIT 1000;
`
f1 := Film.AS("f1")
f2 := Film.AS("f2")
f1.FilmID.EQ(Int(11))
query := f1.
INNER_JOIN(f2, f1.FilmID.NOT_EQ(f2.FilmID).AND(f1.Length.EQ(f2.Length))).
SELECT(f1.Title.AS("thesame_length_films.title1"),
f2.Title.AS("thesame_length_films.title2"),
f1.Length.AS("thesame_length_films.length")).
ORDER_BY(f1.Length.ASC(), f1.Title.ASC(), f2.Title.ASC()).
LIMIT(1000)
testutils.AssertDebugStatementSql(t, query, expectedSQL, int64(1000))
type thesameLengthFilms struct {
Title1 string
Title2 string
Length int16
}
var films []thesameLengthFilms
err := query.Query(db, &films)
require.NoError(t, err)
require.Equal(t, len(films), 1000)
testutils.AssertDeepEqual(t, films[0], thesameLengthFilms{"Alien Center", "Iron Moon", 46})
}
func TestSelectSubQuery(t *testing.T) {
rRatingFilms :=
SELECT(
Film.FilmID,
Film.Title,
Film.Rating,
).FROM(
Film,
).WHERE(
Film.Rating.EQ(enum.MpaaRating.R),
).AsTable("rFilms")
rFilmID := Film.FilmID.From(rRatingFilms)
stmt :=
SELECT(
rRatingFilms.AllColumns(),
Actor.AllColumns,
).FROM(
rRatingFilms.
INNER_JOIN(FilmActor, FilmActor.FilmID.EQ(rFilmID)).
INNER_JOIN(Actor, FilmActor.ActorID.EQ(Actor.ActorID)),
).WHERE(
rFilmID.LT(Int(50)),
).ORDER_BY(
rFilmID.ASC(),
Actor.ActorID.ASC(),
)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT "rFilms"."film.film_id" AS "film.film_id",
"rFilms"."film.title" AS "film.title",
"rFilms"."film.rating" AS "film.rating",
actor.actor_id AS "actor.actor_id",
actor.first_name AS "actor.first_name",
actor.last_name AS "actor.last_name",
actor.last_update AS "actor.last_update"
FROM (
SELECT film.film_id AS "film.film_id",
film.title AS "film.title",
film.rating AS "film.rating"
FROM dvds.film
WHERE film.rating = 'R'
) AS "rFilms"
INNER JOIN dvds.film_actor ON (film_actor.film_id = "rFilms"."film.film_id")
INNER JOIN dvds.actor ON (film_actor.actor_id = actor.actor_id)
WHERE "rFilms"."film.film_id" < 50
ORDER BY "rFilms"."film.film_id" ASC, actor.actor_id ASC;
`)
var dest []struct {
model.Film
Actors []model.Actor
}
err := stmt.Query(db, &dest)
require.NoError(t, err)
require.Len(t, dest, 10)
testutils.AssertJSON(t, dest[0], `
{
"FilmID": 8,
"Title": "Airport Pollock",
"Description": null,
"ReleaseYear": null,
"LanguageID": 0,
"RentalDuration": 0,
"RentalRate": 0,
"Length": null,
"ReplacementCost": 0,
"Rating": "R",
"LastUpdate": "0001-01-01T00:00:00Z",
"SpecialFeatures": null,
"Fulltext": "",
"Actors": [
{
"ActorID": 55,
"FirstName": "Fay",
"LastName": "Kilmer",
"LastUpdate": "2013-05-26T14:47:57.62Z"
},
{
"ActorID": 96,
"FirstName": "Gene",
"LastName": "Willis",
"LastUpdate": "2013-05-26T14:47:57.62Z"
},
{
"ActorID": 110,
"FirstName": "Susan",
"LastName": "Davis",
"LastUpdate": "2013-05-26T14:47:57.62Z"
},
{
"ActorID": 138,
"FirstName": "Lucille",
"LastName": "Dee",
"LastUpdate": "2013-05-26T14:47:57.62Z"
}
]
}
`)
}
func TestSelectFunctions(t *testing.T) {
expectedQuery := `
SELECT MAX(film.rental_rate) AS "max_film_rate"
FROM dvds.film;
`
query := Film.SELECT(
MAXf(Film.RentalRate).AS("max_film_rate"),
)
testutils.AssertDebugStatementSql(t, query, expectedQuery)
ret := struct {
MaxFilmRate float64
}{}
err := query.Query(db, &ret)
require.NoError(t, err)
require.Equal(t, ret.MaxFilmRate, 4.99)
}
func TestSelectQueryScalar(t *testing.T) {
expectedSQL := `
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"
FROM dvds.film
WHERE film.rental_rate = (
SELECT MAX(film.rental_rate)
FROM dvds.film
)
ORDER BY film.film_id ASC;
`
maxFilmRentalRate := FloatExp(
Film.
SELECT(MAXf(Film.RentalRate)),
)
query := Film.
SELECT(Film.AllColumns).
WHERE(Film.RentalRate.EQ(maxFilmRentalRate)).
ORDER_BY(Film.FilmID.ASC())
testutils.AssertDebugStatementSql(t, query, expectedSQL)
var maxRentalRateFilms []model.Film
err := query.Query(db, &maxRentalRateFilms)
require.NoError(t, err)
require.Equal(t, len(maxRentalRateFilms), 336)
gRating := model.MpaaRating_G
testutils.AssertDeepEqual(t, maxRentalRateFilms[0], model.Film{
FilmID: 2,
Title: "Ace Goldfinger",
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: ptr.Of(int16(48)),
ReplacementCost: 12.99,
Rating: &gRating,
RentalDuration: 3,
LastUpdate: *testutils.TimestampWithoutTimeZone("2013-05-26 14:50:58.951", 3),
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",
})
}
func TestSelectGroupByHaving(t *testing.T) {
expectedSQL := `
SELECT customer.customer_id AS "customer.customer_id",
customer.store_id AS "customer.store_id",
customer.first_name AS "customer.first_name",
customer.last_name AS "customer.last_name",
customer.email AS "customer.email",
customer.address_id AS "customer.address_id",
customer.activebool AS "customer.activebool",
customer.create_date AS "customer.create_date",
customer.last_update AS "customer.last_update",
customer.active AS "customer.active",
SUM(payment.amount) AS "amount.sum",
AVG(payment.amount) AS "amount.avg",
MAX(payment.amount) AS "amount.max",
MIN(payment.amount) AS "amount.min",
COUNT(payment.amount) AS "amount.count"
FROM dvds.payment
INNER JOIN dvds.customer ON (customer.customer_id = payment.customer_id)
GROUP BY customer.customer_id
HAVING SUM(payment.amount) > 125::real
ORDER BY customer.customer_id, SUM(payment.amount) ASC;
`
query := SELECT(
Customer.AllColumns,
SUMf(Payment.Amount).AS("amount.sum"),
AVG(Payment.Amount).AS("amount.avg"),
MAXf(Payment.Amount).AS("amount.max"),
MINf(Payment.Amount).AS("amount.min"),
COUNT(Payment.Amount).AS("amount.count"),
).FROM(
Payment.
INNER_JOIN(Customer, Customer.CustomerID.EQ(Payment.CustomerID)),
).GROUP_BY(
Customer.CustomerID,
).HAVING(
SUMf(Payment.Amount).GT(Real(125)),
).ORDER_BY(
Customer.CustomerID, SUMf(Payment.Amount).ASC(),
)
//fmt.Println(query.DebugSql())
testutils.AssertDebugStatementSql(t, query, expectedSQL, float32(125))
var dest []struct {
model.Customer
Amount struct {
Sum float64
Avg float64
Max float64
Min float64
Count int64
} `alias:"amount"`
}
err := query.Query(db, &dest)
require.NoError(t, err)
//testutils.PrintJson(dest)
require.Equal(t, len(dest), 104)
if sourceIsCockroachDB() {
return // small precision difference in result
}
//testutils.SaveJsonFile(dest, "postgres/testdata/customer_payment_sum.json")
testutils.AssertJSONFile(t, dest, "./testdata/results/postgres/customer_payment_sum.json")
}
func TestSelectGroupByGroupingSets(t *testing.T) {
skipForCockroachDB(t)
stmt := SELECT(
GROUPING(Inventory.FilmID, Inventory.StoreID).AS("grouping_filmId_store_id"),
Inventory.FilmID.AS("film_id"),
Inventory.StoreID.AS("store_id"),
COUNT(Inventory.InventoryID).AS("count"),
).FROM(
Inventory,
).WHERE(
Inventory.FilmID.IN(Int(2), Int(3)),
).GROUP_BY(
GROUPING_SETS(
WRAP(Inventory.FilmID, Inventory.StoreID),
WRAP(Inventory.FilmID),
WRAP(),
),
).ORDER_BY(
Inventory.FilmID,
Inventory.StoreID,
)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT GROUPING(inventory.film_id, inventory.store_id) AS "grouping_filmId_store_id",
inventory.film_id AS "film_id",
inventory.store_id AS "store_id",
COUNT(inventory.inventory_id) AS "count"
FROM dvds.inventory
WHERE inventory.film_id IN (2, 3)
GROUP BY GROUPING SETS((inventory.film_id, inventory.store_id), (inventory.film_id), ())
ORDER BY inventory.film_id, inventory.store_id;
`)
var dest []struct {
GroupingFilmIDStoreID int
FilmID *int
StoreID *int
Count int
}
err := stmt.Query(db, &dest)
require.NoError(t, err)
//testutils.PrintJson(dest)
testutils.AssertJSON(t, dest, `
[
{
"GroupingFilmIDStoreID": 0,
"FilmID": 2,
"StoreID": 2,
"Count": 3
},
{
"GroupingFilmIDStoreID": 1,
"FilmID": 2,
"StoreID": null,
"Count": 3
},
{
"GroupingFilmIDStoreID": 0,
"FilmID": 3,
"StoreID": 2,
"Count": 4
},
{
"GroupingFilmIDStoreID": 1,
"FilmID": 3,
"StoreID": null,
"Count": 4
},
{
"GroupingFilmIDStoreID": 3,
"FilmID": null,
"StoreID": null,
"Count": 7
}
]
`)
}
func TestSelectGroupByCube(t *testing.T) {
skipForCockroachDB(t)
stmt := SELECT(
Country.Country.AS("country"),
City.City.AS("city"),
COUNT(City.CityID).AS("count"),
).FROM(
City.INNER_JOIN(
Country,
Country.CountryID.EQ(City.CountryID),
),
).WHERE(
Country.Country.EQ(String("Belarus")),
).GROUP_BY(
CUBE(Country.Country, City.City),
).ORDER_BY(
Country.Country,
City.City,
)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT country.country AS "country",
city.city AS "city",
COUNT(city.city_id) AS "count"
FROM dvds.city
INNER JOIN dvds.country ON (country.country_id = city.country_id)
WHERE country.country = 'Belarus'::text
GROUP BY CUBE(country.country, city.city)
ORDER BY country.country, city.city;
`)
var dest []struct {
Country string
City string
Count int
}
err := stmt.Query(db, &dest)
require.NoError(t, err)
testutils.AssertJSON(t, dest, `
[
{
"Country": "Belarus",
"City": "Mogiljov",
"Count": 1
},
{
"Country": "",
"City": "Mogiljov",
"Count": 1
},
{
"Country": "Belarus",
"City": "Molodetno",
"Count": 1
},
{
"Country": "",
"City": "Molodetno",
"Count": 1
},
{
"Country": "",
"City": "",
"Count": 2
},
{
"Country": "Belarus",
"City": "",
"Count": 2
}
]
`)
}
func TestSelectGroupByRollup(t *testing.T) {
skipForCockroachDB(t)
stmt := SELECT(
EXTRACT(YEAR, Rental.RentalDate).AS("year"),
EXTRACT(MONTH, Rental.RentalDate).AS("month"),
EXTRACT(DAY, Rental.RentalDate).AS("day"),
COUNT(Rental.RentalID).AS("count"),
).FROM(
Rental,
).WHERE(
Rental.RentalDate.LT(Timestamp(2005, 5, 26, 1, 1, 1)),
).GROUP_BY(
ROLLUP(
EXTRACT(YEAR, Rental.RentalDate),
EXTRACT(MONTH, Rental.RentalDate),
EXTRACT(DAY, Rental.RentalDate),
),
).ORDER_BY(
IntegerColumn("year").ASC(),
EXTRACT(MONTH, Rental.RentalDate).ASC(),
IntegerColumn("day").ASC(),
)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT EXTRACT(YEAR FROM rental.rental_date) AS "year",
EXTRACT(MONTH FROM rental.rental_date) AS "month",
EXTRACT(DAY FROM rental.rental_date) AS "day",
COUNT(rental.rental_id) AS "count"
FROM dvds.rental
WHERE rental.rental_date < '2005-05-26 01:01:01'::timestamp without time zone
GROUP BY ROLLUP(EXTRACT(YEAR FROM rental.rental_date), EXTRACT(MONTH FROM rental.rental_date), EXTRACT(DAY FROM rental.rental_date))
ORDER BY year ASC, EXTRACT(MONTH FROM rental.rental_date) ASC, day ASC;
`)
var dest []struct {
Year *int
Month *int
Day *int
Count int
}
err := stmt.Query(db, &dest)
require.NoError(t, err)
testutils.AssertJSON(t, dest, `
[
{
"Year": 2005,
"Month": 5,
"Day": 24,
"Count": 8
},
{
"Year": 2005,
"Month": 5,
"Day": 25,
"Count": 137
},
{
"Year": 2005,
"Month": 5,
"Day": 26,
"Count": 9
},
{
"Year": 2005,
"Month": 5,
"Day": null,
"Count": 154
},
{
"Year": 2005,
"Month": null,
"Day": null,
"Count": 154
},
{
"Year": null,
"Month": null,
"Day": null,
"Count": 154
}
]
`)
}
func TestSelectAggregateFunctionDistinct(t *testing.T) {
stmt := SELECT(
Payment.CustomerID,
COUNT(DISTINCT(Payment.Amount)).AS("distinct.count"),
SUM(DISTINCT(Payment.Amount)).AS("distinct.sum"),
AVG(DISTINCT(Payment.Amount)).AS("distinct.avg"),
MIN(DISTINCT(Payment.PaymentDate)).AS("distinct.first_payment_date"),
MAX(DISTINCT(Payment.PaymentDate)).AS("distinct.last_payment_date"),
).FROM(
Payment,
).WHERE(
Payment.CustomerID.EQ(Int(1)),
).GROUP_BY(
Payment.CustomerID,
)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT payment.customer_id AS "payment.customer_id",
COUNT(DISTINCT payment.amount) AS "distinct.count",
SUM(DISTINCT payment.amount) AS "distinct.sum",
AVG(DISTINCT payment.amount) AS "distinct.avg",
MIN(DISTINCT payment.payment_date) AS "distinct.first_payment_date",
MAX(DISTINCT payment.payment_date) AS "distinct.last_payment_date"
FROM dvds.payment
WHERE payment.customer_id = 1
GROUP BY payment.customer_id;
`)
type Distinct struct {
model.Payment
Count int64
Sum float64
Avg float64
FirstPaymentDate time.Time
LastPaymentDate time.Time
}
var dest Distinct
err := stmt.Query(db, &dest)
require.NoError(t, err)
testutils.AssertJSON(t, dest, `
{
"PaymentID": 0,
"CustomerID": 1,
"StaffID": 0,
"RentalID": 0,
"Amount": 0,
"PaymentDate": "0001-01-01T00:00:00Z",
"Count": 8,
"Sum": 38.92,
"Avg": 4.865,
"FirstPaymentDate": "2007-02-14T23:22:38.996577Z",
"LastPaymentDate": "2007-04-30T01:10:44.996577Z"
}
`)
}
func TestSelectGroupBy2(t *testing.T) {
expectedSQL := `
SELECT customer.customer_id AS "customer.customer_id",
customer.store_id AS "customer.store_id",
customer.first_name AS "customer.first_name",
customer.last_name AS "customer.last_name",
customer.email AS "customer.email",
customer.address_id AS "customer.address_id",
customer.activebool AS "customer.activebool",
customer.create_date AS "customer.create_date",
customer.last_update AS "customer.last_update",
customer.active AS "customer.active",
customer_payment_sum.amount_sum AS "CustomerWithAmounts.AmountSum"
FROM dvds.customer
INNER JOIN (
SELECT payment.customer_id AS "payment.customer_id",
SUM(payment.amount) AS "amount_sum"
FROM dvds.payment
GROUP BY payment.customer_id
) AS customer_payment_sum ON (customer.customer_id = customer_payment_sum."payment.customer_id")
ORDER BY customer_payment_sum.amount_sum ASC;
`
customersPayments := Payment.
SELECT(
Payment.CustomerID,
SUMf(Payment.Amount).AS("amount_sum"),
).
GROUP_BY(Payment.CustomerID).
AsTable("customer_payment_sum")
customerID := Payment.CustomerID.From(customersPayments)
amountSum := FloatColumn("amount_sum").From(customersPayments)
query := Customer.
INNER_JOIN(customersPayments, Customer.CustomerID.EQ(customerID)).
SELECT(
Customer.AllColumns,
amountSum.AS("CustomerWithAmounts.AmountSum"),
).
ORDER_BY(amountSum.ASC())
testutils.AssertDebugStatementSql(t, query, expectedSQL)
type CustomerWithAmounts struct {
Customer *model.Customer
AmountSum float64
}
customersWithAmounts := []CustomerWithAmounts{}
err := query.Query(db, &customersWithAmounts)
require.NoError(t, err)
require.Equal(t, len(customersWithAmounts), 599)
testutils.AssertDeepEqual(t, customersWithAmounts[0].Customer, &model.Customer{
CustomerID: 318,
StoreID: 1,
FirstName: "Brian",
LastName: "Wyman",
AddressID: 323,
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: ptr.Of(int32(1)),
})
require.Equal(t, customersWithAmounts[0].AmountSum, 27.93)
}
func TestSelectStaff(t *testing.T) {
var staffs []model.Staff
err := Staff.SELECT(Staff.AllColumns).Query(db, &staffs)
require.NoError(t, err)
testutils.AssertJSON(t, staffs, `
[
{
"StaffID": 1,
"FirstName": "Mike",
"LastName": "Hillyer",
"AddressID": 3,
"Email": "Mike.Hillyer@sakilastaff.com",
"StoreID": 1,
"Active": true,
"Username": "Mike",
"Password": "8cb2237d0679ca88db6464eac60da96345513964",
"LastUpdate": "2006-05-16T16:13:11.79328Z",
"Picture": "iVBORw0KWgo="
},
{
"StaffID": 2,
"FirstName": "Jon",
"LastName": "Stephens",
"AddressID": 4,
"Email": "Jon.Stephens@sakilastaff.com",
"StoreID": 2,
"Active": true,
"Username": "Jon",
"Password": "8cb2237d0679ca88db6464eac60da96345513964",
"LastUpdate": "2006-05-16T16:13:11.79328Z",
"Picture": null
}
]
`)
}
func TestSelectTimeColumns(t *testing.T) {
expectedSQL := `
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"
FROM dvds.payment
WHERE payment.payment_date < '2007-02-14 22:16:01'::timestamp without time zone
ORDER BY payment.payment_date ASC;
`
query := Payment.SELECT(Payment.AllColumns).
WHERE(Payment.PaymentDate.LT(Timestamp(2007, time.February, 14, 22, 16, 01, 0))).
ORDER_BY(Payment.PaymentDate.ASC())
testutils.AssertDebugStatementSql(t, query, expectedSQL, "2007-02-14 22:16:01")
payments := []model.Payment{}
err := query.Query(db, &payments)
require.NoError(t, err)
require.Equal(t, len(payments), 9)
testutils.AssertDeepEqual(t, payments[0], model.Payment{
PaymentID: 17793,
CustomerID: 416,
StaffID: 2,
RentalID: 1158,
Amount: 2.99,
PaymentDate: *testutils.TimestampWithoutTimeZone("2007-02-14 21:21:59.996577", 6),
})
}
func TestSelectUnion(t *testing.T) {
expectedQuery := `
(
SELECT payment.payment_id AS "payment.payment_id",
payment.amount AS "payment.amount"
FROM dvds.payment
WHERE payment.amount <= 100::double precision
)
UNION ALL
(
SELECT payment.payment_id AS "payment.payment_id",
payment.amount AS "payment.amount"
FROM dvds.payment
WHERE payment.amount >= 200::double precision
)
ORDER BY "payment.payment_id" ASC, "payment.amount" DESC
LIMIT 10
OFFSET 20;
`
query := UNION_ALL(
Payment.
SELECT(Payment.PaymentID.AS("payment.payment_id"), Payment.Amount).
WHERE(Payment.Amount.LT_EQ(Double(100))),
Payment.
SELECT(Payment.PaymentID, Payment.Amount).
WHERE(Payment.Amount.GT_EQ(Double(200))),
).ORDER_BY(
IntegerColumn("payment.payment_id").ASC(),
Payment.Amount.DESC(),
).LIMIT(10).OFFSET(20)
testutils.AssertDebugStatementSql(t, query, expectedQuery, float64(100), float64(200), int64(10), int64(20))
var dest []model.Payment
err := query.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 10)
testutils.AssertDeepEqual(t, dest[0], model.Payment{
PaymentID: 17523,
Amount: 4.99,
})
testutils.AssertDeepEqual(t, dest[1], model.Payment{
PaymentID: 17524,
Amount: 0.99,
})
testutils.AssertDeepEqual(t, dest[9], model.Payment{
PaymentID: 17532,
Amount: 8.99,
})
}
func TestSelectUnionOffsetWithExpression(t *testing.T) {
stmt := UNION(
SELECT(Rental.AllColumns).
FROM(Rental).
WHERE(Rental.ReturnDate.IS_NULL()),
SELECT(Rental.AllColumns).
FROM(Rental).
WHERE(Rental.LastUpdate.GT(LOCALTIMESTAMP())),
).OFFSET_e(IntExp(
SELECT(Int32(3)),
)).LIMIT(10)
testutils.AssertStatementSql(t, stmt, `
(
SELECT rental.rental_id AS "rental.rental_id",
rental.rental_date AS "rental.rental_date",
rental.inventory_id AS "rental.inventory_id",
rental.customer_id AS "rental.customer_id",
rental.return_date AS "rental.return_date",
rental.staff_id AS "rental.staff_id",
rental.last_update AS "rental.last_update"
FROM dvds.rental
WHERE rental.return_date IS NULL
)
UNION
(
SELECT rental.rental_id AS "rental.rental_id",
rental.rental_date AS "rental.rental_date",
rental.inventory_id AS "rental.inventory_id",
rental.customer_id AS "rental.customer_id",
rental.return_date AS "rental.return_date",
rental.staff_id AS "rental.staff_id",
rental.last_update AS "rental.last_update"
FROM dvds.rental
WHERE rental.last_update > LOCALTIMESTAMP
)
LIMIT $1
OFFSET (
SELECT $2::integer
);
`)
var dest []model.Rental
err := stmt.Query(db, &dest)
require.NoError(t, err)
require.Len(t, dest, 10)
}
func TestSelectAllSetOperators(t *testing.T) {
var select1 = Payment.SELECT(Payment.AllColumns).WHERE(Payment.PaymentID.GT_EQ(Int(17600)).AND(Payment.PaymentID.LT(Int(17610))))
var select2 = Payment.SELECT(Payment.AllColumns).WHERE(Payment.PaymentID.GT_EQ(Int(17620)).AND(Payment.PaymentID.LT(Int(17630))))
t.Run("UNION", func(t *testing.T) {
query := select1.UNION(select2)
dest := []model.Payment{}
err := query.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 20)
})
t.Run("UNION_ALL", func(t *testing.T) {
query := select1.UNION_ALL(select2)
dest := []model.Payment{}
err := query.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 20)
})
t.Run("INTERSECT", func(t *testing.T) {
query := select1.INTERSECT(select2)
dest := []model.Payment{}
err := query.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 0)
})
t.Run("INTERSECT_ALL", func(t *testing.T) {
query := select1.INTERSECT_ALL(select2)
dest := []model.Payment{}
err := query.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 0)
})
t.Run("EXCEPT", func(t *testing.T) {
query := select1.EXCEPT(select2)
dest := []model.Payment{}
err := query.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 10)
})
t.Run("EXCEPT_ALL", func(t *testing.T) {
query := select1.EXCEPT_ALL(select2)
dest := []model.Payment{}
err := query.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 10)
})
}
func TestSelectWithCase(t *testing.T) {
expectedQuery := `
SELECT (CASE payment.staff_id WHEN 1 THEN 'ONE'::text WHEN 2 THEN 'TWO'::text WHEN 3 THEN 'THREE'::text ELSE 'OTHER'::text END) AS "staff_id_num"
FROM dvds.payment
ORDER BY payment.payment_id ASC
LIMIT 20;
`
query := Payment.SELECT(
CASE(Payment.StaffID).
WHEN(Int(1)).THEN(String("ONE")).
WHEN(Int(2)).THEN(String("TWO")).
WHEN(Int(3)).THEN(String("THREE")).
ELSE(String("OTHER")).AS("staff_id_num"),
).
ORDER_BY(Payment.PaymentID.ASC()).
LIMIT(20)
testutils.AssertDebugStatementSql(t, query, expectedQuery, int64(1), "ONE", int64(2), "TWO", int64(3), "THREE", "OTHER", int64(20))
dest := []struct {
StaffIDNum string
}{}
err := query.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 20)
require.Equal(t, dest[0].StaffIDNum, "TWO")
require.Equal(t, dest[1].StaffIDNum, "ONE")
}
func getRowLockTestData() map[RowLock]string {
return map[RowLock]string{
UPDATE(): "UPDATE",
NO_KEY_UPDATE(): "NO KEY UPDATE",
SHARE(): "SHARE",
KEY_SHARE(): "KEY SHARE",
}
}
func TestSelectRowLock(t *testing.T) {
query := SELECT(STAR).
FROM(Address).
WHERE(Address.AddressID.LT(Int(10)))
expectedSQL := `
SELECT *
FROM dvds.address
WHERE address.address_id < 10
FOR`
for lockType, lockTypeStr := range getRowLockTestData() {
query.FOR(lockType)
testutils.AssertDebugStatementSql(t, query, expectedSQL+" "+lockTypeStr+";\n", int64(10))
testutils.AssertExecAndRollback(t, query, db, 9)
}
for lockType, lockTypeStr := range getRowLockTestData() {
query.FOR(lockType.NOWAIT())
testutils.AssertDebugStatementSql(t, query, expectedSQL+" "+lockTypeStr+" NOWAIT;\n", int64(10))
testutils.AssertExecAndRollback(t, query, db, 9)
}
if sourceIsCockroachDB() {
return // SKIP LOCKED lock wait policy is not supported
}
for lockType, lockTypeStr := range getRowLockTestData() {
query.FOR(lockType.SKIP_LOCKED())
testutils.AssertDebugStatementSql(t, query, expectedSQL+" "+lockTypeStr+" SKIP LOCKED;\n", int64(10))
testutils.AssertExecAndRollback(t, query, db, 9)
}
}
func TestSelectRowLockWithUpdateOf(t *testing.T) {
stmt := SELECT(
Film.FilmID,
Film.Title,
Actor.ActorID,
Actor.FirstName,
).FROM(
Film.
INNER_JOIN(FilmCategory, FilmCategory.FilmID.EQ(Film.FilmID)).
INNER_JOIN(FilmActor, FilmActor.FilmID.EQ(Film.FilmID)).
INNER_JOIN(Actor, Actor.ActorID.EQ(FilmActor.ActorID)),
).LIMIT(
1,
).FOR(
UPDATE().OF(Film, Actor).NOWAIT(),
)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT film.film_id AS "film.film_id",
film.title AS "film.title",
actor.actor_id AS "actor.actor_id",
actor.first_name AS "actor.first_name"
FROM dvds.film
INNER JOIN dvds.film_category ON (film_category.film_id = film.film_id)
INNER JOIN dvds.film_actor ON (film_actor.film_id = film.film_id)
INNER JOIN dvds.actor ON (actor.actor_id = film_actor.actor_id)
LIMIT 1
FOR UPDATE OF film, actor NOWAIT;
`)
testutils.ExecuteInTxAndRollback(t, db, func(tx qrm.DB) {
var dest []struct {
model.Film
CategoryID int
Actor []model.Actor
}
err := stmt.Query(tx, &dest)
require.NoError(t, err)
require.Len(t, dest, 1)
})
}
func TestSelectRowLockWithUpdateOfAliasedTable(t *testing.T) {
myFilm := Film.AS("myFilm")
stmt := SELECT(
myFilm.FilmID,
myFilm.Title,
).FROM(
myFilm,
).LIMIT(
1,
).FOR(
UPDATE().OF(myFilm),
)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT "myFilm".film_id AS "myFilm.film_id",
"myFilm".title AS "myFilm.title"
FROM dvds.film AS "myFilm"
LIMIT 1
FOR UPDATE OF "myFilm";
`)
testutils.ExecuteInTxAndRollback(t, db, func(tx qrm.DB) {
var dest []struct {
model.Film `alias:"myFilm.*"`
}
err := stmt.Query(tx, &dest)
require.NoError(t, err)
require.Len(t, dest, 1)
})
}
func TestSelectQuickStart(t *testing.T) {
var expectedSQL = `
SELECT actor.actor_id AS "actor.actor_id",
actor.first_name AS "actor.first_name",
actor.last_name AS "actor.last_name",
actor.last_update AS "actor.last_update",
film.film_id AS "film.film_id",
film.title AS "film.title",
film.description AS "film.description",
film.release_year AS "film.release_year",
film.language_id AS "film.language_id",
film.rental_duration AS "film.rental_duration",
film.rental_rate AS "film.rental_rate",
film.length AS "film.length",
film.replacement_cost AS "film.replacement_cost",
film.rating AS "film.rating",
film.last_update AS "film.last_update",
film.special_features AS "film.special_features",
film.fulltext AS "film.fulltext",
language.language_id AS "language.language_id",
language.name AS "language.name",
language.last_update AS "language.last_update",
category.category_id AS "category.category_id",
category.name AS "category.name",
category.last_update AS "category.last_update"
FROM dvds.actor
INNER JOIN dvds.film_actor ON (actor.actor_id = film_actor.actor_id)
INNER JOIN dvds.film ON (film.film_id = film_actor.film_id)
INNER JOIN dvds.language ON (language.language_id = film.language_id)
INNER JOIN dvds.film_category ON (film_category.film_id = film.film_id)
INNER JOIN dvds.category ON (category.category_id = film_category.category_id)
WHERE (((language.name = 'English'::char(20)) AND (category.name != 'Action'::text)) AND (film.length > 180::integer)) AND (film.rating != 'R')
ORDER BY actor.actor_id ASC, film.film_id ASC;
`
stmt := SELECT(
Actor.ActorID, Actor.FirstName, Actor.LastName, Actor.LastUpdate, // list of all actor columns (equivalent to Actor.AllColumns)
Film.AllColumns, // list of all film columns (equivalent to Film.FilmID, Film.Title, ...)
Language.AllColumns,
Category.AllColumns,
).FROM(
Actor.
INNER_JOIN(FilmActor, Actor.ActorID.EQ(FilmActor.ActorID)). // INNER JOIN Actor with FilmActor on condition Actor.ActorID = FilmActor.ActorID
INNER_JOIN(Film, Film.FilmID.EQ(FilmActor.FilmID)). // then with Film, Language, FilmCategory and Category.
INNER_JOIN(Language, Language.LanguageID.EQ(Film.LanguageID)).
INNER_JOIN(FilmCategory, FilmCategory.FilmID.EQ(Film.FilmID)).
INNER_JOIN(Category, Category.CategoryID.EQ(FilmCategory.CategoryID)),
).WHERE(
Language.Name.EQ(Char(20)("English")). // note that every column has type.
AND(Category.Name.NOT_EQ(Text("Action"))). // String column Language.Name and Category.Name can be compared only with string expression
AND(Film.Length.GT(Int32(180))). // Film.Length is integer column and can be compared only with integer expression
AND(Film.Rating.NOT_EQ(enum.MpaaRating.R)),
).ORDER_BY(
Actor.ActorID.ASC(),
Film.FilmID.ASC(),
)
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, "English", "Action", int32(180))
var dest []struct {
model.Actor
Films []struct {
model.Film
Language model.Language
Categories []model.Category
}
}
err := stmt.Query(db, &dest)
require.NoError(t, err)
//testutils.SaveJSONFile(dest, "./testdata/results/postgres/quick-start-dest.json")
testutils.AssertJSONFile(t, dest, "./testdata/results/postgres/quick-start-dest.json")
var dest2 []struct {
model.Category
Films []model.Film
Actors []model.Actor
}
allowUnusedColumns(func() {
err = stmt.Query(db, &dest2)
require.NoError(t, err)
})
//testutils.SaveJSONFile(dest2, "./testdata/results/postgres/quick-start-dest2.json")
testutils.AssertJSONFile(t, dest2, "./testdata/results/postgres/quick-start-dest2.json")
}
func TestSelectQuickStartWithSubQueries(t *testing.T) {
filmLogerThan180 := Film.
SELECT(Film.AllColumns).
WHERE(Film.Length.GT(Int(180)).AND(Film.Rating.NOT_EQ(enum.MpaaRating.R))).
AsTable("films")
filmID := Film.FilmID.From(filmLogerThan180)
filmLanguageID := Film.LanguageID.From(filmLogerThan180)
categoriesNotAction := Category.
SELECT(Category.AllColumns).
WHERE(Category.Name.NOT_EQ(String("Action"))).
AsTable("categories")
categoryID := Category.CategoryID.From(categoriesNotAction)
stmt := SELECT(
Actor.AllColumns,
filmLogerThan180.AllColumns(),
Language.AllColumns,
categoriesNotAction.AllColumns(),
).FROM(
Actor.
INNER_JOIN(FilmActor, Actor.ActorID.EQ(FilmActor.ActorID)).
INNER_JOIN(filmLogerThan180, filmID.EQ(FilmActor.FilmID)).
INNER_JOIN(Language, Language.LanguageID.EQ(filmLanguageID)).
INNER_JOIN(FilmCategory, FilmCategory.FilmID.EQ(filmID)).
INNER_JOIN(categoriesNotAction, categoryID.EQ(FilmCategory.CategoryID)),
).ORDER_BY(
Actor.ActorID.ASC(),
filmID.ASC(),
)
var dest []struct {
model.Actor
Films []struct {
model.Film
Language model.Language
Categories []model.Category
}
}
err := stmt.Query(db, &dest)
require.NoError(t, err)
//jsonSave("./testdata/quick-start-dest.json", dest)
testutils.AssertJSONFile(t, dest, "./testdata/results/postgres/quick-start-dest.json")
var dest2 []struct {
model.Category
Films []model.Film
Actors []model.Actor
}
allowUnusedColumns(func() {
err = stmt.Query(db, &dest2)
require.NoError(t, err)
})
//jsonSave("./testdata/quick-start-dest2.json", dest2)
testutils.AssertJSONFile(t, dest2, "./testdata/results/postgres/quick-start-dest2.json")
}
func TestSelectExpressionWrappers(t *testing.T) {
query := SELECT(
BoolExp(Raw("true")),
IntExp(Raw("11")),
FloatExp(Raw("11.22")),
StringExp(Raw("'stringer'")),
TimeExp(Raw("'raw'")),
TimezExp(Raw("'raw'")),
TimestampExp(Raw("'raw'")),
TimestampzExp(Raw("'raw'")),
DateExp(Raw("'date'")),
)
testutils.AssertStatementSql(t, query, `
SELECT true,
11,
11.22,
'stringer',
'raw',
'raw',
'raw',
'raw',
'date';
`)
allowUnusedColumns(func() {
err := query.Query(db, &[]struct{}{})
require.NoError(t, err)
})
}
func TestSelectWindowFunction(t *testing.T) {
var expectedSQL = `
SELECT AVG(payment.amount) OVER (),
AVG(payment.amount) OVER (PARTITION BY payment.customer_id),
MAX(payment.amount) OVER (ORDER BY payment.payment_date DESC),
MIN(payment.amount) OVER (PARTITION BY payment.customer_id ORDER BY payment.payment_date DESC),
SUM(payment.amount) OVER (PARTITION BY payment.customer_id ORDER BY payment.payment_date DESC ROWS BETWEEN 1 PRECEDING AND 6 FOLLOWING),
SUM(payment.amount) OVER (PARTITION BY payment.customer_id ORDER BY payment.payment_date DESC RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING),
MAX(payment.customer_id) OVER (ORDER BY payment.payment_date DESC ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING),
MIN(payment.customer_id) OVER (PARTITION BY payment.customer_id ORDER BY payment.payment_date DESC),
SUM(payment.customer_id) OVER (PARTITION BY payment.customer_id ORDER BY payment.payment_date DESC),
ROW_NUMBER() OVER (ORDER BY payment.payment_date),
RANK() OVER (ORDER BY payment.payment_date),
DENSE_RANK() OVER (ORDER BY payment.payment_date),
CUME_DIST() OVER (ORDER BY payment.payment_date),
NTILE(11) OVER (ORDER BY payment.payment_date),
LAG(payment.amount) OVER (ORDER BY payment.payment_date),
LAG(payment.amount) OVER (ORDER BY payment.payment_date),
LAG(payment.amount, 2, payment.amount) OVER (ORDER BY payment.payment_date),
LAG(payment.amount, 2, $1) OVER (ORDER BY payment.payment_date),
LEAD(payment.amount) OVER (ORDER BY payment.payment_date),
LEAD(payment.amount) OVER (ORDER BY payment.payment_date),
LEAD(payment.amount, 2, payment.amount) OVER (ORDER BY payment.payment_date),
LEAD(payment.amount, 2, $2) OVER (ORDER BY payment.payment_date),
FIRST_VALUE(payment.amount) OVER (ORDER BY payment.payment_date),
LAST_VALUE(payment.amount) OVER (ORDER BY payment.payment_date),
NTH_VALUE(payment.amount, 3) OVER (ORDER BY payment.payment_date)
FROM dvds.payment
WHERE payment.payment_id < $3
GROUP BY payment.amount, payment.customer_id, payment.payment_date;
`
query := SELECT(
AVG(Payment.Amount).OVER(),
AVG(Payment.Amount).OVER(PARTITION_BY(Payment.CustomerID)),
MAXf(Payment.Amount).OVER(ORDER_BY(Payment.PaymentDate.DESC())),
MINf(Payment.Amount).OVER(PARTITION_BY(Payment.CustomerID).ORDER_BY(Payment.PaymentDate.DESC())),
SUMf(Payment.Amount).OVER(PARTITION_BY(Payment.CustomerID).
ORDER_BY(Payment.PaymentDate.DESC()).ROWS(PRECEDING(1), FOLLOWING(6))),
SUMf(Payment.Amount).OVER(PARTITION_BY(Payment.CustomerID).
ORDER_BY(Payment.PaymentDate.DESC()).RANGE(PRECEDING(UNBOUNDED), FOLLOWING(UNBOUNDED))),
MAXi(Payment.CustomerID).OVER(ORDER_BY(Payment.PaymentDate.DESC()).ROWS(CURRENT_ROW, FOLLOWING(UNBOUNDED))),
MINi(Payment.CustomerID).OVER(PARTITION_BY(Payment.CustomerID).ORDER_BY(Payment.PaymentDate.DESC())),
SUMi(Payment.CustomerID).OVER(PARTITION_BY(Payment.CustomerID).ORDER_BY(Payment.PaymentDate.DESC())),
ROW_NUMBER().OVER(ORDER_BY(Payment.PaymentDate)),
RANK().OVER(ORDER_BY(Payment.PaymentDate)),
DENSE_RANK().OVER(ORDER_BY(Payment.PaymentDate)),
CUME_DIST().OVER(ORDER_BY(Payment.PaymentDate)),
NTILE(11).OVER(ORDER_BY(Payment.PaymentDate)),
LAG(Payment.Amount).OVER(ORDER_BY(Payment.PaymentDate)),
LAG(Payment.Amount, 2).OVER(ORDER_BY(Payment.PaymentDate)),
LAG(Payment.Amount, 2, Payment.Amount).OVER(ORDER_BY(Payment.PaymentDate)),
LAG(Payment.Amount, 2, 100).OVER(ORDER_BY(Payment.PaymentDate)),
LEAD(Payment.Amount).OVER(ORDER_BY(Payment.PaymentDate)),
LEAD(Payment.Amount, 2).OVER(ORDER_BY(Payment.PaymentDate)),
LEAD(Payment.Amount, 2, Payment.Amount).OVER(ORDER_BY(Payment.PaymentDate)),
LEAD(Payment.Amount, 2, 100).OVER(ORDER_BY(Payment.PaymentDate)),
FIRST_VALUE(Payment.Amount).OVER(ORDER_BY(Payment.PaymentDate)),
LAST_VALUE(Payment.Amount).OVER(ORDER_BY(Payment.PaymentDate)),
NTH_VALUE(Payment.Amount, 3).OVER(ORDER_BY(Payment.PaymentDate)),
).FROM(
Payment,
).WHERE(
Payment.PaymentID.LT(Int(10)),
).GROUP_BY(
Payment.Amount,
Payment.CustomerID,
Payment.PaymentDate,
)
//fmt.Println(query.Sql())
testutils.AssertStatementSql(t, query, expectedSQL, 100, 100, int64(10))
allowUnusedColumns(func() {
err := query.Query(db, &[]struct{}{})
require.NoError(t, err)
})
}
func TestSelectWindowClause(t *testing.T) {
var expectedSQL = `
SELECT AVG(payment.amount) OVER (),
AVG(payment.amount) OVER (w1),
AVG(payment.amount) OVER (w2 ORDER BY payment.customer_id RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING),
AVG(payment.amount) OVER (w3 RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
FROM dvds.payment
WHERE payment.payment_id < $1
WINDOW w1 AS (PARTITION BY payment.payment_date), w2 AS (w1), w3 AS (w2 ORDER BY payment.customer_id)
ORDER BY payment.customer_id;
`
query := SELECT(
AVG(Payment.Amount).OVER(),
AVG(Payment.Amount).OVER(Window("w1")),
AVG(Payment.Amount).OVER(
Window("w2").
ORDER_BY(Payment.CustomerID).
RANGE(PRECEDING(UNBOUNDED), FOLLOWING(UNBOUNDED)),
),
AVG(Payment.Amount).OVER(Window("w3").RANGE(PRECEDING(UNBOUNDED), FOLLOWING(UNBOUNDED))),
).
FROM(Payment).
WHERE(Payment.PaymentID.LT(Int(10))).
WINDOW("w1").AS(PARTITION_BY(Payment.PaymentDate)).
WINDOW("w2").AS(Window("w1")).
WINDOW("w3").AS(Window("w2").ORDER_BY(Payment.CustomerID)).
ORDER_BY(Payment.CustomerID)
//fmt.Println(query.Sql())
testutils.AssertStatementSql(t, query, expectedSQL, int64(10))
allowUnusedColumns(func() {
err := query.Query(db, &[]struct{}{})
require.NoError(t, err)
})
}
func TestSelectSimpleView(t *testing.T) {
query := SELECT(
view.ActorInfo.AllColumns,
).FROM(
view.ActorInfo,
).ORDER_BY(
view.ActorInfo.ActorID,
).LIMIT(10)
type ActorInfo struct {
ActorID int
FirstName string
LastName string
FilmInfo string
}
var dest []ActorInfo
err := query.Query(db, &dest)
require.NoError(t, err)
if sourceIsCockroachDB() {
return // skip for cockroach db, FilmInfo is set to '' in ddl
}
testutils.AssertJSON(t, dest[1:2], `
[
{
"ActorID": 2,
"FirstName": "Nick",
"LastName": "Wahlberg",
"FilmInfo": "Action: Bull Shawshank, Animation: Fight Jawbreaker, Children: Jersey Sassy, Classics: Dracula Crystal, Gilbert Pelican, Comedy: Mallrats United, Rushmore Mermaid, Documentary: Adaptation Holes, Drama: Wardrobe Phantom, Family: Apache Divine, Chisum Behavior, Indian Love, Maguire Apache, Foreign: Baby Hall, Happiness United, Games: Roof Champion, Music: Lucky Flying, New: Destiny Saturday, Flash Wars, Jekyll Frogmen, Mask Peach, Sci-Fi: Chainsaw Uptown, Goodfellas Salute, Travel: Liaisons Sweet, Smile Earring"
}
]
`)
}
func TestSelectJoinViewWithTable(t *testing.T) {
query := SELECT(
view.CustomerList.AllColumns,
Rental.AllColumns,
).FROM(
view.CustomerList.
INNER_JOIN(Rental, view.CustomerList.ID.EQ(Rental.CustomerID)),
).WHERE(
view.CustomerList.ID.LT_EQ(Int(2)),
).ORDER_BY(
view.CustomerList.ID,
)
var dest []struct {
model.CustomerList `sql:"primary_key=ID"`
Rentals []model.Rental
}
//fmt.Println(query.DebugSql())
err := query.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 2)
require.Equal(t, len(dest[0].Rentals), 32)
require.Equal(t, len(dest[1].Rentals), 27)
}
func TestSelectDynamicProjectionList(t *testing.T) {
var request struct {
ColumnsToSelect []string
ShowFullName bool
}
request.ColumnsToSelect = []string{"customer_id", "create_date"}
request.ShowFullName = true
// ...
projectionList := ProjectionList{}
for _, columnName := range request.ColumnsToSelect {
switch columnName {
case Customer.CustomerID.Name():
projectionList = append(projectionList, Customer.CustomerID)
case Customer.Email.Name():
projectionList = append(projectionList, Customer.Email)
case Customer.CreateDate.Name():
projectionList = append(projectionList, Customer.CreateDate)
}
}
var showFullName bool
if showFullName {
projectionList = append(projectionList, Customer.FirstName.CONCAT(Customer.LastName))
}
stmt := SELECT(projectionList).
FROM(Customer).
LIMIT(3)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT customer.customer_id AS "customer.customer_id",
customer.create_date AS "customer.create_date"
FROM dvds.customer
LIMIT 3;
`)
var dest []model.Customer
err := stmt.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 3)
}
func TestSelectDynamicCondition(t *testing.T) {
var request struct {
CustomerID *int64
Email *string
Active *bool
}
request.CustomerID = ptr.Of(int64(1))
request.Active = ptr.Of(true)
// ...
condition := Bool(true)
if request.CustomerID != nil {
condition = condition.AND(Customer.CustomerID.EQ(Int(*request.CustomerID)))
}
if request.Email != nil {
condition = condition.AND(Customer.Email.EQ(String(*request.Email)))
}
if request.Active != nil {
condition = condition.AND(Customer.Activebool.EQ(Bool(*request.Active)))
}
stmt := SELECT(Customer.AllColumns).
FROM(Customer).
WHERE(condition)
testutils.AssertStatementSql(t, stmt, `
SELECT customer.customer_id AS "customer.customer_id",
customer.store_id AS "customer.store_id",
customer.first_name AS "customer.first_name",
customer.last_name AS "customer.last_name",
customer.email AS "customer.email",
customer.address_id AS "customer.address_id",
customer.activebool AS "customer.activebool",
customer.create_date AS "customer.create_date",
customer.last_update AS "customer.last_update",
customer.active AS "customer.active"
FROM dvds.customer
WHERE ($1::boolean AND (customer.customer_id = $2)) AND (customer.activebool = $3::boolean);
`, true, int64(1), true)
var dest []model.Customer
err := stmt.Query(db, &dest)
require.NoError(t, err)
require.Len(t, dest, 1)
testutils.AssertDeepEqual(t, dest[0], customer0)
}
func TestSelectLateral(t *testing.T) {
languages := LATERAL(
SELECT(
Language.AllColumns,
).FROM(
Language,
).WHERE(
Language.Name.NOT_IN(Char(20)("Spanish"), Char(20)("Catalan")).
AND(Film.LanguageID.EQ(Language.LanguageID)),
),
).AS("films")
stmt := SELECT(
Film.FilmID,
Film.Title,
languages.AllColumns(),
).FROM(
Film.CROSS_JOIN(languages),
).WHERE(
Film.FilmID.EQ(Int(1)),
).ORDER_BY(
Film.FilmID,
).LIMIT(1)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT film.film_id AS "film.film_id",
film.title AS "film.title",
films."language.language_id" AS "language.language_id",
films."language.name" AS "language.name",
films."language.last_update" AS "language.last_update"
FROM dvds.film
CROSS JOIN LATERAL (
SELECT language.language_id AS "language.language_id",
language.name AS "language.name",
language.last_update AS "language.last_update"
FROM dvds.language
WHERE (language.name NOT IN ('Spanish'::char(20), 'Catalan'::char(20))) AND (film.language_id = language.language_id)
) AS films
WHERE film.film_id = 1
ORDER BY film.film_id
LIMIT 1;
`)
type FilmLanguage struct {
model.Film
model.Language
}
var dest []FilmLanguage
err := stmt.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, dest[0].Film.Title, "Academy Dinosaur")
require.Equal(t, dest[0].Language.Name, "English ")
t.Run("implicit cross join", func(t *testing.T) {
stmt2 := SELECT(
Film.FilmID,
Film.Title,
languages.AllColumns(),
).FROM(
Film,
languages,
).WHERE(
Film.FilmID.EQ(Int(1)),
).ORDER_BY(
Film.FilmID,
).LIMIT(1)
testutils.AssertDebugStatementSql(t, stmt2, `
SELECT film.film_id AS "film.film_id",
film.title AS "film.title",
films."language.language_id" AS "language.language_id",
films."language.name" AS "language.name",
films."language.last_update" AS "language.last_update"
FROM dvds.film,
LATERAL (
SELECT language.language_id AS "language.language_id",
language.name AS "language.name",
language.last_update AS "language.last_update"
FROM dvds.language
WHERE (language.name NOT IN ('Spanish'::char(20), 'Catalan'::char(20))) AND (film.language_id = language.language_id)
) AS films
WHERE film.film_id = 1
ORDER BY film.film_id
LIMIT 1;
`)
var dest2 []FilmLanguage
err2 := stmt2.Query(db, &dest2)
require.NoError(t, err2)
require.Equal(t, dest, dest2)
})
}
func TestSelectColumnListWithExcludedColumns(t *testing.T) {
t.Run("one column", func(t *testing.T) {
stmt := SELECT(
Address.AllColumns.Except(Address.LastUpdate),
).FROM(
Address,
)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT address.address_id AS "address.address_id",
address.address AS "address.address",
address.address2 AS "address.address2",
address.district AS "address.district",
address.city_id AS "address.city_id",
address.postal_code AS "address.postal_code",
address.phone AS "address.phone"
FROM dvds.address;
`)
var dest []model.Address
require.NoError(t, stmt.Query(db, &dest))
require.Len(t, dest, 603)
})
t.Run("multiple columns", func(t *testing.T) {
expectedSQL := `
SELECT address.address_id AS "address.address_id",
address.address AS "address.address",
address.address2 AS "address.address2",
address.district AS "address.district",
address.city_id AS "address.city_id"
FROM dvds.address;
`
// list of columns
stmt := SELECT(
Address.AllColumns.Except(Address.PostalCode, Address.Phone, Address.LastUpdate),
).FROM(
Address,
)
testutils.AssertDebugStatementSql(t, stmt, expectedSQL)
// column list
excludedColumns := ColumnList{Address.PostalCode, Address.Phone, Address.LastUpdate, Film.Title} // Film.Title is ignored
stmt = SELECT(
Address.AllColumns.Except(excludedColumns),
).FROM(Address)
testutils.AssertDebugStatementSql(t, stmt, expectedSQL)
// column list with just column names
excludedColumns = ColumnList{StringColumn("postal_code"), StringColumn("phone"), TimestampColumn("last_update")}
stmt = SELECT(
Address.AllColumns.Except(excludedColumns),
).FROM(Address)
testutils.AssertDebugStatementSql(t, stmt, expectedSQL)
var dest []model.Address
require.NoError(t, stmt.Query(db, &dest))
require.Len(t, dest, 603)
})
}
type FilmWrap struct {
model.Film
Actors []ActorWrap
}
type ActorWrap struct {
model.Actor
Films []FilmWrap
}
func TestSelectRecursionScanNxM(t *testing.T) {
stmt := SELECT(
Actor.AllColumns,
Film.AllColumns,
).FROM(
Actor.
INNER_JOIN(FilmActor, Actor.ActorID.EQ(FilmActor.ActorID)).
INNER_JOIN(Film, Film.FilmID.EQ(FilmActor.FilmID)),
).ORDER_BY(
Actor.ActorID,
Film.FilmID,
).LIMIT(100)
t.Run("film->actors", func(t *testing.T) {
var films []FilmWrap
err := stmt.Query(db, &films)
require.NoError(t, err)
require.Len(t, films, 95)
testutils.AssertJSON(t, films[:2], `
[
{
"FilmID": 1,
"Title": "Academy Dinosaur",
"Description": "A Epic Drama of a Feminist And a Mad Scientist who must Battle a Teacher in The Canadian Rockies",
"ReleaseYear": 2006,
"LanguageID": 1,
"RentalDuration": 6,
"RentalRate": 0.99,
"Length": 86,
"ReplacementCost": 20.99,
"Rating": "PG",
"LastUpdate": "2013-05-26T14:50:58.951Z",
"SpecialFeatures": "{\"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",
"Actors": [
{
"ActorID": 1,
"FirstName": "Penelope",
"LastName": "Guiness",
"LastUpdate": "2013-05-26T14:47:57.62Z",
"Films": null
}
]
},
{
"FilmID": 23,
"Title": "Anaconda Confessions",
"Description": "A Lacklusture Display of a Dentist And a Dentist who must Fight a Girl in Australia",
"ReleaseYear": 2006,
"LanguageID": 1,
"RentalDuration": 3,
"RentalRate": 0.99,
"Length": 92,
"ReplacementCost": 9.99,
"Rating": "R",
"LastUpdate": "2013-05-26T14:50:58.951Z",
"SpecialFeatures": "{Trailers,\"Deleted Scenes\"}",
"Fulltext": "'anaconda':1 'australia':18 'confess':2 'dentist':8,11 'display':5 'fight':14 'girl':16 'lacklustur':4 'must':13",
"Actors": [
{
"ActorID": 1,
"FirstName": "Penelope",
"LastName": "Guiness",
"LastUpdate": "2013-05-26T14:47:57.62Z",
"Films": null
},
{
"ActorID": 4,
"FirstName": "Jennifer",
"LastName": "Davis",
"LastUpdate": "2013-05-26T14:47:57.62Z",
"Films": null
}
]
}
]
`)
})
t.Run("actors->films", func(t *testing.T) {
var actors []ActorWrap
err := stmt.Query(db, &actors)
require.NoError(t, err)
require.Equal(t, len(actors), 5)
require.Equal(t, actors[0].ActorID, int32(1))
require.Equal(t, actors[0].FirstName, "Penelope")
require.Len(t, actors[0].Films, 19)
testutils.AssertJSON(t, actors[0].Films[:2], `
[
{
"FilmID": 1,
"Title": "Academy Dinosaur",
"Description": "A Epic Drama of a Feminist And a Mad Scientist who must Battle a Teacher in The Canadian Rockies",
"ReleaseYear": 2006,
"LanguageID": 1,
"RentalDuration": 6,
"RentalRate": 0.99,
"Length": 86,
"ReplacementCost": 20.99,
"Rating": "PG",
"LastUpdate": "2013-05-26T14:50:58.951Z",
"SpecialFeatures": "{\"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",
"Actors": null
},
{
"FilmID": 23,
"Title": "Anaconda Confessions",
"Description": "A Lacklusture Display of a Dentist And a Dentist who must Fight a Girl in Australia",
"ReleaseYear": 2006,
"LanguageID": 1,
"RentalDuration": 3,
"RentalRate": 0.99,
"Length": 92,
"ReplacementCost": 9.99,
"Rating": "R",
"LastUpdate": "2013-05-26T14:50:58.951Z",
"SpecialFeatures": "{Trailers,\"Deleted Scenes\"}",
"Fulltext": "'anaconda':1 'australia':18 'confess':2 'dentist':8,11 'display':5 'fight':14 'girl':16 'lacklustur':4 'must':13",
"Actors": null
}
]
`)
})
}
type StoreWrap struct {
model.Store
Staffs []StaffWrap
}
type StaffWrap struct {
model.Staff
Store StoreWrap
}
func TestSelectRecursionScanNx1(t *testing.T) {
stmt := SELECT(
Store.AllColumns,
Staff.AllColumns,
).FROM(
Store.
INNER_JOIN(Staff, Staff.StoreID.EQ(Store.StoreID)),
).ORDER_BY(
Store.StoreID,
Staff.StaffID,
)
t.Run("store->staff", func(t *testing.T) {
var stores []StoreWrap
err := stmt.Query(db, &stores)
require.NoError(t, err)
require.Len(t, stores, 2)
testutils.AssertJSON(t, stores, `
[
{
"StoreID": 1,
"ManagerStaffID": 1,
"AddressID": 1,
"LastUpdate": "2006-02-15T09:57:12Z",
"Staffs": [
{
"StaffID": 1,
"FirstName": "Mike",
"LastName": "Hillyer",
"AddressID": 3,
"Email": "Mike.Hillyer@sakilastaff.com",
"StoreID": 1,
"Active": true,
"Username": "Mike",
"Password": "8cb2237d0679ca88db6464eac60da96345513964",
"LastUpdate": "2006-05-16T16:13:11.79328Z",
"Picture": "iVBORw0KWgo=",
"Store": {
"StoreID": 0,
"ManagerStaffID": 0,
"AddressID": 0,
"LastUpdate": "0001-01-01T00:00:00Z",
"Staffs": null
}
}
]
},
{
"StoreID": 2,
"ManagerStaffID": 2,
"AddressID": 2,
"LastUpdate": "2006-02-15T09:57:12Z",
"Staffs": [
{
"StaffID": 2,
"FirstName": "Jon",
"LastName": "Stephens",
"AddressID": 4,
"Email": "Jon.Stephens@sakilastaff.com",
"StoreID": 2,
"Active": true,
"Username": "Jon",
"Password": "8cb2237d0679ca88db6464eac60da96345513964",
"LastUpdate": "2006-05-16T16:13:11.79328Z",
"Picture": null,
"Store": {
"StoreID": 0,
"ManagerStaffID": 0,
"AddressID": 0,
"LastUpdate": "0001-01-01T00:00:00Z",
"Staffs": null
}
}
]
}
]
`)
})
t.Run("staff->store", func(t *testing.T) {
var staffs []StaffWrap
err := stmt.Query(db, &staffs)
require.NoError(t, err)
testutils.AssertJSON(t, staffs, `
[
{
"StaffID": 1,
"FirstName": "Mike",
"LastName": "Hillyer",
"AddressID": 3,
"Email": "Mike.Hillyer@sakilastaff.com",
"StoreID": 1,
"Active": true,
"Username": "Mike",
"Password": "8cb2237d0679ca88db6464eac60da96345513964",
"LastUpdate": "2006-05-16T16:13:11.79328Z",
"Picture": "iVBORw0KWgo=",
"Store": {
"StoreID": 1,
"ManagerStaffID": 1,
"AddressID": 1,
"LastUpdate": "2006-02-15T09:57:12Z",
"Staffs": null
}
},
{
"StaffID": 2,
"FirstName": "Jon",
"LastName": "Stephens",
"AddressID": 4,
"Email": "Jon.Stephens@sakilastaff.com",
"StoreID": 2,
"Active": true,
"Username": "Jon",
"Password": "8cb2237d0679ca88db6464eac60da96345513964",
"LastUpdate": "2006-05-16T16:13:11.79328Z",
"Picture": null,
"Store": {
"StoreID": 2,
"ManagerStaffID": 2,
"AddressID": 2,
"LastUpdate": "2006-02-15T09:57:12Z",
"Staffs": null
}
}
]
`)
})
}
type StoreInfo struct {
model.Store
Staffs ManagerInfo
}
type ManagerInfo struct {
model.Staff
Store *StoreInfo
}
func TestSelectRecursionScan1x1(t *testing.T) {
stmt := SELECT(
Store.AllColumns,
Staff.AllColumns,
).FROM(
Store.
INNER_JOIN(Staff, Staff.StaffID.EQ(Store.ManagerStaffID)),
).ORDER_BY(
Store.StoreID,
)
var dest []StoreInfo
err := stmt.Query(db, &dest)
require.NoError(t, err)
testutils.AssertJSON(t, dest, `
[
{
"StoreID": 1,
"ManagerStaffID": 1,
"AddressID": 1,
"LastUpdate": "2006-02-15T09:57:12Z",
"Staffs": {
"StaffID": 1,
"FirstName": "Mike",
"LastName": "Hillyer",
"AddressID": 3,
"Email": "Mike.Hillyer@sakilastaff.com",
"StoreID": 1,
"Active": true,
"Username": "Mike",
"Password": "8cb2237d0679ca88db6464eac60da96345513964",
"LastUpdate": "2006-05-16T16:13:11.79328Z",
"Picture": "iVBORw0KWgo=",
"Store": null
}
},
{
"StoreID": 2,
"ManagerStaffID": 2,
"AddressID": 2,
"LastUpdate": "2006-02-15T09:57:12Z",
"Staffs": {
"StaffID": 2,
"FirstName": "Jon",
"LastName": "Stephens",
"AddressID": 4,
"Email": "Jon.Stephens@sakilastaff.com",
"StoreID": 2,
"Active": true,
"Username": "Jon",
"Password": "8cb2237d0679ca88db6464eac60da96345513964",
"LastUpdate": "2006-05-16T16:13:11.79328Z",
"Picture": null,
"Store": null
}
}
]
`)
}
// In parameterized statements integer literals, like Int(num), are replaced with a placeholders. For some expressions,
// postgres interpreter will not have enough information to deduce the type. If this is the case postgres returns an error.
// Int8, Int16, .... functions will add automatic type cast over placeholder, so type deduction is always possible.
func TestSelectLiteralTypeDeduction(t *testing.T) {
stmt := SELECT(
SUM(
CASE().WHEN(Staff.Active.IS_TRUE()).
THEN(Int8(6)). // if Int8 and Int32 are replaced with Int,
ELSE(Int32(-1)), // execution of this statement will return an error
).AS("num_passed"),
).FROM(Staff)
testutils.AssertStatementSql(t, stmt, `
SELECT SUM((CASE WHEN staff.active IS TRUE THEN $1::smallint ELSE $2::integer END)) AS "num_passed"
FROM dvds.staff;
`)
allowUnusedColumns(func() {
err := stmt.Query(db, &struct{}{})
require.NoError(t, err)
})
}
func GET_FILM_COUNT(lenFrom, lenTo IntegerExpression) IntegerExpression {
return IntExp(Func("dvds.get_film_count", lenFrom, lenTo))
}
func TestSelectCustomFunctionCall(t *testing.T) {
skipForCockroachDB(t)
stmt := SELECT(
GET_FILM_COUNT(Int(100), Int(120)).AS("film_count"),
)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT dvds.get_film_count(100, 120) AS "film_count";
`)
var dest struct {
FilmCount int
}
err := stmt.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, dest.FilmCount, 165)
stmt2 := SELECT(
Raw("dvds.get_film_count(#1, #2)", RawArgs{"#1": 100, "#2": 120}).AS("film_count"),
)
err = stmt2.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, dest.FilmCount, 165)
stmt3 := RawStatement(`
SELECT dvds.get_film_count(#1, #2) AS "film_count";`, RawArgs{"#1": 100, "#2": 120},
)
err = stmt3.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, dest.FilmCount, 165)
}
func TestSelectScanUsingConn(t *testing.T) {
conn, err := db.Conn(context.Background())
require.NoError(t, err)
defer conn.Close()
stmt := SELECT(Actor.AllColumns).
FROM(Actor).
DISTINCT().
WHERE(Actor.ActorID.EQ(Int(2)))
var actor model.Actor
err = stmt.Query(conn, &actor)
require.NoError(t, err)
err = stmt.QueryContext(context.Background(), conn, &actor)
require.NoError(t, err)
testutils.AssertDeepEqual(t, actor, model.Actor{
ActorID: 2,
FirstName: "Nick",
LastName: "Wahlberg",
LastUpdate: *testutils.TimestampWithoutTimeZone("2013-05-26 14:47:57.62", 2),
})
_, err = stmt.Exec(conn)
require.NoError(t, err)
_, err = stmt.ExecContext(context.Background(), conn)
require.NoError(t, err)
t.Run("ensure qrm.DB still works", func(t *testing.T) {
var qrmDB qrm.DB = db
err = stmt.Query(qrmDB, &actor)
require.NoError(t, err)
err = stmt.QueryContext(context.Background(), qrmDB, &actor)
require.NoError(t, err)
_, err = stmt.Exec(qrmDB)
require.NoError(t, err)
_, err = stmt.ExecContext(context.Background(), qrmDB)
require.NoError(t, err)
})
}
func TestSelectConditionalFunctions(t *testing.T) {
stmt := SELECT(
EXISTS(
Film.SELECT(Film.FilmID).WHERE(Film.RentalDuration.GT(Int(100))),
).AS("exists"),
CASE(Film.Length.GT(Int(120))).
WHEN(Bool(true)).THEN(Text("long film")).
ELSE(Text("short film")).AS("case"),
COALESCE(Film.Description, Text("none")).AS("coalesce"),
NULLIF(Film.ReleaseYear, Int(200)).AS("null_if"),
GREATEST(Film.RentalDuration, Int(4), Int(5)).AS("greatest"),
LEAST(Film.RentalDuration, Int(7), Int(6)).AS("least"),
).FROM(
Film,
).WHERE(
Film.FilmID.LT(Int(5)),
).ORDER_BY(
Film.FilmID,
)
testutils.AssertDebugStatementSql(t, stmt, `
SELECT (EXISTS (
SELECT film.film_id AS "film.film_id"
FROM dvds.film
WHERE film.rental_duration > 100
)) AS "exists",
(CASE (film.length > 120) WHEN TRUE::boolean THEN 'long film'::text ELSE 'short film'::text END) AS "case",
COALESCE(film.description, 'none'::text) AS "coalesce",
NULLIF(film.release_year, 200) AS "null_if",
GREATEST(film.rental_duration, 4, 5) AS "greatest",
LEAST(film.rental_duration, 7, 6) AS "least"
FROM dvds.film
WHERE film.film_id < 5
ORDER BY film.film_id;
`)
var res []struct {
Exists bool
Case string
Coalesce string
NullIf string
Greatest string
Least string
}
err := stmt.Query(db, &res)
require.NoError(t, err)
testutils.AssertJSON(t, res, `
[
{
"Exists": false,
"Case": "short film",
"Coalesce": "A Epic Drama of a Feminist And a Mad Scientist who must Battle a Teacher in The Canadian Rockies",
"NullIf": "2006",
"Greatest": "6",
"Least": "6"
},
{
"Exists": false,
"Case": "short film",
"Coalesce": "A Astounding Epistle of a Database Administrator And a Explorer who must Find a Car in Ancient China",
"NullIf": "2006",
"Greatest": "5",
"Least": "3"
},
{
"Exists": false,
"Case": "short film",
"Coalesce": "A Astounding Reflection of a Lumberjack And a Car who must Sink a Lumberjack in A Baloon Factory",
"NullIf": "2006",
"Greatest": "7",
"Least": "6"
},
{
"Exists": false,
"Case": "short film",
"Coalesce": "A Fanciful Documentary of a Frisbee And a Lumberjack who must Chase a Monkey in A Shark Tank",
"NullIf": "2006",
"Greatest": "5",
"Least": "5"
}
]
`)
}
func TestCustomSetReturningFunction(t *testing.T) {
skipForCockroachDB(t) // no set Set-Returning Functions
inventoryID := IntegerColumn("inventoryID")
filmsInStock := CTE("film_in_stock", inventoryID)
stmt := WITH(
filmsInStock.AS(
RawStatement("SELECT * FROM dvds.film_in_stock(#filmID, #storeID)",
RawArgs{
"#filmID": 1,
"#storeID": 2,
}),
),
)(
SELECT(
Inventory.AllColumns,
).FROM(Inventory.
INNER_JOIN(filmsInStock, Inventory.InventoryID.EQ(inventoryID)),
),
)
testutils.AssertStatementSql(t, stmt, `
WITH film_in_stock ("inventoryID") AS (SELECT * FROM dvds.film_in_stock($1, $2)
)
SELECT inventory.inventory_id AS "inventory.inventory_id",
inventory.film_id AS "inventory.film_id",
inventory.store_id AS "inventory.store_id",
inventory.last_update AS "inventory.last_update"
FROM dvds.inventory
INNER JOIN film_in_stock ON (inventory.inventory_id = film_in_stock."inventoryID");
`)
var dest []model.Inventory
err := stmt.Query(db, &dest)
require.NoError(t, err)
testutils.AssertJSON(t, dest, `
[
{
"InventoryID": 5,
"FilmID": 1,
"StoreID": 2,
"LastUpdate": "2006-02-15T10:09:17Z"
},
{
"InventoryID": 7,
"FilmID": 1,
"StoreID": 2,
"LastUpdate": "2006-02-15T10:09:17Z"
},
{
"InventoryID": 8,
"FilmID": 1,
"StoreID": 2,
"LastUpdate": "2006-02-15T10:09:17Z"
}
]
`)
}
var customer0 = model.Customer{
CustomerID: 1,
StoreID: 1,
FirstName: "Mary",
LastName: "Smith",
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: ptr.Of(int32(1)),
}
var customer1 = model.Customer{
CustomerID: 2,
StoreID: 1,
FirstName: "Patricia",
LastName: "Johnson",
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: ptr.Of(int32(1)),
}
var lastCustomer = model.Customer{
CustomerID: 599,
StoreID: 2,
FirstName: "Austin",
LastName: "Cintron",
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: ptr.Of(int32(1)),
}