Skip to content

Commit 751dbc6

Browse files
authored
Merge pull request #192 from doug-martin/v9.6.0-rc
V9.6.0 rc
2 parents 1dd9123 + d04abcc commit 751dbc6

14 files changed

Lines changed: 253 additions & 15 deletions

HISTORY.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# v9.6.0
2+
3+
* [ADDED] Support for Lateral queries [#182](https://github.com/doug-martin/goqu/issues/182)
4+
15
# v9.5.1
26

37
* [FIXED] WITH clause without a RETURNING clause will panic [#177](https://github.com/doug-martin/goqu/issues/177)

dialect/sqlite3/sqlite3.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ func DialectOptions() *goqu.SQLDialectOptions {
2020
opts.WrapCompoundsInParens = false
2121
opts.SupportsDistinctOn = false
2222
opts.SupportsWindowFunction = false
23+
opts.SupportsLateral = false
2324

2425
opts.PlaceHolderRune = '?'
2526
opts.IncludePlaceholderNum = false

docs/expressions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* [`V`](#V) - An Value to be used in SQL.
1313
* [`And`](#and) - AND multiple expressions together.
1414
* [`Or`](#or) - OR multiple expressions together.
15-
* [Complex Example] - Complex Example using most of the Expression DSL.
15+
* [Complex Example](#complex) - Complex Example using most of the Expression DSL.
1616

1717
The entry points for expressions are:
1818

docs/selecting.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,39 @@ Output:
258258
SELECT * FROM (SELECT * FROM "test" WHERE ("age" > 10)) AS "test2"
259259
```
260260

261+
Lateral Query
262+
263+
```go
264+
maxEntry := goqu.From("entry").
265+
Select(goqu.MAX("int").As("max_int")).
266+
Where(goqu.Ex{"time": goqu.Op{"lt": goqu.I("e.time")}}).
267+
As("max_entry")
268+
269+
maxId := goqu.From("entry").
270+
Select("id").
271+
Where(goqu.Ex{"int": goqu.I("max_entry.max_int")}).
272+
As("max_id")
273+
274+
ds := goqu.
275+
Select("e.id", "max_entry.max_int", "max_id.id").
276+
From(
277+
goqu.T("entry").As("e"),
278+
goqu.Lateral(maxEntry),
279+
goqu.Lateral(maxId),
280+
)
281+
query, args, _ := ds.ToSQL()
282+
fmt.Println(query, args)
283+
284+
query, args, _ = ds.Prepared(true).ToSQL()
285+
fmt.Println(query, args)
286+
```
287+
288+
Output
289+
```
290+
SELECT "e"."id", "max_entry"."max_int", "max_id"."id" FROM "entry" AS "e", LATERAL (SELECT MAX("int") AS "max_int" FROM "entry" WHERE ("time" < "e"."time")) AS "max_entry", LATERAL (SELECT "id" FROM "entry" WHERE ("int" = "max_entry"."max_int")) AS "max_id" []
291+
SELECT "e"."id", "max_entry"."max_int", "max_id"."id" FROM "entry" AS "e", LATERAL (SELECT MAX("int") AS "max_int" FROM "entry" WHERE ("time" < "e"."time")) AS "max_entry", LATERAL (SELECT "id" FROM "entry" WHERE ("int" = "max_entry"."max_int")) AS "max_id" []
292+
```
293+
261294
<a name="joins"></a>
262295
**[`Join`](https://godoc.org/github.com/doug-martin/goqu/#SelectDataset.Join)**
263296

@@ -452,6 +485,38 @@ Output:
452485
SELECT * FROM "test" CROSS JOIN "test2"
453486
```
454487

488+
Join with a Lateral
489+
490+
```go
491+
maxEntry := goqu.From("entry").
492+
Select(goqu.MAX("int").As("max_int")).
493+
Where(goqu.Ex{"time": goqu.Op{"lt": goqu.I("e.time")}}).
494+
As("max_entry")
495+
496+
maxId := goqu.From("entry").
497+
Select("id").
498+
Where(goqu.Ex{"int": goqu.I("max_entry.max_int")}).
499+
As("max_id")
500+
501+
ds := goqu.
502+
Select("e.id", "max_entry.max_int", "max_id.id").
503+
From(goqu.T("entry").As("e")).
504+
Join(goqu.Lateral(maxEntry), goqu.On(goqu.V(true))).
505+
Join(goqu.Lateral(maxId), goqu.On(goqu.V(true)))
506+
query, args, _ := ds.ToSQL()
507+
fmt.Println(query, args)
508+
509+
query, args, _ = ds.Prepared(true).ToSQL()
510+
fmt.Println(query, args)
511+
```
512+
513+
Output:
514+
```
515+
SELECT "e"."id", "max_entry"."max_int", "max_id"."id" FROM "entry" AS "e" INNER JOIN LATERAL (SELECT MAX("int") AS "max_int" FROM "entry" WHERE ("time" < "e"."time")) AS "max_entry" ON TRUE INNER JOIN LATERAL (SELECT "id" FROM "entry" WHERE ("int" = "max_entry"."max_int")) AS "max_id" ON TRUE []
516+
517+
SELECT "e"."id", "max_entry"."max_int", "max_id"."id" FROM "entry" AS "e" INNER JOIN LATERAL (SELECT MAX("int") AS "max_int" FROM "entry" WHERE ("time" < "e"."time")) AS "max_entry" ON ? INNER JOIN LATERAL (SELECT "id" FROM "entry" WHERE ("int" = "max_entry"."max_int")) AS "max_id" ON ? [true true]
518+
```
519+
455520
<a name="where"></a>
456521
**[`Where`](https://godoc.org/github.com/doug-martin/goqu/#SelectDataset.Where)**
457522

@@ -1187,3 +1252,4 @@ fmt.Printf("\nIds := %+v", ids)
11871252

11881253

11891254

1255+

exp/exp.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,11 @@ type (
316316
Condition() JoinCondition
317317
IsConditionEmpty() bool
318318
}
319+
LateralExpression interface {
320+
Expression
321+
Aliaseable
322+
Table() AppendableExpression
323+
}
319324

320325
// Expression for representing "literal" sql.
321326
// L("col = 1") -> col = 1)

exp/lateral.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package exp
2+
3+
type (
4+
lateral struct {
5+
table AppendableExpression
6+
}
7+
)
8+
9+
// Creates a new SQL lateral expression
10+
// L(From("test")) -> LATERAL (SELECT * FROM "tests")
11+
func NewLateralExpression(table AppendableExpression) LateralExpression {
12+
return lateral{table: table}
13+
}
14+
15+
func (l lateral) Clone() Expression {
16+
return NewLateralExpression(l.table)
17+
}
18+
19+
func (l lateral) Table() AppendableExpression {
20+
return l.table
21+
}
22+
23+
func (l lateral) Expression() Expression { return l }
24+
func (l lateral) As(val interface{}) AliasedExpression { return aliased(l, val) }

exp/lateral_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package exp
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/suite"
7+
)
8+
9+
type lateralExpressionSuite struct {
10+
suite.Suite
11+
}
12+
13+
func TestLateralExpressionSuite(t *testing.T) {
14+
suite.Run(t, &lateralExpressionSuite{})
15+
}
16+
17+
func (les *lateralExpressionSuite) TestClone() {
18+
le := NewLateralExpression(newTestAppendableExpression(`SELECT * FROM "test"`, []interface{}{}))
19+
les.Equal(NewLateralExpression(newTestAppendableExpression(`SELECT * FROM "test"`, []interface{}{})), le.Clone())
20+
}
21+
22+
func (les *lateralExpressionSuite) TestExpression() {
23+
le := NewLateralExpression(newTestAppendableExpression(`SELECT * FROM "test"`, []interface{}{}))
24+
les.Equal(le, le.Expression())
25+
}
26+
27+
func (les *lateralExpressionSuite) TestLateral() {
28+
le := NewLateralExpression(newTestAppendableExpression(`SELECT * FROM "test"`, []interface{}{}))
29+
les.Equal(newTestAppendableExpression(`SELECT * FROM "test"`, []interface{}{}), le.Table())
30+
}
31+
32+
func (les *lateralExpressionSuite) TestAs() {
33+
le := NewLateralExpression(newTestAppendableExpression(`SELECT * FROM "test"`, []interface{}{}))
34+
les.Equal(aliased(le, "foo"), le.As("foo"))
35+
}

expressions.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,3 +283,7 @@ func Star() exp.LiteralExpression { return exp.Star() }
283283
func Default() exp.LiteralExpression {
284284
return exp.Default()
285285
}
286+
287+
func Lateral(table exp.AppendableExpression) exp.LateralExpression {
288+
return exp.NewLateralExpression(table)
289+
}

expressions_example_test.go

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1737,9 +1737,65 @@ func ExampleW() {
17371737
Window(goqu.W("w").PartitionBy("a"))
17381738
query, args, _ = ds.ToSQL()
17391739
fmt.Println(query, args)
1740-
// Output
1740+
// Output:
17411741
// SELECT ROW_NUMBER() OVER (PARTITION BY "a" ORDER BY "b" ASC) FROM "test" []
17421742
// SELECT ROW_NUMBER() OVER "w" FROM "test" WINDOW "w" AS (PARTITION BY "a" ORDER BY "b" ASC) []
1743-
// SELECT ROW_NUMBER() OVER "w" FROM "test" WINDOW "w1" AS (PARTITION BY "a"), "w" AS ("w1" ORDER BY "b" ASC) []
1743+
// SELECT ROW_NUMBER() OVER "w1" FROM "test" WINDOW "w1" AS (PARTITION BY "a"), "w" AS ("w1" ORDER BY "b" ASC) []
17441744
// SELECT ROW_NUMBER() OVER ("w" ORDER BY "b") FROM "test" WINDOW "w" AS (PARTITION BY "a") []
17451745
}
1746+
1747+
func ExampleLateral() {
1748+
maxEntry := goqu.From("entry").
1749+
Select(goqu.MAX("int").As("max_int")).
1750+
Where(goqu.Ex{"time": goqu.Op{"lt": goqu.I("e.time")}}).
1751+
As("max_entry")
1752+
1753+
maxID := goqu.From("entry").
1754+
Select("id").
1755+
Where(goqu.Ex{"int": goqu.I("max_entry.max_int")}).
1756+
As("max_id")
1757+
1758+
ds := goqu.
1759+
Select("e.id", "max_entry.max_int", "max_id.id").
1760+
From(
1761+
goqu.T("entry").As("e"),
1762+
goqu.Lateral(maxEntry),
1763+
goqu.Lateral(maxID),
1764+
)
1765+
query, args, _ := ds.ToSQL()
1766+
fmt.Println(query, args)
1767+
1768+
query, args, _ = ds.Prepared(true).ToSQL()
1769+
fmt.Println(query, args)
1770+
1771+
// Output:
1772+
// SELECT "e"."id", "max_entry"."max_int", "max_id"."id" FROM "entry" AS "e", LATERAL (SELECT MAX("int") AS "max_int" FROM "entry" WHERE ("time" < "e"."time")) AS "max_entry", LATERAL (SELECT "id" FROM "entry" WHERE ("int" = "max_entry"."max_int")) AS "max_id" []
1773+
// SELECT "e"."id", "max_entry"."max_int", "max_id"."id" FROM "entry" AS "e", LATERAL (SELECT MAX("int") AS "max_int" FROM "entry" WHERE ("time" < "e"."time")) AS "max_entry", LATERAL (SELECT "id" FROM "entry" WHERE ("int" = "max_entry"."max_int")) AS "max_id" []
1774+
}
1775+
1776+
func ExampleLateral_join() {
1777+
maxEntry := goqu.From("entry").
1778+
Select(goqu.MAX("int").As("max_int")).
1779+
Where(goqu.Ex{"time": goqu.Op{"lt": goqu.I("e.time")}}).
1780+
As("max_entry")
1781+
1782+
maxID := goqu.From("entry").
1783+
Select("id").
1784+
Where(goqu.Ex{"int": goqu.I("max_entry.max_int")}).
1785+
As("max_id")
1786+
1787+
ds := goqu.
1788+
Select("e.id", "max_entry.max_int", "max_id.id").
1789+
From(goqu.T("entry").As("e")).
1790+
Join(goqu.Lateral(maxEntry), goqu.On(goqu.V(true))).
1791+
Join(goqu.Lateral(maxID), goqu.On(goqu.V(true)))
1792+
query, args, _ := ds.ToSQL()
1793+
fmt.Println(query, args)
1794+
1795+
query, args, _ = ds.Prepared(true).ToSQL()
1796+
fmt.Println(query, args)
1797+
1798+
// Output:
1799+
// SELECT "e"."id", "max_entry"."max_int", "max_id"."id" FROM "entry" AS "e" INNER JOIN LATERAL (SELECT MAX("int") AS "max_int" FROM "entry" WHERE ("time" < "e"."time")) AS "max_entry" ON TRUE INNER JOIN LATERAL (SELECT "id" FROM "entry" WHERE ("int" = "max_entry"."max_int")) AS "max_id" ON TRUE []
1800+
// SELECT "e"."id", "max_entry"."max_int", "max_id"."id" FROM "entry" AS "e" INNER JOIN LATERAL (SELECT MAX("int") AS "max_int" FROM "entry" WHERE ("time" < "e"."time")) AS "max_entry" ON ? INNER JOIN LATERAL (SELECT "id" FROM "entry" WHERE ("int" = "max_entry"."max_int")) AS "max_id" ON ? [true true]
1801+
}

expressions_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,11 @@ func (ges *goquExpressionsSuite) TestDefault() {
169169
ges.Equal(exp.Default(), Default())
170170
}
171171

172+
func (ges *goquExpressionsSuite) TestLateral() {
173+
ds := From("test")
174+
ges.Equal(exp.NewLateralExpression(ds), Lateral(ds))
175+
}
176+
172177
func TestGoquExpressions(t *testing.T) {
173178
suite.Run(t, new(goquExpressionsSuite))
174179
}

0 commit comments

Comments
 (0)