Add RETURNING to Delete statement.

Add DELETE statement wiki page.
This commit is contained in:
go-jet 2019-06-30 17:16:00 +02:00
parent 3d38946eda
commit 5e0e2f2908
10 changed files with 189 additions and 37 deletions

View file

@ -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))

View file

@ -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
} }

View file

@ -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))
}

View file

@ -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
View 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)
}

View file

@ -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
View 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)
);
```

View file

@ -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,

View file

@ -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,