Skip to content

Commit

Permalink
Add support for expression in OFFSET clause.
Browse files Browse the repository at this point in the history
  • Loading branch information
go-jet committed Feb 13, 2024
1 parent dab153a commit 255f4a8
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 23 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -579,5 +579,5 @@ To run the tests, additional dependencies are required:

## License

Copyright 2019-2023 Goran Bjelanovic
Copyright 2019-2024 Goran Bjelanovic
Licensed under the Apache License, Version 2.0.
12 changes: 7 additions & 5 deletions internal/jet/clause.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,16 +222,18 @@ func (l *ClauseLimit) Serialize(statementType StatementType, out *SQLBuilder, op

// ClauseOffset struct
type ClauseOffset struct {
Count int64
Count IntegerExpression
}

// Serialize serializes clause into SQLBuilder
func (o *ClauseOffset) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
if o.Count >= 0 {
out.NewLine()
out.WriteString("OFFSET")
out.insertParametrizedArgument(o.Count)
if is.Nil(o.Count) {
return
}

out.NewLine()
out.WriteString("OFFSET")
o.Count.serialize(statementType, out, options...)
}

// ClauseFetch struct
Expand Down
3 changes: 1 addition & 2 deletions mysql/select_statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ func newSelectStatement(table ReadableTable, projections []Projection) SelectSta
newSelect.From.Tables = []jet.Serializer{table}
}
newSelect.Limit.Count = -1
newSelect.Offset.Count = -1
newSelect.ShareLock.Name = "LOCK IN SHARE MODE"
newSelect.ShareLock.InNewLine = true

Expand Down Expand Up @@ -158,7 +157,7 @@ func (s *selectStatementImpl) LIMIT(limit int64) SelectStatement {
}

func (s *selectStatementImpl) OFFSET(offset int64) SelectStatement {
s.Offset.Count = offset
s.Offset.Count = Int(offset)
return s
}

Expand Down
3 changes: 1 addition & 2 deletions mysql/set_statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ func newSetStatementImpl(operator string, all bool, selects []jet.SerializerStat
newSetStatement.setOperator.All = all
newSetStatement.setOperator.Selects = selects
newSetStatement.setOperator.Limit.Count = -1
newSetStatement.setOperator.Offset.Count = -1

newSetStatement.setOperatorsImpl.parent = newSetStatement

Expand All @@ -81,7 +80,7 @@ func (s *setStatementImpl) LIMIT(limit int64) setStatement {
}

func (s *setStatementImpl) OFFSET(offset int64) setStatement {
s.setOperator.Offset.Count = offset
s.setOperator.Offset.Count = Int(offset)
return s
}

Expand Down
8 changes: 7 additions & 1 deletion postgres/select_statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ type SelectStatement interface {
ORDER_BY(orderByClauses ...OrderByClause) SelectStatement
LIMIT(limit int64) SelectStatement
OFFSET(offset int64) SelectStatement
// OFFSET_e can be used when an integer expression is needed as offset, otherwise OFFSET can be used
OFFSET_e(offset IntegerExpression) SelectStatement
FETCH_FIRST(count IntegerExpression) fetchExpand
FOR(lock RowLock) SelectStatement

Expand Down Expand Up @@ -91,7 +93,6 @@ func newSelectStatement(table ReadableTable, projections []Projection) SelectSta
newSelect.From.Tables = []jet.Serializer{table}
}
newSelect.Limit.Count = -1
newSelect.Offset.Count = -1

newSelect.setOperatorsImpl.parent = newSelect

Expand Down Expand Up @@ -157,6 +158,11 @@ func (s *selectStatementImpl) LIMIT(limit int64) SelectStatement {
}

func (s *selectStatementImpl) OFFSET(offset int64) SelectStatement {
s.Offset.Count = Int(offset)
return s
}

func (s *selectStatementImpl) OFFSET_e(offset IntegerExpression) SelectStatement {
s.Offset.Count = offset
return s
}
Expand Down
8 changes: 7 additions & 1 deletion postgres/set_statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ type setStatement interface {

LIMIT(limit int64) setStatement
OFFSET(offset int64) setStatement
// OFFSET_e can be used when an integer expression is needed as offset, otherwise OFFSET can be used
OFFSET_e(offset IntegerExpression) setStatement

AsTable(alias string) SelectTable
}
Expand Down Expand Up @@ -107,7 +109,6 @@ func newSetStatementImpl(operator string, all bool, selects []jet.SerializerStat
newSetStatement.setOperator.All = all
newSetStatement.setOperator.Selects = selects
newSetStatement.setOperator.Limit.Count = -1
newSetStatement.setOperator.Offset.Count = -1

newSetStatement.setOperatorsImpl.parent = newSetStatement

Expand All @@ -125,6 +126,11 @@ func (s *setStatementImpl) LIMIT(limit int64) setStatement {
}

func (s *setStatementImpl) OFFSET(offset int64) setStatement {
s.setOperator.Offset.Count = Int(offset)
return s
}

func (s *setStatementImpl) OFFSET_e(offset IntegerExpression) setStatement {
s.setOperator.Offset.Count = offset
return s
}
Expand Down
3 changes: 1 addition & 2 deletions sqlite/select_statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ func newSelectStatement(table ReadableTable, projections []Projection) SelectSta
newSelect.From.Tables = []jet.Serializer{table}
}
newSelect.Limit.Count = -1
newSelect.Offset.Count = -1
newSelect.ShareLock.Name = "LOCK IN SHARE MODE"
newSelect.ShareLock.InNewLine = true

Expand Down Expand Up @@ -141,7 +140,7 @@ func (s *selectStatementImpl) LIMIT(limit int64) SelectStatement {
}

func (s *selectStatementImpl) OFFSET(offset int64) SelectStatement {
s.Offset.Count = offset
s.Offset.Count = Int(offset)
return s
}

Expand Down
3 changes: 1 addition & 2 deletions sqlite/set_statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ func newSetStatementImpl(operator string, all bool, selects []jet.SerializerStat
newSetStatement.setOperator.All = all
newSetStatement.setOperator.Selects = selects
newSetStatement.setOperator.Limit.Count = -1
newSetStatement.setOperator.Offset.Count = -1
newSetStatement.setOperator.SkipSelectWrap = true

newSetStatement.setOperatorsImpl.parent = newSetStatement
Expand All @@ -82,7 +81,7 @@ func (s *setStatementImpl) LIMIT(limit int64) setStatement {
}

func (s *setStatementImpl) OFFSET(offset int64) setStatement {
s.setOperator.Offset.Count = offset
s.setOperator.Offset.Count = Int(offset)
return s
}

Expand Down
94 changes: 87 additions & 7 deletions tests/postgres/select_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,38 @@ FETCH FIRST (
})
}

func TestOffsetExpression(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 TestJoinQueryStruct(t *testing.T) {

expectedSQL := `
Expand Down Expand Up @@ -2365,16 +2397,14 @@ OFFSET 20;
Payment.
SELECT(Payment.PaymentID, Payment.Amount).
WHERE(Payment.Amount.GT_EQ(Float(200))),
).
ORDER_BY(IntegerColumn("payment.payment_id").ASC(), Payment.Amount.DESC()).
LIMIT(10).
OFFSET(20)

//fmt.Println(query.DebugSql())
).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))

dest := []model.Payment{}
var dest []model.Payment

err := query.Query(db, &dest)

Expand All @@ -2394,6 +2424,56 @@ OFFSET 20;
})
}

func TestUnionOffsetWithExpression(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 TestAllSetOperators(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))))
Expand Down

0 comments on commit 255f4a8

Please sign in to comment.