jet/tests/postgres/scan_test.go

977 lines
26 KiB
Go
Raw Normal View History

2019-07-30 11:45:10 +02:00
package postgres
2019-05-20 17:37:55 +02:00
import (
"context"
"testing"
"time"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
2020-06-27 18:48:19 +02:00
"github.com/go-jet/jet/v2/internal/testutils"
. "github.com/go-jet/jet/v2/postgres"
"github.com/go-jet/jet/v2/qrm"
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/dvds/model"
. "github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/dvds/table"
2019-05-20 17:37:55 +02:00
)
var oneInventoryQuery = Inventory.
2019-05-20 17:37:55 +02:00
SELECT(Inventory.AllColumns).
LIMIT(1).
ORDER_BY(Inventory.InventoryID)
func TestScanToInvalidDestination(t *testing.T) {
t.Run("nil dest", func(t *testing.T) {
testutils.AssertQueryPanicErr(t, oneInventoryQuery, db, nil, "jet: destination is nil")
2019-05-20 17:37:55 +02:00
})
t.Run("struct dest", func(t *testing.T) {
testutils.AssertQueryPanicErr(t, oneInventoryQuery, db, struct{}{}, "jet: destination has to be a pointer to slice or pointer to struct")
2019-05-20 17:37:55 +02:00
})
t.Run("slice dest", func(t *testing.T) {
testutils.AssertQueryPanicErr(t, oneInventoryQuery, db, []struct{}{}, "jet: destination has to be a pointer to slice or pointer to struct")
2019-05-20 17:37:55 +02:00
})
t.Run("slice of pointers to pointer dest", func(t *testing.T) {
testutils.AssertQueryPanicErr(t, oneInventoryQuery, db, []**struct{}{}, "jet: destination has to be a pointer to slice or pointer to struct")
2019-05-20 17:37:55 +02:00
})
2019-08-13 17:20:35 +02:00
t.Run("map dest", func(t *testing.T) {
testutils.AssertQueryPanicErr(t, oneInventoryQuery, db, &map[string]string{}, "jet: destination has to be a pointer to slice or pointer to struct")
2019-08-13 17:20:35 +02:00
})
2019-05-20 17:37:55 +02:00
t.Run("map dest", func(t *testing.T) {
testutils.AssertQueryPanicErr(t, oneInventoryQuery, db, []map[string]string{}, "jet: destination has to be a pointer to slice or pointer to struct")
2019-05-20 17:37:55 +02:00
})
2019-08-13 17:20:35 +02:00
t.Run("map dest", func(t *testing.T) {
testutils.AssertQueryPanicErr(t, oneInventoryQuery, db, &[]map[string]string{}, "jet: unsupported slice element type")
2019-08-13 17:20:35 +02:00
})
2019-05-20 17:37:55 +02:00
}
func TestScanToValidDestination(t *testing.T) {
t.Run("pointer to struct", func(t *testing.T) {
dest := []struct{}{}
err := oneInventoryQuery.Query(db, &dest)
2019-05-20 17:37:55 +02:00
require.NoError(t, err)
2019-05-20 17:37:55 +02:00
})
2019-08-13 17:20:35 +02:00
t.Run("global query function scan", func(t *testing.T) {
queryStr, args := oneInventoryQuery.Sql()
dest := []struct{}{}
err := qrm.Query(nil, db, queryStr, args, &dest)
require.NoError(t, err)
2019-08-13 17:20:35 +02:00
})
2019-05-20 17:37:55 +02:00
t.Run("pointer to slice", func(t *testing.T) {
err := oneInventoryQuery.Query(db, &[]struct{}{})
2019-05-20 17:37:55 +02:00
require.NoError(t, err)
2019-05-20 17:37:55 +02:00
})
t.Run("pointer to slice of pointer to structs", func(t *testing.T) {
err := oneInventoryQuery.Query(db, &[]*struct{}{})
2019-05-20 17:37:55 +02:00
require.NoError(t, err)
2019-05-20 17:37:55 +02:00
})
t.Run("pointer to slice of strings", func(t *testing.T) {
err := oneInventoryQuery.Query(db, &[]int32{})
2019-05-22 11:28:32 +02:00
require.NoError(t, err)
2019-05-22 11:28:32 +02:00
})
t.Run("pointer to slice of strings", func(t *testing.T) {
err := oneInventoryQuery.Query(db, &[]*int32{})
2019-05-20 17:37:55 +02:00
require.NoError(t, err)
2019-05-20 17:37:55 +02:00
})
}
func TestScanToStruct(t *testing.T) {
query := Inventory.
SELECT(Inventory.AllColumns).
ORDER_BY(Inventory.InventoryID)
//fmt.Println(query.DebugSql())
2019-08-13 17:20:35 +02:00
2019-05-20 17:37:55 +02:00
t.Run("one struct", func(t *testing.T) {
dest := model.Inventory{}
err := query.LIMIT(1).Query(db, &dest)
require.NoError(t, err)
testutils.AssertDeepEqual(t, inventory1, dest)
2019-05-20 17:37:55 +02:00
})
t.Run("multiple structs, just first one used", func(t *testing.T) {
dest := model.Inventory{}
err := query.LIMIT(10).Query(db, &dest)
require.NoError(t, err)
testutils.AssertDeepEqual(t, inventory1, dest)
2019-05-20 17:37:55 +02:00
})
t.Run("one struct", func(t *testing.T) {
dest := struct {
model.Inventory
}{}
err := query.LIMIT(1).Query(db, &dest)
require.NoError(t, err)
testutils.AssertDeepEqual(t, inventory1, dest.Inventory)
2019-05-20 17:37:55 +02:00
})
t.Run("one struct", func(t *testing.T) {
dest := struct {
*model.Inventory
}{}
err := query.LIMIT(1).Query(db, &dest)
require.NoError(t, err)
testutils.AssertDeepEqual(t, inventory1, *dest.Inventory)
2019-05-20 17:37:55 +02:00
})
t.Run("invalid dest", func(t *testing.T) {
dest := struct {
Inventory **model.Inventory
}{}
testutils.AssertQueryPanicErr(t, query, db, &dest, "jet: unsupported dest type: Inventory **model.Inventory")
2019-05-20 17:37:55 +02:00
})
t.Run("invalid dest 2", func(t *testing.T) {
dest := struct {
Inventory ***model.Inventory
}{}
testutils.AssertQueryPanicErr(t, query, db, &dest, "jet: unsupported dest type: Inventory ***model.Inventory")
2019-05-20 17:37:55 +02:00
})
2019-05-21 17:34:43 +02:00
t.Run("custom struct", func(t *testing.T) {
type Inventory struct {
2019-06-26 10:30:31 +02:00
InventoryID *int32 `sql:"primary_key"`
2019-05-21 17:34:43 +02:00
FilmID int16
StoreID *int16
}
dest := Inventory{}
err := query.Query(db, &dest)
require.NoError(t, err)
2019-05-21 17:34:43 +02:00
require.Equal(t, *dest.InventoryID, int32(1))
require.Equal(t, dest.FilmID, int16(1))
require.Equal(t, *dest.StoreID, int16(1))
2019-05-21 17:34:43 +02:00
})
2019-07-29 18:08:53 +02:00
t.Run("type convert int32 to int", func(t *testing.T) {
2019-05-22 11:28:32 +02:00
type Inventory struct {
InventoryID int
FilmID string
}
dest := Inventory{}
err := query.Query(db, &dest)
require.NoError(t, err)
2019-05-22 11:28:32 +02:00
})
t.Run("type mismatch scanner type", func(t *testing.T) {
type Inventory struct {
InventoryID uuid.UUID
FilmID string
}
dest := Inventory{}
2019-08-13 17:20:35 +02:00
testutils.AssertQueryPanicErr(t, query, db, &dest, `jet: Scan: unable to scan type int32 into UUID, at 'InventoryID uuid.UUID' of type postgres.Inventory`)
2019-05-22 11:28:32 +02:00
})
2019-08-13 17:20:35 +02:00
t.Run("type mismatch base type", func(t *testing.T) {
type Inventory struct {
InventoryID int32
FilmID bool
}
dest := []Inventory{}
testutils.AssertQueryPanicErr(t, query.OFFSET(10), db, &dest, `jet: can't set int16 to bool`)
})
2019-05-20 17:37:55 +02:00
}
func TestScanToNestedStruct(t *testing.T) {
query := Inventory.
2019-05-29 14:03:38 +02:00
INNER_JOIN(Film, Inventory.FilmID.EQ(Film.FilmID)).
INNER_JOIN(Store, Inventory.StoreID.EQ(Store.StoreID)).
2019-05-20 17:37:55 +02:00
SELECT(Inventory.AllColumns, Film.AllColumns, Store.AllColumns).
2019-05-29 14:03:38 +02:00
WHERE(Inventory.InventoryID.EQ(Int(1)))
2019-05-20 17:37:55 +02:00
t.Run("embedded structs", func(t *testing.T) {
dest := struct {
model.Inventory
model.Film
model.Store
}{}
err := query.Query(db, &dest)
require.NoError(t, err)
testutils.AssertDeepEqual(t, dest.Inventory, inventory1)
testutils.AssertDeepEqual(t, dest.Film, film1)
testutils.AssertDeepEqual(t, dest.Store, store1)
2019-05-20 17:37:55 +02:00
})
t.Run("embedded pointer structs", func(t *testing.T) {
dest := struct {
*model.Inventory
*model.Film
*model.Store
}{}
err := query.Query(db, &dest)
require.NoError(t, err)
testutils.AssertDeepEqual(t, *dest.Inventory, inventory1)
testutils.AssertDeepEqual(t, *dest.Film, film1)
testutils.AssertDeepEqual(t, *dest.Store, store1)
2019-05-20 17:37:55 +02:00
})
t.Run("embedded unused structs", func(t *testing.T) {
dest := struct {
model.Inventory
model.Actor //unused
}{}
err := query.Query(db, &dest)
require.NoError(t, err)
testutils.AssertDeepEqual(t, dest.Inventory, inventory1)
testutils.AssertDeepEqual(t, dest.Actor, model.Actor{})
2019-05-20 17:37:55 +02:00
})
t.Run("embedded unused pointer structs", func(t *testing.T) {
dest := struct {
model.Inventory
*model.Actor //unused
}{}
err := query.Query(db, &dest)
require.NoError(t, err)
testutils.AssertDeepEqual(t, dest.Inventory, inventory1)
testutils.AssertDeepEqual(t, dest.Actor, (*model.Actor)(nil))
2019-05-20 17:37:55 +02:00
})
t.Run("embedded unused pointer structs", func(t *testing.T) {
dest := struct {
model.Inventory
Actor *model.Actor //unused
}{}
err := query.Query(db, &dest)
require.NoError(t, err)
testutils.AssertDeepEqual(t, dest.Inventory, inventory1)
testutils.AssertDeepEqual(t, dest.Actor, (*model.Actor)(nil))
2019-05-20 17:37:55 +02:00
})
t.Run("embedded pointer to selected column", func(t *testing.T) {
query := Inventory.
2019-05-29 14:03:38 +02:00
INNER_JOIN(Film, Inventory.FilmID.EQ(Film.FilmID)).
INNER_JOIN(Store, Inventory.StoreID.EQ(Store.StoreID)).
SELECT(Inventory.AllColumns, Film.AllColumns, Store.AllColumns, String("").AS("actor.first_name")).
2019-05-29 14:03:38 +02:00
WHERE(Inventory.InventoryID.EQ(Int(1)))
2019-05-20 17:37:55 +02:00
dest := struct {
model.Inventory
Actor *model.Actor //unused
}{}
err := query.Query(db, &dest)
require.NoError(t, err)
testutils.AssertDeepEqual(t, dest.Inventory, inventory1)
require.True(t, dest.Actor != nil)
2019-05-20 17:37:55 +02:00
})
t.Run("struct embedded unused pointer", func(t *testing.T) {
dest := struct {
model.Inventory
Actor *struct {
model.Actor
} //unused
}{}
err := query.Query(db, &dest)
require.NoError(t, err)
testutils.AssertDeepEqual(t, dest.Inventory, inventory1)
testutils.AssertDeepEqual(t, dest.Actor, (*struct{ model.Actor })(nil))
2019-05-20 17:37:55 +02:00
})
t.Run("multiple embedded unused pointer", func(t *testing.T) {
dest := struct {
model.Inventory
Actor *struct {
model.Actor //unused
model.Language //unesed
}
}{}
err := query.Query(db, &dest)
require.NoError(t, err)
testutils.AssertDeepEqual(t, dest.Inventory, inventory1)
testutils.AssertDeepEqual(t, dest.Actor, (*struct {
2019-05-20 17:37:55 +02:00
model.Actor
model.Language
})(nil))
})
t.Run("field not nil, embedded selected model", func(t *testing.T) {
dest := struct {
model.Inventory
Actor *struct {
model.Actor //unselected
model.Film //selected
}
}{}
err := query.Query(db, &dest)
require.NoError(t, err)
testutils.AssertDeepEqual(t, dest.Inventory, inventory1)
require.True(t, dest.Actor != nil)
testutils.AssertDeepEqual(t, dest.Actor.Actor, model.Actor{})
testutils.AssertDeepEqual(t, dest.Actor.Film, film1)
2019-05-20 17:37:55 +02:00
})
t.Run("field not nil, deeply nested selected model", func(t *testing.T) {
dest := struct {
model.Inventory
Actor *struct {
model.Actor //unselected
Film *struct {
*model.Film //selected
}
}
}{}
err := query.Query(db, &dest)
require.NoError(t, err)
testutils.AssertDeepEqual(t, dest.Inventory, inventory1)
require.True(t, dest.Actor != nil)
require.True(t, dest.Actor.Film != nil)
testutils.AssertDeepEqual(t, dest.Actor.Film.Film, &film1)
2019-05-20 17:37:55 +02:00
})
t.Run("embedded structs", func(t *testing.T) {
query := Inventory.
2019-05-29 14:03:38 +02:00
INNER_JOIN(Film, Inventory.FilmID.EQ(Film.FilmID)).
INNER_JOIN(Store, Inventory.StoreID.EQ(Store.StoreID)).
INNER_JOIN(Language, Film.LanguageID.EQ(Language.LanguageID)).
2019-05-20 17:37:55 +02:00
SELECT(Inventory.AllColumns, Film.AllColumns, Store.AllColumns, Language.AllColumns).
2019-05-29 14:03:38 +02:00
WHERE(Inventory.InventoryID.EQ(Int(1)))
2019-05-20 17:37:55 +02:00
2019-06-12 12:47:30 +02:00
type Language3 model.Language
2019-05-20 17:37:55 +02:00
dest := struct {
model.Inventory
Film struct {
model.Film
Language model.Language
2019-06-26 10:30:31 +02:00
Language2 *model.Language `alias:"Language.*"`
Language3 *Language3 `alias:"language"`
2019-05-20 17:37:55 +02:00
Lang struct {
model.Language
}
Lang2 *struct {
model.Language
}
}
Store model.Store
}{}
err := query.Query(db, &dest)
require.NoError(t, err)
testutils.AssertDeepEqual(t, dest.Inventory, inventory1)
testutils.AssertDeepEqual(t, dest.Film.Film, film1)
testutils.AssertDeepEqual(t, dest.Store, store1)
testutils.AssertDeepEqual(t, dest.Film.Language, language1)
testutils.AssertDeepEqual(t, dest.Film.Lang.Language, language1)
testutils.AssertDeepEqual(t, dest.Film.Lang2.Language, language1)
testutils.AssertDeepEqual(t, dest.Film.Language2, &language1)
testutils.AssertDeepEqual(t, model.Language(*dest.Film.Language3), language1)
2019-05-20 17:37:55 +02:00
})
}
func TestScanToSlice(t *testing.T) {
t.Run("slice of structs", func(t *testing.T) {
query := Inventory.
SELECT(Inventory.AllColumns).
ORDER_BY(Inventory.InventoryID).
LIMIT(10)
t.Run("slice od inventory", func(t *testing.T) {
dest := []model.Inventory{}
2019-05-20 17:37:55 +02:00
err := query.Query(db, &dest)
2019-05-20 17:37:55 +02:00
require.NoError(t, err)
require.Equal(t, len(dest), 10)
testutils.AssertDeepEqual(t, dest[0], inventory1)
testutils.AssertDeepEqual(t, dest[1], inventory2)
})
t.Run("slice of ints", func(t *testing.T) {
var dest []int32
err := query.Query(db, &dest)
require.NoError(t, err)
testutils.AssertDeepEqual(t, dest, []int32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
})
2019-05-22 11:28:32 +02:00
2019-08-13 17:20:35 +02:00
t.Run("slice type convertible", func(t *testing.T) {
2019-05-22 11:28:32 +02:00
var dest []int
err := query.Query(db, &dest)
require.NoError(t, err)
2019-08-13 17:20:35 +02:00
})
t.Run("slice type mismatch", func(t *testing.T) {
var dest []bool
testutils.AssertQueryPanicErr(t, query, db, &dest, `jet: can't append int32 to []bool slice`)
//require.Error(t, err, `jet: can't append int32 to []bool slice `)
2019-05-22 11:28:32 +02:00
})
2019-05-20 17:37:55 +02:00
})
t.Run("slice of complex structs", func(t *testing.T) {
query := Inventory.
2019-05-29 14:03:38 +02:00
INNER_JOIN(Film, Inventory.FilmID.EQ(Film.FilmID)).
INNER_JOIN(Store, Inventory.StoreID.EQ(Store.StoreID)).
2019-06-26 10:30:31 +02:00
SELECT(
Inventory.AllColumns,
Film.AllColumns,
Store.AllColumns,
).
2019-05-20 17:37:55 +02:00
ORDER_BY(Inventory.InventoryID).
LIMIT(10)
t.Run("struct with slice of ints", func(t *testing.T) {
var dest struct {
model.Film
2019-06-26 10:30:31 +02:00
IDs []int32 `alias:"inventory.inventory_id"`
}
err := query.Query(db, &dest)
require.NoError(t, err)
testutils.AssertDeepEqual(t, dest.Film, film1)
testutils.AssertDeepEqual(t, dest.IDs, []int32{1, 2, 3, 4, 5, 6, 7, 8})
})
t.Run("slice of structs with slice of ints", func(t *testing.T) {
var dest []struct {
model.Film
IDs []int32 `alias:"inventory.inventory_id"`
}
err := query.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 2)
testutils.AssertDeepEqual(t, dest[0].Film, film1)
testutils.AssertDeepEqual(t, dest[0].IDs, []int32{1, 2, 3, 4, 5, 6, 7, 8})
testutils.AssertDeepEqual(t, dest[1].Film, film2)
testutils.AssertDeepEqual(t, dest[1].IDs, []int32{9, 10})
})
t.Run("slice of structs with slice of pointer to ints", func(t *testing.T) {
var dest []struct {
model.Film
IDs []*int32 `alias:"inventory.inventory_id"`
}
err := query.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 2)
testutils.AssertDeepEqual(t, dest[0].Film, film1)
2020-05-02 22:15:38 +02:00
testutils.AssertDeepEqual(t, dest[0].IDs, []*int32{testutils.Int32Ptr(1), testutils.Int32Ptr(2), testutils.Int32Ptr(3), testutils.Int32Ptr(4),
testutils.Int32Ptr(5), testutils.Int32Ptr(6), testutils.Int32Ptr(7), testutils.Int32Ptr(8)})
testutils.AssertDeepEqual(t, dest[1].Film, film2)
2020-05-02 22:15:38 +02:00
testutils.AssertDeepEqual(t, dest[1].IDs, []*int32{testutils.Int32Ptr(9), testutils.Int32Ptr(10)})
})
2019-05-20 17:37:55 +02:00
t.Run("complex struct 1", func(t *testing.T) {
dest := []struct {
model.Inventory
model.Film
model.Store
}{}
err := query.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 10)
testutils.AssertDeepEqual(t, dest[0].Inventory, inventory1)
testutils.AssertDeepEqual(t, dest[0].Film, film1)
testutils.AssertDeepEqual(t, dest[0].Store, store1)
2019-05-20 17:37:55 +02:00
testutils.AssertDeepEqual(t, dest[1].Inventory, inventory2)
2019-05-20 17:37:55 +02:00
})
t.Run("complex struct 2", func(t *testing.T) {
var dest []struct {
*model.Inventory
model.Film
*model.Store
}
err := query.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 10)
testutils.AssertDeepEqual(t, dest[0].Inventory, &inventory1)
testutils.AssertDeepEqual(t, dest[0].Film, film1)
testutils.AssertDeepEqual(t, dest[0].Store, &store1)
2019-05-20 17:37:55 +02:00
testutils.AssertDeepEqual(t, dest[1].Inventory, &inventory2)
2019-05-20 17:37:55 +02:00
})
t.Run("complex struct 3", func(t *testing.T) {
var dest []struct {
Inventory model.Inventory
Film *model.Film
Store struct {
*model.Store
}
}
err := query.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 10)
testutils.AssertDeepEqual(t, dest[0].Inventory, inventory1)
testutils.AssertDeepEqual(t, dest[0].Film, &film1)
testutils.AssertDeepEqual(t, dest[0].Store.Store, &store1)
2019-05-20 17:37:55 +02:00
testutils.AssertDeepEqual(t, dest[1].Inventory, inventory2)
2019-05-20 17:37:55 +02:00
})
t.Run("complex struct 4", func(t *testing.T) {
var dest []struct {
model.Film
Inventories []struct {
model.Inventory
model.Store
}
}
err := query.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 2)
testutils.AssertDeepEqual(t, dest[0].Film, film1)
testutils.AssertDeepEqual(t, len(dest[0].Inventories), 8)
testutils.AssertDeepEqual(t, dest[0].Inventories[0].Inventory, inventory1)
testutils.AssertDeepEqual(t, dest[0].Inventories[0].Store, store1)
2019-05-20 17:37:55 +02:00
})
t.Run("complex struct 5", func(t *testing.T) {
var dest []struct {
model.Film
Inventories []struct {
model.Inventory
Rentals *[]model.Rental
Rentals2 []model.Rental
}
}
err := query.Query(db, &dest)
require.NoError(t, err)
2019-05-20 17:37:55 +02:00
require.Equal(t, len(dest), 2)
testutils.AssertDeepEqual(t, dest[0].Film, film1)
require.Equal(t, len(dest[0].Inventories), 8)
testutils.AssertDeepEqual(t, dest[0].Inventories[0].Inventory, inventory1)
require.True(t, dest[0].Inventories[0].Rentals == nil)
require.True(t, dest[0].Inventories[0].Rentals2 == nil)
2019-05-20 17:37:55 +02:00
})
})
t.Run("slice of complex structs 2", func(t *testing.T) {
query := Country.
2019-05-29 14:03:38 +02:00
INNER_JOIN(City, City.CountryID.EQ(Country.CountryID)).
INNER_JOIN(Address, Address.CityID.EQ(City.CityID)).
INNER_JOIN(Customer, Customer.AddressID.EQ(Address.AddressID)).
2019-05-20 17:37:55 +02:00
SELECT(Country.AllColumns, City.AllColumns, Address.AllColumns, Customer.AllColumns).
ORDER_BY(Country.CountryID.ASC(), City.CityID.ASC(), Address.AddressID.ASC(), Customer.CustomerID.ASC()).
LIMIT(1000)
t.Run("dest1", func(t *testing.T) {
var dest []struct {
model.Country
Cities []struct {
model.City
Adresses []struct {
model.Address
Customer model.Customer
}
}
}
err := query.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 108)
testutils.AssertDeepEqual(t, dest[100].Country, countryUk)
require.Equal(t, len(dest[100].Cities), 8)
testutils.AssertDeepEqual(t, dest[100].Cities[2].City, cityLondon)
require.Equal(t, len(dest[100].Cities[2].Adresses), 2)
testutils.AssertDeepEqual(t, dest[100].Cities[2].Adresses[0].Address, address256)
testutils.AssertDeepEqual(t, dest[100].Cities[2].Adresses[0].Customer, customer256)
testutils.AssertDeepEqual(t, dest[100].Cities[2].Adresses[1].Address, addres517)
testutils.AssertDeepEqual(t, dest[100].Cities[2].Adresses[1].Customer, customer512)
2019-05-20 17:37:55 +02:00
})
t.Run("dest1", func(t *testing.T) {
var dest []*struct {
*model.Country
Cities []*struct {
*model.City
Adresses *[]*struct {
*model.Address
Customer *model.Customer
}
}
}
err := query.Query(db, &dest)
require.NoError(t, err)
require.Equal(t, len(dest), 108)
testutils.AssertDeepEqual(t, dest[100].Country, &countryUk)
require.Equal(t, len(dest[100].Cities), 8)
testutils.AssertDeepEqual(t, dest[100].Cities[2].City, &cityLondon)
require.Equal(t, len(*dest[100].Cities[2].Adresses), 2)
testutils.AssertDeepEqual(t, (*dest[100].Cities[2].Adresses)[0].Address, &address256)
testutils.AssertDeepEqual(t, (*dest[100].Cities[2].Adresses)[0].Customer, &customer256)
testutils.AssertDeepEqual(t, (*dest[100].Cities[2].Adresses)[1].Address, &addres517)
testutils.AssertDeepEqual(t, (*dest[100].Cities[2].Adresses)[1].Customer, &customer512)
2019-05-20 17:37:55 +02:00
})
})
t.Run("dest1", func(t *testing.T) {
var dest []*struct {
*model.Country
Cities []**struct {
*model.City
}
}
testutils.AssertQueryPanicErr(t, oneInventoryQuery, db, &dest, "jet: unsupported slice element type at 'Cities []**struct { *model.City }'")
2019-05-20 17:37:55 +02:00
})
}
func TestStructScanErrNoRows(t *testing.T) {
query := SELECT(Customer.AllColumns).
FROM(Customer).
WHERE(Customer.CustomerID.EQ(Int(-1)))
customer := model.Customer{}
err := query.Query(db, &customer)
require.Error(t, err, qrm.ErrNoRows.Error())
}
func TestStructScanAllNull(t *testing.T) {
query := SELECT(NULL.AS("null1"), NULL.AS("null2"))
dest := struct {
Null1 *int
Null2 *int
}{}
err := query.Query(db, &dest)
require.NoError(t, err)
testutils.AssertDeepEqual(t, dest, struct {
Null1 *int
Null2 *int
}{})
}
func TestRowsScan(t *testing.T) {
stmt := SELECT(
Inventory.AllColumns,
).FROM(
Inventory,
).ORDER_BY(
Inventory.InventoryID.ASC(),
)
rows, err := stmt.Rows(context.Background(), db)
require.NoError(t, err)
for rows.Next() {
var inventory model.Inventory
err = rows.Scan(&inventory)
require.NoError(t, err)
require.NotEqual(t, inventory.InventoryID, int32(0))
require.NotEqual(t, inventory.FilmID, int16(0))
require.NotEqual(t, inventory.StoreID, int16(0))
require.NotEqual(t, inventory.LastUpdate, time.Time{})
if inventory.InventoryID == 2103 {
require.Equal(t, inventory.FilmID, int16(456))
require.Equal(t, inventory.StoreID, int16(2))
require.Equal(t, inventory.LastUpdate.Format(time.RFC3339), "2006-02-15T10:09:17Z")
}
}
err = rows.Close()
require.NoError(t, err)
err = rows.Err()
require.NoError(t, err)
requireLogged(t, stmt)
}
func TestScanNumericToNumber(t *testing.T) {
type Number struct {
Int8 int8
UInt8 uint8
Int16 int16
UInt16 uint16
Int32 int32
UInt32 uint32
Int64 int64
UInt64 uint64
Float32 float32
Float64 float64
}
numeric := CAST(Decimal("1234567890.111")).AS_NUMERIC()
stmt := SELECT(
numeric.AS("number.int8"),
numeric.AS("number.uint8"),
numeric.AS("number.int16"),
numeric.AS("number.uint16"),
numeric.AS("number.int32"),
numeric.AS("number.uint32"),
numeric.AS("number.int64"),
numeric.AS("number.uint64"),
numeric.AS("number.float32"),
numeric.AS("number.float64"),
)
var number Number
err := stmt.Query(db, &number)
require.NoError(t, err)
require.Equal(t, number.Int8, int8(-46)) // overflow
require.Equal(t, number.UInt8, uint8(210)) // overflow
require.Equal(t, number.Int16, int16(722)) // overflow
require.Equal(t, number.UInt16, uint16(722)) // overflow
require.Equal(t, number.Int32, int32(1234567890))
require.Equal(t, number.UInt32, uint32(1234567890))
require.Equal(t, number.Int64, int64(1234567890))
require.Equal(t, number.UInt64, uint64(1234567890))
require.Equal(t, number.Float32, float32(1.234568e+09))
require.Equal(t, number.Float64, float64(1.234567890111e+09))
}
// QueryContext panic when the scanned value is nil and the destination is a slice of primitive
// https://github.com/go-jet/jet/issues/91
func TestScanToPrimitiveElementsSlice(t *testing.T) {
tx, err := db.Begin()
require.NoError(t, err)
defer tx.Rollback()
// add actor without associated film (so that destination Title array is NULL).
_, err = Actor.INSERT().
MODEL(
model.Actor{
ActorID: 201,
FirstName: "Brigitte",
LastName: "Bardot",
LastUpdate: time.Time{},
},
).Exec(tx)
require.NoError(t, err)
stmt := SELECT(
Actor.ActorID.AS("actor_id"),
Film.Title.AS("title"),
).FROM(
Actor.
LEFT_JOIN(FilmActor, Actor.ActorID.EQ(FilmActor.ActorID)).
LEFT_JOIN(Film, Film.FilmID.EQ(FilmActor.FilmID)),
).WHERE(
Actor.ActorID.GT(Int(199)),
).ORDER_BY(Actor.ActorID.DESC())
var dest []struct {
ActorID int `sql:"primary_key"`
Title []string
}
err = stmt.Query(tx, &dest)
require.NoError(t, err)
require.Equal(t, dest[0].ActorID, 201)
require.Equal(t, dest[0].Title, []string(nil))
require.Equal(t, dest[1].ActorID, 200)
require.Len(t, dest[1].Title, 20)
}
2019-05-20 17:37:55 +02:00
var address256 = model.Address{
AddressID: 256,
Address: "1497 Yuzhou Drive",
2020-05-02 22:15:38 +02:00
Address2: testutils.StringPtr(""),
2019-05-20 17:37:55 +02:00
District: "England",
CityID: 312,
2020-05-02 22:15:38 +02:00
PostalCode: testutils.StringPtr("3433"),
2019-05-20 17:37:55 +02:00
Phone: "246810237916",
2019-07-29 18:08:53 +02:00
LastUpdate: *testutils.TimestampWithoutTimeZone("2006-02-15 09:45:30", 0),
2019-05-20 17:37:55 +02:00
}
var addres517 = model.Address{
AddressID: 517,
Address: "548 Uruapan Street",
2020-05-02 22:15:38 +02:00
Address2: testutils.StringPtr(""),
2019-05-20 17:37:55 +02:00
District: "Ontario",
CityID: 312,
2020-05-02 22:15:38 +02:00
PostalCode: testutils.StringPtr("35653"),
2019-05-20 17:37:55 +02:00
Phone: "879347453467",
2019-07-29 18:08:53 +02:00
LastUpdate: *testutils.TimestampWithoutTimeZone("2006-02-15 09:45:30", 0),
2019-05-20 17:37:55 +02:00
}
var customer256 = model.Customer{
CustomerID: 252,
StoreID: 2,
FirstName: "Mattie",
LastName: "Hoffman",
2020-05-02 22:15:38 +02:00
Email: testutils.StringPtr("mattie.hoffman@sakilacustomer.org"),
2019-05-20 17:37:55 +02:00
AddressID: 256,
Activebool: true,
2019-07-29 18:08:53 +02:00
CreateDate: *testutils.TimestampWithoutTimeZone("2006-02-14 00:00:00", 0),
LastUpdate: testutils.TimestampWithoutTimeZone("2013-05-26 14:49:45.738", 0),
2020-05-02 22:15:38 +02:00
Active: testutils.Int32Ptr(1),
2019-05-20 17:37:55 +02:00
}
var customer512 = model.Customer{
CustomerID: 512,
StoreID: 1,
FirstName: "Cecil",
LastName: "Vines",
2020-05-02 22:15:38 +02:00
Email: testutils.StringPtr("cecil.vines@sakilacustomer.org"),
2019-05-20 17:37:55 +02:00
AddressID: 517,
Activebool: true,
2019-07-29 18:08:53 +02:00
CreateDate: *testutils.TimestampWithoutTimeZone("2006-02-14 00:00:00", 0),
LastUpdate: testutils.TimestampWithoutTimeZone("2013-05-26 14:49:45.738", 0),
2020-05-02 22:15:38 +02:00
Active: testutils.Int32Ptr(1),
2019-05-20 17:37:55 +02:00
}
var countryUk = model.Country{
CountryID: 102,
Country: "United Kingdom",
2019-07-29 18:08:53 +02:00
LastUpdate: *testutils.TimestampWithoutTimeZone("2006-02-15 09:44:00", 0),
2019-05-20 17:37:55 +02:00
}
var cityLondon = model.City{
CityID: 312,
City: "London",
CountryID: 102,
2019-07-29 18:08:53 +02:00
LastUpdate: *testutils.TimestampWithoutTimeZone("2006-02-15 09:45:25", 0),
2019-05-20 17:37:55 +02:00
}
var inventory1 = model.Inventory{
InventoryID: 1,
FilmID: 1,
StoreID: 1,
2019-07-29 18:08:53 +02:00
LastUpdate: *testutils.TimestampWithoutTimeZone("2006-02-15 10:09:17", 0),
2019-05-20 17:37:55 +02:00
}
var inventory2 = model.Inventory{
InventoryID: 2,
FilmID: 1,
StoreID: 1,
2019-07-29 18:08:53 +02:00
LastUpdate: *testutils.TimestampWithoutTimeZone("2006-02-15 10:09:17", 0),
2019-05-20 17:37:55 +02:00
}
var film1 = model.Film{
FilmID: 1,
Title: "Academy Dinosaur",
2020-05-02 22:15:38 +02:00
Description: testutils.StringPtr("A Epic Drama of a Feminist And a Mad Scientist who must Battle a Teacher in The Canadian Rockies"),
ReleaseYear: testutils.Int32Ptr(2006),
2019-05-20 17:37:55 +02:00
LanguageID: 1,
RentalDuration: 6,
RentalRate: 0.99,
2020-05-02 22:15:38 +02:00
Length: testutils.Int16Ptr(86),
2019-05-20 17:37:55 +02:00
ReplacementCost: 20.99,
Rating: &pgRating,
2019-07-29 18:08:53 +02:00
LastUpdate: *testutils.TimestampWithoutTimeZone("2013-05-26 14:50:58.951", 3),
2020-05-02 22:15:38 +02:00
SpecialFeatures: testutils.StringPtr("{\"Deleted Scenes\",\"Behind the Scenes\"}"),
2019-05-20 17:37:55 +02:00
Fulltext: "'academi':1 'battl':15 'canadian':20 'dinosaur':2 'drama':5 'epic':4 'feminist':8 'mad':11 'must':14 'rocki':21 'scientist':12 'teacher':17",
}
var film2 = model.Film{
FilmID: 2,
Title: "Ace Goldfinger",
2020-05-02 22:15:38 +02:00
Description: testutils.StringPtr("A Astounding Epistle of a Database Administrator And a Explorer who must Find a Car in Ancient China"),
ReleaseYear: testutils.Int32Ptr(2006),
LanguageID: 1,
RentalDuration: 3,
RentalRate: 4.99,
2020-05-02 22:15:38 +02:00
Length: testutils.Int16Ptr(48),
ReplacementCost: 12.99,
Rating: &gRating,
2019-07-29 18:08:53 +02:00
LastUpdate: *testutils.TimestampWithoutTimeZone("2013-05-26 14:50:58.951", 3),
2020-05-02 22:15:38 +02:00
SpecialFeatures: testutils.StringPtr(`{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`,
}
2019-05-20 17:37:55 +02:00
var store1 = model.Store{
StoreID: 1,
ManagerStaffID: 1,
AddressID: 1,
2019-07-29 18:08:53 +02:00
LastUpdate: *testutils.TimestampWithoutTimeZone("2006-02-15 09:57:12", 0),
2019-05-20 17:37:55 +02:00
}
var pgRating = model.MpaaRating_Pg
var gRating = model.MpaaRating_G
2019-05-20 17:37:55 +02:00
var language1 = model.Language{
LanguageID: 1,
Name: "English ",
2019-07-29 18:08:53 +02:00
LastUpdate: *testutils.TimestampWithoutTimeZone("2006-02-15 10:02:19", 0),
2019-05-20 17:37:55 +02:00
}