Add LATERAL query support
This commit is contained in:
parent
4ef0113f6b
commit
0f773b26d6
6 changed files with 224 additions and 12 deletions
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
|
||||
}
|
||||
|
|
@ -2,9 +2,19 @@ package postgres
|
|||
|
||||
import "github.com/go-jet/jet/v2/internal/jet"
|
||||
|
||||
func LATERAL(selectStmt SelectStatement, alias string) SelectTable {
|
||||
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(selectStmt, alias),
|
||||
SelectTable: jet.NewLateral(l.selectStmt, alias),
|
||||
}
|
||||
|
||||
subQuery.readableTableInterfaceImpl.parent = subQuery
|
||||
|
|
|
|||
|
|
@ -3,7 +3,12 @@ package postgres
|
|||
import "testing"
|
||||
|
||||
func TestLATERAL(t *testing.T) {
|
||||
assertSerialize(t, LATERAL(SELECT(Int(1)), "lat1"), `LATERAL (
|
||||
assertSerialize(t,
|
||||
LATERAL(
|
||||
SELECT(Int(1)),
|
||||
).AS("lat1"),
|
||||
|
||||
`LATERAL (
|
||||
SELECT $1
|
||||
) AS lat1`)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,3 +64,9 @@ func requireLogged(t *testing.T, statement postgres.Statement) {
|
|||
require.Equal(t, loggedSQLArgs, args)
|
||||
require.Equal(t, loggedDebugSQL, statement.DebugSql())
|
||||
}
|
||||
|
||||
func skipForMariaDB(t *testing.T) {
|
||||
if sourceIsMariaDB() {
|
||||
t.SkipNow()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
package mysql
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/go-jet/jet/v2/internal/testutils"
|
||||
. "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/model"
|
||||
. "github.com/go-jet/jet/v2/tests/.gentestdata/mysql/dvds/table"
|
||||
"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) {
|
||||
|
|
@ -787,3 +789,101 @@ LIMIT 5;
|
|||
require.Equal(t, dest.Films[1].Title, "ACE GOLDFINGER")
|
||||
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
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestSelect_ScanToStruct(t *testing.T) {
|
||||
|
|
@ -1905,22 +1907,88 @@ func TestLateral(t *testing.T) {
|
|||
Language.Name.NOT_IN(String("spanish")).
|
||||
AND(Film.LanguageID.EQ(Language.LanguageID)),
|
||||
),
|
||||
"films")
|
||||
).AS("films")
|
||||
|
||||
stmt := SELECT(
|
||||
Film.AllColumns,
|
||||
Film.FilmID,
|
||||
Film.Title,
|
||||
languages.AllColumns(),
|
||||
).FROM(
|
||||
Film.CROSS_JOIN(languages),
|
||||
).WHERE(
|
||||
Film.FilmID.EQ(Int(1)),
|
||||
)
|
||||
).ORDER_BY(
|
||||
Film.FilmID,
|
||||
).LIMIT(1)
|
||||
|
||||
var dest []struct {
|
||||
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