Add USING clause support for DELETE statements
This commit is contained in:
parent
72e8d7d584
commit
60ffd004c5
6 changed files with 134 additions and 11 deletions
|
|
@ -6,6 +6,7 @@ import "github.com/go-jet/jet/v2/internal/jet"
|
||||||
type DeleteStatement interface {
|
type DeleteStatement interface {
|
||||||
Statement
|
Statement
|
||||||
|
|
||||||
|
USING(tables ...ReadableTable) DeleteStatement
|
||||||
WHERE(expression BoolExpression) DeleteStatement
|
WHERE(expression BoolExpression) DeleteStatement
|
||||||
ORDER_BY(orderByClauses ...OrderByClause) DeleteStatement
|
ORDER_BY(orderByClauses ...OrderByClause) DeleteStatement
|
||||||
LIMIT(limit int64) DeleteStatement
|
LIMIT(limit int64) DeleteStatement
|
||||||
|
|
@ -15,6 +16,7 @@ type deleteStatementImpl struct {
|
||||||
jet.SerializerStatement
|
jet.SerializerStatement
|
||||||
|
|
||||||
Delete jet.ClauseStatementBegin
|
Delete jet.ClauseStatementBegin
|
||||||
|
Using jet.ClauseFrom
|
||||||
Where jet.ClauseWhere
|
Where jet.ClauseWhere
|
||||||
OrderBy jet.ClauseOrderBy
|
OrderBy jet.ClauseOrderBy
|
||||||
Limit jet.ClauseLimit
|
Limit jet.ClauseLimit
|
||||||
|
|
@ -22,10 +24,15 @@ type deleteStatementImpl struct {
|
||||||
|
|
||||||
func newDeleteStatement(table Table) DeleteStatement {
|
func newDeleteStatement(table Table) DeleteStatement {
|
||||||
newDelete := &deleteStatementImpl{}
|
newDelete := &deleteStatementImpl{}
|
||||||
newDelete.SerializerStatement = jet.NewStatementImpl(Dialect, jet.DeleteStatementType, newDelete, &newDelete.Delete,
|
newDelete.SerializerStatement = jet.NewStatementImpl(Dialect, jet.DeleteStatementType, newDelete,
|
||||||
&newDelete.Where, &newDelete.OrderBy, &newDelete.Limit)
|
&newDelete.Delete,
|
||||||
|
&newDelete.Using,
|
||||||
|
&newDelete.Where,
|
||||||
|
&newDelete.OrderBy,
|
||||||
|
&newDelete.Limit)
|
||||||
|
|
||||||
newDelete.Delete.Name = "DELETE FROM"
|
newDelete.Delete.Name = "DELETE FROM"
|
||||||
|
newDelete.Using.Name = "USING"
|
||||||
newDelete.Delete.Tables = append(newDelete.Delete.Tables, table)
|
newDelete.Delete.Tables = append(newDelete.Delete.Tables, table)
|
||||||
newDelete.Where.Mandatory = true
|
newDelete.Where.Mandatory = true
|
||||||
newDelete.Limit.Count = -1
|
newDelete.Limit.Count = -1
|
||||||
|
|
@ -33,6 +40,11 @@ func newDeleteStatement(table Table) DeleteStatement {
|
||||||
return newDelete
|
return newDelete
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *deleteStatementImpl) USING(tables ...ReadableTable) DeleteStatement {
|
||||||
|
d.Using.Tables = readableTablesToSerializerList(tables)
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
func (d *deleteStatementImpl) WHERE(expression BoolExpression) DeleteStatement {
|
func (d *deleteStatementImpl) WHERE(expression BoolExpression) DeleteStatement {
|
||||||
d.Where.Condition = expression
|
d.Where.Condition = expression
|
||||||
return d
|
return d
|
||||||
|
|
|
||||||
|
|
@ -106,10 +106,7 @@ func (s *selectStatementImpl) DISTINCT() SelectStatement {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *selectStatementImpl) FROM(tables ...ReadableTable) SelectStatement {
|
func (s *selectStatementImpl) FROM(tables ...ReadableTable) SelectStatement {
|
||||||
s.From.Tables = nil
|
s.From.Tables = readableTablesToSerializerList(tables)
|
||||||
for _, table := range tables {
|
|
||||||
s.From.Tables = append(s.From.Tables, table)
|
|
||||||
}
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,3 +186,11 @@ func toJetFrameOffset(offset interface{}) jet.Serializer {
|
||||||
|
|
||||||
return jet.FixedLiteral(offset)
|
return jet.FixedLiteral(offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readableTablesToSerializerList(tables []ReadableTable) []jet.Serializer {
|
||||||
|
var ret []jet.Serializer
|
||||||
|
for _, table := range tables {
|
||||||
|
ret = append(ret, table)
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ import "github.com/go-jet/jet/v2/internal/jet"
|
||||||
type DeleteStatement interface {
|
type DeleteStatement interface {
|
||||||
jet.SerializerStatement
|
jet.SerializerStatement
|
||||||
|
|
||||||
|
USING(tables ...ReadableTable) DeleteStatement
|
||||||
WHERE(expression BoolExpression) DeleteStatement
|
WHERE(expression BoolExpression) DeleteStatement
|
||||||
|
|
||||||
RETURNING(projections ...jet.Projection) DeleteStatement
|
RETURNING(projections ...jet.Projection) DeleteStatement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -15,22 +15,32 @@ type deleteStatementImpl struct {
|
||||||
jet.SerializerStatement
|
jet.SerializerStatement
|
||||||
|
|
||||||
Delete jet.ClauseStatementBegin
|
Delete jet.ClauseStatementBegin
|
||||||
|
Using jet.ClauseFrom
|
||||||
Where jet.ClauseWhere
|
Where jet.ClauseWhere
|
||||||
Returning jet.ClauseReturning
|
Returning jet.ClauseReturning
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDeleteStatement(table WritableTable) DeleteStatement {
|
func newDeleteStatement(table WritableTable) DeleteStatement {
|
||||||
newDelete := &deleteStatementImpl{}
|
newDelete := &deleteStatementImpl{}
|
||||||
newDelete.SerializerStatement = jet.NewStatementImpl(Dialect, jet.DeleteStatementType, newDelete, &newDelete.Delete,
|
newDelete.SerializerStatement = jet.NewStatementImpl(Dialect, jet.DeleteStatementType, newDelete,
|
||||||
&newDelete.Where, &newDelete.Returning)
|
&newDelete.Delete,
|
||||||
|
&newDelete.Using,
|
||||||
|
&newDelete.Where,
|
||||||
|
&newDelete.Returning)
|
||||||
|
|
||||||
newDelete.Delete.Name = "DELETE FROM"
|
newDelete.Delete.Name = "DELETE FROM"
|
||||||
newDelete.Delete.Tables = append(newDelete.Delete.Tables, table)
|
newDelete.Delete.Tables = append(newDelete.Delete.Tables, table)
|
||||||
|
newDelete.Using.Name = "USING"
|
||||||
newDelete.Where.Mandatory = true
|
newDelete.Where.Mandatory = true
|
||||||
|
|
||||||
return newDelete
|
return newDelete
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *deleteStatementImpl) USING(tables ...ReadableTable) DeleteStatement {
|
||||||
|
d.Using.Tables = readableTablesToSerializerList(tables)
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
func (d *deleteStatementImpl) WHERE(expression BoolExpression) DeleteStatement {
|
func (d *deleteStatementImpl) WHERE(expression BoolExpression) DeleteStatement {
|
||||||
d.Where.Condition = expression
|
d.Where.Condition = expression
|
||||||
return d
|
return d
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ type DeleteStatement interface {
|
||||||
WHERE(expression BoolExpression) DeleteStatement
|
WHERE(expression BoolExpression) DeleteStatement
|
||||||
ORDER_BY(orderByClauses ...OrderByClause) DeleteStatement
|
ORDER_BY(orderByClauses ...OrderByClause) DeleteStatement
|
||||||
LIMIT(limit int64) DeleteStatement
|
LIMIT(limit int64) DeleteStatement
|
||||||
RETURNING(projections ...jet.Projection) DeleteStatement
|
RETURNING(projections ...Projection) DeleteStatement
|
||||||
}
|
}
|
||||||
|
|
||||||
type deleteStatementImpl struct {
|
type deleteStatementImpl struct {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"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/table"
|
||||||
"github.com/go-jet/jet/v2/tests/.gentestdata/mysql/test_sample/model"
|
"github.com/go-jet/jet/v2/tests/.gentestdata/mysql/test_sample/model"
|
||||||
. "github.com/go-jet/jet/v2/tests/.gentestdata/mysql/test_sample/table"
|
. "github.com/go-jet/jet/v2/tests/.gentestdata/mysql/test_sample/table"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
@ -91,3 +92,29 @@ func initForDeleteTest(t *testing.T) {
|
||||||
|
|
||||||
testutils.AssertExec(t, stmt, db, 2)
|
testutils.AssertExec(t, stmt, db, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDeleteWithUsing(t *testing.T) {
|
||||||
|
tx := beginTx(t)
|
||||||
|
defer tx.Rollback()
|
||||||
|
|
||||||
|
stmt := table.Rental.DELETE().
|
||||||
|
USING(
|
||||||
|
table.Rental.
|
||||||
|
INNER_JOIN(table.Staff, table.Rental.StaffID.EQ(table.Staff.StaffID)),
|
||||||
|
table.Actor,
|
||||||
|
).WHERE(
|
||||||
|
table.Staff.StaffID.EQ(Int(2)).
|
||||||
|
AND(table.Rental.RentalID.LT(Int(10))),
|
||||||
|
)
|
||||||
|
|
||||||
|
testutils.AssertStatementSql(t, stmt, `
|
||||||
|
DELETE FROM dvds.rental
|
||||||
|
USING dvds.rental
|
||||||
|
INNER JOIN dvds.staff ON (rental.staff_id = staff.staff_id),
|
||||||
|
dvds.actor
|
||||||
|
WHERE (staff.staff_id = ?) AND (rental.rental_id < ?);
|
||||||
|
`)
|
||||||
|
|
||||||
|
_, err := stmt.Exec(tx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"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"
|
||||||
|
model2 "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/test_sample/model"
|
"github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/test_sample/model"
|
||||||
. "github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/test_sample/table"
|
. "github.com/go-jet/jet/v2/tests/.gentestdata/jetdb/test_sample/table"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
@ -103,3 +105,70 @@ func TestDeleteExecContext(t *testing.T) {
|
||||||
require.Error(t, err, "context deadline exceeded")
|
require.Error(t, err, "context deadline exceeded")
|
||||||
requireLogged(t, deleteStmt)
|
requireLogged(t, deleteStmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDeleteFrom(t *testing.T) {
|
||||||
|
tx := beginTx(t)
|
||||||
|
defer tx.Rollback()
|
||||||
|
|
||||||
|
stmt := table.Rental.DELETE().
|
||||||
|
USING(
|
||||||
|
table.Staff.
|
||||||
|
INNER_JOIN(table.Store, table.Store.StoreID.EQ(table.Staff.StaffID)),
|
||||||
|
table.Actor,
|
||||||
|
).WHERE(
|
||||||
|
table.Staff.StaffID.EQ(table.Rental.StaffID).
|
||||||
|
AND(table.Staff.StaffID.EQ(Int(2))).
|
||||||
|
AND(table.Rental.RentalID.LT(Int(10))),
|
||||||
|
).RETURNING(
|
||||||
|
table.Rental.AllColumns,
|
||||||
|
table.Store.AllColumns,
|
||||||
|
)
|
||||||
|
|
||||||
|
testutils.AssertStatementSql(t, stmt, `
|
||||||
|
DELETE FROM dvds.rental
|
||||||
|
USING dvds.staff
|
||||||
|
INNER JOIN dvds.store ON (store.store_id = staff.staff_id),
|
||||||
|
dvds.actor
|
||||||
|
WHERE ((staff.staff_id = rental.staff_id) AND (staff.staff_id = $1)) AND (rental.rental_id < $2)
|
||||||
|
RETURNING 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",
|
||||||
|
store.store_id AS "store.store_id",
|
||||||
|
store.manager_staff_id AS "store.manager_staff_id",
|
||||||
|
store.address_id AS "store.address_id",
|
||||||
|
store.last_update AS "store.last_update";
|
||||||
|
`)
|
||||||
|
|
||||||
|
var dest []struct {
|
||||||
|
Rental model2.Rental
|
||||||
|
Store model2.Store
|
||||||
|
}
|
||||||
|
|
||||||
|
err := stmt.Query(tx, &dest)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, dest, 3)
|
||||||
|
testutils.AssertJSON(t, dest[0], `
|
||||||
|
{
|
||||||
|
"Rental": {
|
||||||
|
"RentalID": 4,
|
||||||
|
"RentalDate": "2005-05-24T23:04:41Z",
|
||||||
|
"InventoryID": 2452,
|
||||||
|
"CustomerID": 333,
|
||||||
|
"ReturnDate": "2005-06-03T01:43:41Z",
|
||||||
|
"StaffID": 2,
|
||||||
|
"LastUpdate": "2006-02-16T02:30:53Z"
|
||||||
|
},
|
||||||
|
"Store": {
|
||||||
|
"StoreID": 2,
|
||||||
|
"ManagerStaffID": 2,
|
||||||
|
"AddressID": 2,
|
||||||
|
"LastUpdate": "2006-02-15T09:57:12Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue