Merge remote-tracking branch 'remotes/origin/add-lateral' into develop
# Conflicts: # tests/mysql/select_test.go # tests/postgres/select_test.go
This commit is contained in:
commit
5ab430c367
13 changed files with 345 additions and 22 deletions
|
|
@ -45,19 +45,25 @@ func (s *ClauseSelect) Serialize(statementType StatementType, out *SQLBuilder, o
|
||||||
|
|
||||||
// ClauseFrom struct
|
// ClauseFrom struct
|
||||||
type ClauseFrom struct {
|
type ClauseFrom struct {
|
||||||
Table Serializer
|
Tables []Serializer
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serialize serializes clause into SQLBuilder
|
// Serialize serializes clause into SQLBuilder
|
||||||
func (f *ClauseFrom) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
|
func (f *ClauseFrom) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||||
if f.Table == nil {
|
if len(f.Tables) == 0 { // SELECT statement does not have to have FROM clause
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
out.NewLine()
|
out.NewLine()
|
||||||
out.WriteString("FROM")
|
out.WriteString("FROM")
|
||||||
|
|
||||||
out.IncreaseIdent()
|
out.IncreaseIdent()
|
||||||
f.Table.serialize(statementType, out, FallTrough(options)...)
|
for i, table := range f.Tables {
|
||||||
|
if i > 0 {
|
||||||
|
out.WriteString(",")
|
||||||
|
out.NewLine()
|
||||||
|
}
|
||||||
|
table.serialize(statementType, out, FallTrough(options)...)
|
||||||
|
}
|
||||||
out.DecreaseIdent()
|
out.DecreaseIdent()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@ type selectTableImpl struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSelectTable func
|
// NewSelectTable func
|
||||||
func NewSelectTable(selectStmt SerializerStatement, alias string) SelectTable {
|
func NewSelectTable(selectStmt SerializerStatement, alias string) selectTableImpl {
|
||||||
selectTable := &selectTableImpl{selectStmt: selectStmt, alias: alias}
|
selectTable := selectTableImpl{selectStmt: selectStmt, alias: alias}
|
||||||
return selectTable
|
return selectTable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -38,3 +38,21 @@ func (s selectTableImpl) serialize(statement StatementType, out *SQLBuilder, opt
|
||||||
out.WriteString("AS")
|
out.WriteString("AS")
|
||||||
out.WriteIdentifier(s.alias)
|
out.WriteIdentifier(s.alias)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --------------------------------------
|
||||||
|
|
||||||
|
type lateralImpl struct {
|
||||||
|
selectTableImpl
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLateral(selectStmt SerializerStatement, alias string) SelectTable {
|
||||||
|
return lateralImpl{selectTableImpl: NewSelectTable(selectStmt, alias)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s lateralImpl) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
|
||||||
|
out.WriteString("LATERAL")
|
||||||
|
s.selectStmt.serialize(statement, out)
|
||||||
|
|
||||||
|
out.WriteString("AS")
|
||||||
|
out.WriteIdentifier(s.alias)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -136,9 +136,6 @@ func (t *joinTableImpl) TableName() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *joinTableImpl) AS(alias string) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *joinTableImpl) columns() []Column {
|
func (t *joinTableImpl) columns() []Column {
|
||||||
var ret []Column
|
var ret []Column
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/go-jet/jet/v2/internal/utils"
|
"github.com/go-jet/jet/v2/internal/utils"
|
||||||
"github.com/go-jet/jet/v2/qrm"
|
"github.com/go-jet/jet/v2/qrm"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -116,7 +117,12 @@ func AssertDebugStatementSql(t *testing.T, query jet.Statement, expectedQuery st
|
||||||
}
|
}
|
||||||
|
|
||||||
debuqSql := query.DebugSql()
|
debuqSql := query.DebugSql()
|
||||||
require.Equal(t, debuqSql, expectedQuery)
|
if !assert.Equal(t, debuqSql, expectedQuery) {
|
||||||
|
fmt.Println("Expected: ")
|
||||||
|
fmt.Println(expectedQuery)
|
||||||
|
fmt.Println("Got: ")
|
||||||
|
fmt.Println(debuqSql)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssertSerialize checks if clause serialize produces expected query and args
|
// AssertSerialize checks if clause serialize produces expected query and args
|
||||||
|
|
|
||||||
23
mysql/lateral.go
Normal file
23
mysql/lateral.go
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
package mysql
|
||||||
|
|
||||||
|
import "github.com/go-jet/jet/v2/internal/jet"
|
||||||
|
|
||||||
|
func LATERAL(selectStmt SelectStatement) lateralImpl {
|
||||||
|
return lateralImpl{
|
||||||
|
selectStmt: selectStmt,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type lateralImpl struct {
|
||||||
|
selectStmt SelectStatement
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l lateralImpl) AS(alias string) SelectTable {
|
||||||
|
subQuery := &selectTableImpl{
|
||||||
|
SelectTable: jet.NewLateral(l.selectStmt, alias),
|
||||||
|
}
|
||||||
|
|
||||||
|
subQuery.readableTableInterfaceImpl.parent = subQuery
|
||||||
|
|
||||||
|
return subQuery
|
||||||
|
}
|
||||||
|
|
@ -41,7 +41,7 @@ type SelectStatement interface {
|
||||||
Expression
|
Expression
|
||||||
|
|
||||||
DISTINCT() SelectStatement
|
DISTINCT() SelectStatement
|
||||||
FROM(table ReadableTable) SelectStatement
|
FROM(tables ...ReadableTable) SelectStatement
|
||||||
WHERE(expression BoolExpression) SelectStatement
|
WHERE(expression BoolExpression) SelectStatement
|
||||||
GROUP_BY(groupByClauses ...jet.GroupByClause) SelectStatement
|
GROUP_BY(groupByClauses ...jet.GroupByClause) SelectStatement
|
||||||
HAVING(boolExpression BoolExpression) SelectStatement
|
HAVING(boolExpression BoolExpression) SelectStatement
|
||||||
|
|
@ -70,7 +70,9 @@ func newSelectStatement(table ReadableTable, projections []Projection) SelectSta
|
||||||
&newSelect.Limit, &newSelect.Offset, &newSelect.For, &newSelect.ShareLock)
|
&newSelect.Limit, &newSelect.Offset, &newSelect.For, &newSelect.ShareLock)
|
||||||
|
|
||||||
newSelect.Select.ProjectionList = projections
|
newSelect.Select.ProjectionList = projections
|
||||||
newSelect.From.Table = table
|
if table != nil {
|
||||||
|
newSelect.From.Tables = []jet.Serializer{table}
|
||||||
|
}
|
||||||
newSelect.Limit.Count = -1
|
newSelect.Limit.Count = -1
|
||||||
newSelect.Offset.Count = -1
|
newSelect.Offset.Count = -1
|
||||||
newSelect.ShareLock.Name = "LOCK IN SHARE MODE"
|
newSelect.ShareLock.Name = "LOCK IN SHARE MODE"
|
||||||
|
|
@ -103,8 +105,10 @@ func (s *selectStatementImpl) DISTINCT() SelectStatement {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *selectStatementImpl) FROM(table ReadableTable) SelectStatement {
|
func (s *selectStatementImpl) FROM(tables ...ReadableTable) SelectStatement {
|
||||||
s.From.Table = table
|
for _, table := range tables {
|
||||||
|
s.From.Tables = append(s.From.Tables, table)
|
||||||
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
23
postgres/lateral.go
Normal file
23
postgres/lateral.go
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
package postgres
|
||||||
|
|
||||||
|
import "github.com/go-jet/jet/v2/internal/jet"
|
||||||
|
|
||||||
|
func LATERAL(selectStmt SelectStatement) lateralImpl {
|
||||||
|
return lateralImpl{
|
||||||
|
selectStmt: selectStmt,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type lateralImpl struct {
|
||||||
|
selectStmt SelectStatement
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l lateralImpl) AS(alias string) SelectTable {
|
||||||
|
subQuery := &selectTableImpl{
|
||||||
|
SelectTable: jet.NewLateral(l.selectStmt, alias),
|
||||||
|
}
|
||||||
|
|
||||||
|
subQuery.readableTableInterfaceImpl.parent = subQuery
|
||||||
|
|
||||||
|
return subQuery
|
||||||
|
}
|
||||||
14
postgres/lateral_test.go
Normal file
14
postgres/lateral_test.go
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
package postgres
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestLATERAL(t *testing.T) {
|
||||||
|
assertSerialize(t,
|
||||||
|
LATERAL(
|
||||||
|
SELECT(Int(1)),
|
||||||
|
).AS("lat1"),
|
||||||
|
|
||||||
|
`LATERAL (
|
||||||
|
SELECT $1
|
||||||
|
) AS lat1`)
|
||||||
|
}
|
||||||
|
|
@ -44,7 +44,7 @@ type SelectStatement interface {
|
||||||
Expression
|
Expression
|
||||||
|
|
||||||
DISTINCT() SelectStatement
|
DISTINCT() SelectStatement
|
||||||
FROM(table ReadableTable) SelectStatement
|
FROM(tables ...ReadableTable) SelectStatement
|
||||||
WHERE(expression BoolExpression) SelectStatement
|
WHERE(expression BoolExpression) SelectStatement
|
||||||
GROUP_BY(groupByClauses ...jet.GroupByClause) SelectStatement
|
GROUP_BY(groupByClauses ...jet.GroupByClause) SelectStatement
|
||||||
HAVING(boolExpression BoolExpression) SelectStatement
|
HAVING(boolExpression BoolExpression) SelectStatement
|
||||||
|
|
@ -76,7 +76,9 @@ func newSelectStatement(table ReadableTable, projections []Projection) SelectSta
|
||||||
&newSelect.Limit, &newSelect.Offset, &newSelect.For)
|
&newSelect.Limit, &newSelect.Offset, &newSelect.For)
|
||||||
|
|
||||||
newSelect.Select.ProjectionList = projections
|
newSelect.Select.ProjectionList = projections
|
||||||
newSelect.From.Table = table
|
if table != nil {
|
||||||
|
newSelect.From.Tables = []jet.Serializer{table}
|
||||||
|
}
|
||||||
newSelect.Limit.Count = -1
|
newSelect.Limit.Count = -1
|
||||||
newSelect.Offset.Count = -1
|
newSelect.Offset.Count = -1
|
||||||
|
|
||||||
|
|
@ -106,8 +108,10 @@ func (s *selectStatementImpl) DISTINCT() SelectStatement {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *selectStatementImpl) FROM(table ReadableTable) SelectStatement {
|
func (s *selectStatementImpl) FROM(tables ...ReadableTable) SelectStatement {
|
||||||
s.From.Table = table
|
for _, table := range tables {
|
||||||
|
s.From.Tables = append(s.From.Tables, table)
|
||||||
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -99,3 +99,26 @@ CROSS JOIN db.table2`)
|
||||||
CROSS JOIN db.table2
|
CROSS JOIN db.table2
|
||||||
CROSS JOIN db.table3`)
|
CROSS JOIN db.table3`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestImplicitCROSS_JOIN(t *testing.T) {
|
||||||
|
assertDebugStatementSql(t,
|
||||||
|
SELECT(table1Col1, table2Col3).
|
||||||
|
FROM(table1, table2),
|
||||||
|
`
|
||||||
|
SELECT table1.col1 AS "table1.col1",
|
||||||
|
table2.col3 AS "table2.col3"
|
||||||
|
FROM db.table1,
|
||||||
|
db.table2;
|
||||||
|
`)
|
||||||
|
assertDebugStatementSql(t,
|
||||||
|
SELECT(
|
||||||
|
table1Col1, table2Col3,
|
||||||
|
).FROM(table1, table2, table3),
|
||||||
|
`
|
||||||
|
SELECT table1.col1 AS "table1.col1",
|
||||||
|
table2.col3 AS "table2.col3"
|
||||||
|
FROM db.table1,
|
||||||
|
db.table2,
|
||||||
|
db.table3;
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,3 +64,9 @@ func requireLogged(t *testing.T, statement postgres.Statement) {
|
||||||
require.Equal(t, loggedSQLArgs, args)
|
require.Equal(t, loggedSQLArgs, args)
|
||||||
require.Equal(t, loggedDebugSQL, statement.DebugSql())
|
require.Equal(t, loggedDebugSQL, statement.DebugSql())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func skipForMariaDB(t *testing.T) {
|
||||||
|
if sourceIsMariaDB() {
|
||||||
|
t.SkipNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,17 @@
|
||||||
package mysql
|
package mysql
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/go-jet/jet/v2/internal/testutils"
|
"github.com/go-jet/jet/v2/internal/testutils"
|
||||||
. "github.com/go-jet/jet/v2/mysql"
|
. "github.com/go-jet/jet/v2/mysql"
|
||||||
"github.com/go-jet/jet/v2/tests/.gentestdata/mysql/dvds/enum"
|
"github.com/go-jet/jet/v2/tests/.gentestdata/mysql/dvds/enum"
|
||||||
"github.com/go-jet/jet/v2/tests/.gentestdata/mysql/dvds/model"
|
"github.com/go-jet/jet/v2/tests/.gentestdata/mysql/dvds/model"
|
||||||
. "github.com/go-jet/jet/v2/tests/.gentestdata/mysql/dvds/table"
|
. "github.com/go-jet/jet/v2/tests/.gentestdata/mysql/dvds/table"
|
||||||
"github.com/go-jet/jet/v2/tests/.gentestdata/mysql/dvds/view"
|
"github.com/go-jet/jet/v2/tests/.gentestdata/mysql/dvds/view"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"testing"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSelect_ScanToStruct(t *testing.T) {
|
func TestSelect_ScanToStruct(t *testing.T) {
|
||||||
|
|
@ -787,3 +789,101 @@ LIMIT 5;
|
||||||
require.Equal(t, dest.Films[1].Title, "ACE GOLDFINGER")
|
require.Equal(t, dest.Films[1].Title, "ACE GOLDFINGER")
|
||||||
require.Equal(t, dest.Films[4].Title, "AFRICAN EGG")
|
require.Equal(t, dest.Films[4].Title, "AFRICAN EGG")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLateral(t *testing.T) {
|
||||||
|
skipForMariaDB(t) // MariaDB does not implement LATERAL
|
||||||
|
|
||||||
|
languages := LATERAL(
|
||||||
|
SELECT(
|
||||||
|
Language.AllColumns,
|
||||||
|
).FROM(
|
||||||
|
Language,
|
||||||
|
).WHERE(
|
||||||
|
Language.Name.NOT_IN(String("spanish")).
|
||||||
|
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, strings.Replace(`
|
||||||
|
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')) AND (film.language_id = language.language_id)
|
||||||
|
) AS films
|
||||||
|
WHERE film.film_id = 1
|
||||||
|
ORDER BY film.film_id
|
||||||
|
LIMIT 1;
|
||||||
|
`, "''", "`", -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, strings.Replace(`
|
||||||
|
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')) AND (film.language_id = language.language_id)
|
||||||
|
) AS films
|
||||||
|
WHERE film.film_id = 1
|
||||||
|
ORDER BY film.film_id
|
||||||
|
LIMIT 1;
|
||||||
|
`, "''", "`", -1))
|
||||||
|
|
||||||
|
var dest2 []FilmLanguage
|
||||||
|
|
||||||
|
err2 := stmt2.Query(db, &dest2)
|
||||||
|
require.NoError(t, err2)
|
||||||
|
require.Equal(t, dest, dest2)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,17 @@
|
||||||
package postgres
|
package postgres
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/go-jet/jet/v2/internal/testutils"
|
"github.com/go-jet/jet/v2/internal/testutils"
|
||||||
. "github.com/go-jet/jet/v2/postgres"
|
. "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/enum"
|
||||||
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/dvds/model"
|
"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/table"
|
||||||
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/dvds/view"
|
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/dvds/view"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSelect_ScanToStruct(t *testing.T) {
|
func TestSelect_ScanToStruct(t *testing.T) {
|
||||||
|
|
@ -1893,3 +1895,100 @@ WHERE ($1 AND (customer.customer_id = $2)) AND (customer.activebool = $3);
|
||||||
require.Len(t, dest, 1)
|
require.Len(t, dest, 1)
|
||||||
testutils.AssertDeepEqual(t, dest[0], customer0)
|
testutils.AssertDeepEqual(t, dest[0], customer0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLateral(t *testing.T) {
|
||||||
|
|
||||||
|
languages := LATERAL(
|
||||||
|
SELECT(
|
||||||
|
Language.AllColumns,
|
||||||
|
).FROM(
|
||||||
|
Language,
|
||||||
|
).WHERE(
|
||||||
|
Language.Name.NOT_IN(String("spanish")).
|
||||||
|
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')) 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')) 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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue