Add RETURNING to Delete statement.
Add DELETE statement wiki page.
This commit is contained in:
parent
3d38946eda
commit
5e0e2f2908
10 changed files with 189 additions and 37 deletions
12
clause.go
12
clause.go
|
|
@ -124,6 +124,18 @@ func (q *queryData) writeHaving(statement statementType, having Expression) erro
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (q *queryData) writeReturning(statement statementType, returning []projection) error {
|
||||||
|
if len(returning) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
q.newLine()
|
||||||
|
q.writeString("RETURNING")
|
||||||
|
q.increaseIdent()
|
||||||
|
|
||||||
|
return q.writeProjections(statement, returning)
|
||||||
|
}
|
||||||
|
|
||||||
func (q *queryData) newLine() {
|
func (q *queryData) newLine() {
|
||||||
q.write([]byte{'\n'})
|
q.write([]byte{'\n'})
|
||||||
q.write(bytes.Repeat([]byte{' '}, q.ident))
|
q.write(bytes.Repeat([]byte{' '}, q.ident))
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ type DeleteStatement interface {
|
||||||
Statement
|
Statement
|
||||||
|
|
||||||
WHERE(expression BoolExpression) DeleteStatement
|
WHERE(expression BoolExpression) DeleteStatement
|
||||||
|
|
||||||
|
RETURNING(projections ...projection) DeleteStatement
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDeleteStatement(table WritableTable) DeleteStatement {
|
func newDeleteStatement(table WritableTable) DeleteStatement {
|
||||||
|
|
@ -22,6 +24,7 @@ func newDeleteStatement(table WritableTable) DeleteStatement {
|
||||||
type deleteStatementImpl struct {
|
type deleteStatementImpl struct {
|
||||||
table WritableTable
|
table WritableTable
|
||||||
where BoolExpression
|
where BoolExpression
|
||||||
|
returning []projection
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *deleteStatementImpl) WHERE(expression BoolExpression) DeleteStatement {
|
func (d *deleteStatementImpl) WHERE(expression BoolExpression) DeleteStatement {
|
||||||
|
|
@ -29,6 +32,11 @@ func (d *deleteStatementImpl) WHERE(expression BoolExpression) DeleteStatement {
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *deleteStatementImpl) RETURNING(projections ...projection) DeleteStatement {
|
||||||
|
d.returning = projections
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
func (d *deleteStatementImpl) serializeImpl(out *queryData) error {
|
func (d *deleteStatementImpl) serializeImpl(out *queryData) error {
|
||||||
if d == nil {
|
if d == nil {
|
||||||
return errors.New("delete statement is nil")
|
return errors.New("delete statement is nil")
|
||||||
|
|
@ -52,6 +60,10 @@ func (d *deleteStatementImpl) serializeImpl(out *queryData) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := out.writeReturning(delete_statement, d.returning); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,3 +15,11 @@ DELETE FROM db.table1
|
||||||
WHERE table1.col1 = $1;
|
WHERE table1.col1 = $1;
|
||||||
`, int64(1))
|
`, int64(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDeleteWithWhereAndReturning(t *testing.T) {
|
||||||
|
assertStatement(t, table1.DELETE().WHERE(table1Col1.EQ(Int(1))).RETURNING(table1Col1), `
|
||||||
|
DELETE FROM db.table1
|
||||||
|
WHERE table1.col1 = $1
|
||||||
|
RETURNING table1.col1 AS "table1.col1";
|
||||||
|
`, int64(1))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -142,16 +142,9 @@ func (i *insertStatementImpl) Sql() (sql string, args []interface{}, err error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(i.returning) > 0 {
|
if err = queryData.writeReturning(insert_statement, i.returning); err != nil {
|
||||||
queryData.newLine()
|
|
||||||
queryData.writeString("RETURNING")
|
|
||||||
|
|
||||||
err = queryData.writeProjections(insert_statement, i.returning)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
sql, args = queryData.finalize()
|
sql, args = queryData.finalize()
|
||||||
|
|
||||||
|
|
|
||||||
62
tests/delete_test.go
Normal file
62
tests/delete_test.go
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
package tests
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/go-jet/jet"
|
||||||
|
"github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/model"
|
||||||
|
. "github.com/go-jet/jet/tests/.gentestdata/jetdb/test_sample/table"
|
||||||
|
"gotest.tools/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDeleteWithWhere(t *testing.T) {
|
||||||
|
initForDeleteTest(t)
|
||||||
|
|
||||||
|
var expectedSql = `
|
||||||
|
DELETE FROM test_sample.link
|
||||||
|
WHERE link.name IN ('Gmail', 'Outlook');
|
||||||
|
`
|
||||||
|
deleteStmt := Link.
|
||||||
|
DELETE().
|
||||||
|
WHERE(Link.Name.IN(String("Gmail"), String("Outlook")))
|
||||||
|
|
||||||
|
assertStatementSql(t, deleteStmt, expectedSql, "Gmail", "Outlook")
|
||||||
|
assertExec(t, deleteStmt, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteWithWhereAndReturning(t *testing.T) {
|
||||||
|
initForDeleteTest(t)
|
||||||
|
|
||||||
|
var expectedSql = `
|
||||||
|
DELETE FROM test_sample.link
|
||||||
|
WHERE link.name IN ('Gmail', 'Outlook')
|
||||||
|
RETURNING link.id AS "link.id",
|
||||||
|
link.url AS "link.url",
|
||||||
|
link.name AS "link.name",
|
||||||
|
link.description AS "link.description";
|
||||||
|
`
|
||||||
|
deleteStmt := Link.
|
||||||
|
DELETE().
|
||||||
|
WHERE(Link.Name.IN(String("Gmail"), String("Outlook"))).
|
||||||
|
RETURNING(Link.AllColumns)
|
||||||
|
|
||||||
|
assertStatementSql(t, deleteStmt, expectedSql, "Gmail", "Outlook")
|
||||||
|
|
||||||
|
dest := []model.Link{}
|
||||||
|
|
||||||
|
err := deleteStmt.Query(db, &dest)
|
||||||
|
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, len(dest), 2)
|
||||||
|
assert.DeepEqual(t, dest[0].Name, "Gmail")
|
||||||
|
assert.DeepEqual(t, dest[1].Name, "Outlook")
|
||||||
|
}
|
||||||
|
|
||||||
|
func initForDeleteTest(t *testing.T) {
|
||||||
|
cleanUpLinkTable(t)
|
||||||
|
stmt := Link.INSERT(Link.URL, Link.Name, Link.Description).
|
||||||
|
VALUES("www.gmail.com", "Gmail", "Email service developed by Google").
|
||||||
|
VALUES("www.outlook.live.com", "Outlook", "Email service developed by Microsoft")
|
||||||
|
|
||||||
|
assertExec(t, stmt, 2)
|
||||||
|
}
|
||||||
|
|
@ -118,18 +118,22 @@ func (u *updateStatementImpl) Sql() (sql string, args []interface{}, err error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(u.returning) > 0 {
|
if err = out.writeReturning(update_statement, u.returning); err != nil {
|
||||||
out.newLine()
|
|
||||||
out.writeString("RETURNING")
|
|
||||||
out.increaseIdent()
|
|
||||||
out.increaseIdent()
|
|
||||||
|
|
||||||
err = serializeProjectionList(update_statement, u.returning, out)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
//if len(u.returning) > 0 {
|
||||||
|
// out.newLine()
|
||||||
|
// out.writeString("RETURNING")
|
||||||
|
// out.increaseIdent()
|
||||||
|
// out.increaseIdent()
|
||||||
|
//
|
||||||
|
// err = serializeProjectionList(update_statement, u.returning, out)
|
||||||
|
//
|
||||||
|
// if err != nil {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
sql, args = out.finalize()
|
sql, args = out.finalize()
|
||||||
return
|
return
|
||||||
|
|
|
||||||
58
wiki/DELETE.md
Normal file
58
wiki/DELETE.md
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
DELETE statement deletes rows that satisfy the WHERE clause from the specified table. More about delete statement
|
||||||
|
in PostgreSQL: https://www.postgresql.org/docs/11/sql-delete.html
|
||||||
|
|
||||||
|
Following clauses are supported:
|
||||||
|
- WHERE(delete_condition) - Only rows for which delete condition returns true will be deleted.
|
||||||
|
- RETURNING(output_expression...) - An expressions to be computed and returned by the DELETE command after each row is deleted.
|
||||||
|
The expression can use any column names of the table. Write _TableName_.AllColumns to return all columns.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```
|
||||||
|
// delete all links with name 'Gmail' and 'Outlook'
|
||||||
|
deleteStmt := Link.
|
||||||
|
DELETE().
|
||||||
|
WHERE(Link.Name.IN(String("Gmail"), String("Outlook")))
|
||||||
|
```
|
||||||
|
|
||||||
|
Debug sql of above statement:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
DELETE FROM test_sample.link -- test_sample is name of the schema
|
||||||
|
WHERE link.name IN ('Gmail', 'Outlook');
|
||||||
|
```
|
||||||
|
|
||||||
|
### Execute statement
|
||||||
|
|
||||||
|
To execute delete statement and get sql.Result:
|
||||||
|
|
||||||
|
```
|
||||||
|
res, err := deleteStmt.Exec(db)
|
||||||
|
```
|
||||||
|
|
||||||
|
To execute delete statement and return records deleted,
|
||||||
|
delete statement has to have RETURNING clause:
|
||||||
|
|
||||||
|
```
|
||||||
|
deleteStmt := Link.
|
||||||
|
DELETE().
|
||||||
|
WHERE(Link.Name.IN(String("Gmail"), String("Outlook"))).
|
||||||
|
RETURNING(Link.AllColumns)
|
||||||
|
|
||||||
|
dest := []model.Link{}
|
||||||
|
|
||||||
|
err := deleteStmt.Query(db, &dest)
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `ExecContext` and `QueryContext` to provide context object to execution.
|
||||||
|
|
||||||
|
##### SQL table used for the example:
|
||||||
|
```sql
|
||||||
|
CREATE TABLE IF NOT EXISTS link (
|
||||||
|
id serial PRIMARY KEY,
|
||||||
|
url VARCHAR (255) NOT NULL,
|
||||||
|
name VARCHAR (255) NOT NULL,
|
||||||
|
description VARCHAR (255)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
@ -9,7 +9,9 @@ Following clauses are supported:
|
||||||
- MODEL(model) - list of values for columns will be extracted from model object
|
- MODEL(model) - list of values for columns will be extracted from model object
|
||||||
- MODELS([]model) - list of values for columns will be extracted from list of model objects
|
- MODELS([]model) - list of values for columns will be extracted from list of model objects
|
||||||
- QUERY(select) - select statement that supplies the rows to be inserted.
|
- QUERY(select) - select statement that supplies the rows to be inserted.
|
||||||
- RETURNING(columns...) - list of columns to return as statement result
|
- RETURNING(output_expression...) - An expressions to be computed and returned by the INSERT statement after each row is inserted.
|
||||||
|
The expressions can use any column names of the table. Write _TableName_.AllColumns to return all columns.
|
||||||
|
|
||||||
|
|
||||||
_This list might be extended with feature Jet releases._
|
_This list might be extended with feature Jet releases._
|
||||||
|
|
||||||
|
|
@ -124,7 +126,7 @@ err := insertStmt.Query(db, &dest)
|
||||||
|
|
||||||
Use `ExecContext` and `QueryContext` to provide context object to execution.
|
Use `ExecContext` and `QueryContext` to provide context object to execution.
|
||||||
|
|
||||||
Insert example SQL table:
|
##### SQL table used for the example:
|
||||||
```sql
|
```sql
|
||||||
CREATE TABLE IF NOT EXISTS link (
|
CREATE TABLE IF NOT EXISTS link (
|
||||||
id serial PRIMARY KEY,
|
id serial PRIMARY KEY,
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
UPDATE changes the values of the specified columns in all rows that satisfy the condition.
|
UPDATE changes the values of the specified columns in all rows that satisfy the condition.
|
||||||
More about UPDATE statement in PostgreSQL: https://www.postgresql.org/docs/11/sql-update.html
|
More about UPDATE statement in PostgreSQL: https://www.postgresql.org/docs/11/sql-update.html
|
||||||
|
|
||||||
Following clauses are supported
|
Following clauses are supported:
|
||||||
- UPDATE(columns...) - list of columns to update
|
- UPDATE(columns...) - list of columns to update
|
||||||
- SET(values...) - list of values for columns
|
- SET(values...) - list of values for columns
|
||||||
- MODEL(model) - list of values for columns will be extracted from model object
|
- MODEL(model) - list of values for columns will be extracted from model object
|
||||||
- WHERE(condition) - row condition to update
|
- WHERE(condition) - only rows for which condition returns true will be updated.
|
||||||
- RETURNING(columns...) - list of columns to return as statement result
|
- RETURNING(output_expression...) - An expressions to be computed and returned by the UPDATE statement after each row is updated.
|
||||||
|
The expressions can use any column names of the table. Write _TableName_.AllColumns to return all columns.
|
||||||
|
|
||||||
_This list might be extended with feature Jet releases._
|
_This list might be extended with feature Jet releases._
|
||||||
|
|
||||||
|
|
@ -23,7 +24,7 @@ updateStmt := Link.
|
||||||
Debug sql of above statement:
|
Debug sql of above statement:
|
||||||
```sql
|
```sql
|
||||||
UPDATE test_sample.link -- 'test_sample' is name of the schema
|
UPDATE test_sample.link -- 'test_sample' is name of the schema
|
||||||
SET (name, url) = ('Bong', 'http://bong.com')
|
SET (name, url) = ('Yahoo', 'http://yahoo.com')
|
||||||
WHERE link.name = 'Bing';
|
WHERE link.name = 'Bing';
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -41,8 +42,8 @@ updateStmt := Link.
|
||||||
WHERE(Link.Name.EQ(String("Bing")))
|
WHERE(Link.Name.EQ(String("Bing")))
|
||||||
```
|
```
|
||||||
|
|
||||||
`Link.Name, Link.URL, Link.Description` - can be replaced with Link.MutableColumns. All columns minus primary key columns.
|
`Link.Name, Link.URL, Link.Description` - can be replaced with Link.MutableColumns(all columns minus primary key column).
|
||||||
Primary key columns are not updated usually.
|
Primary key columns usually are not updated.
|
||||||
|
|
||||||
```
|
```
|
||||||
updateStmt := Link.
|
updateStmt := Link.
|
||||||
|
|
@ -75,7 +76,7 @@ err := updateStmt.Query(db, &dest)
|
||||||
|
|
||||||
Use `ExecContext` and `QueryContext` to provide context object to execution.
|
Use `ExecContext` and `QueryContext` to provide context object to execution.
|
||||||
|
|
||||||
Update example SQL table:
|
##### SQL table used for the example:
|
||||||
```sql
|
```sql
|
||||||
CREATE TABLE IF NOT EXISTS link (
|
CREATE TABLE IF NOT EXISTS link (
|
||||||
id serial PRIMARY KEY,
|
id serial PRIMARY KEY,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue