Postgres refactor.
This commit is contained in:
parent
d00167cbba
commit
8519ccbdd0
57 changed files with 2451 additions and 598 deletions
41
postgres/delete_statement.go
Normal file
41
postgres/delete_statement.go
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
package postgres
|
||||
|
||||
import "github.com/go-jet/jet/internal/jet"
|
||||
|
||||
type DeleteStatement interface {
|
||||
jet.Statement
|
||||
|
||||
WHERE(expression BoolExpression) DeleteStatement
|
||||
|
||||
RETURNING(projections ...jet.Projection) DeleteStatement
|
||||
}
|
||||
|
||||
type deleteStatementImpl struct {
|
||||
jet.StatementImpl
|
||||
|
||||
Delete jet.ClauseStatementBegin
|
||||
Where jet.ClauseWhere
|
||||
Returning jet.ClauseReturning
|
||||
}
|
||||
|
||||
func newDeleteStatement(table WritableTable) DeleteStatement {
|
||||
newDelete := &deleteStatementImpl{}
|
||||
newDelete.StatementImpl = jet.NewStatementImpl(Dialect, jet.DeleteStatementType, newDelete, &newDelete.Delete,
|
||||
&newDelete.Where, &newDelete.Returning)
|
||||
|
||||
newDelete.Delete.Name = "DELETE FROM"
|
||||
newDelete.Delete.Tables = append(newDelete.Delete.Tables, table)
|
||||
newDelete.Where.Mandatory = true
|
||||
|
||||
return newDelete
|
||||
}
|
||||
|
||||
func (d *deleteStatementImpl) WHERE(expression BoolExpression) DeleteStatement {
|
||||
d.Where.Condition = expression
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *deleteStatementImpl) RETURNING(projections ...jet.Projection) DeleteStatement {
|
||||
d.Returning.Projections = projections
|
||||
return d
|
||||
}
|
||||
25
postgres/delete_statement_test.go
Normal file
25
postgres/delete_statement_test.go
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
package postgres
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDeleteUnconditionally(t *testing.T) {
|
||||
assertStatementErr(t, table1.DELETE(), `jet: WHERE clause not set`)
|
||||
assertStatementErr(t, table1.DELETE().WHERE(nil), `jet: WHERE clause not set`)
|
||||
}
|
||||
|
||||
func TestDeleteWithWhere(t *testing.T) {
|
||||
assertStatement(t, table1.DELETE().WHERE(table1Col1.EQ(Int(1))), `
|
||||
DELETE FROM db.table1
|
||||
WHERE table1.col1 = $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))
|
||||
}
|
||||
|
|
@ -24,7 +24,7 @@ func NewDialect() jet.Dialect {
|
|||
ArgumentPlaceholder: func(ord int) string {
|
||||
return "$" + strconv.Itoa(ord)
|
||||
},
|
||||
SetClause: postgresSetClause,
|
||||
//SetClause: postgresSetClause,
|
||||
SupportsReturning: true,
|
||||
}
|
||||
|
||||
|
|
@ -59,40 +59,6 @@ func postgresCAST(expressions ...jet.Expression) jet.SerializeFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func postgresSetClause(columns []jet.IColumn, values []jet.Clause, out *jet.SqlBuilder) (err error) {
|
||||
if len(columns) > 1 {
|
||||
out.WriteString("(")
|
||||
}
|
||||
|
||||
err = jet.SerializeColumnNames(columns, out)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(columns) > 1 {
|
||||
out.WriteString(")")
|
||||
}
|
||||
|
||||
out.WriteString("=")
|
||||
|
||||
if len(values) > 1 {
|
||||
out.WriteString("(")
|
||||
}
|
||||
|
||||
err = jet.SerializeClauseList(jet.UpdateStatementType, values, out)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(values) > 1 {
|
||||
out.WriteString(")")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func postgres_REGEXP_LIKE_function(expressions ...jet.Expression) jet.SerializeFunc {
|
||||
return func(statement jet.StatementType, out *jet.SqlBuilder, options ...jet.SerializeOption) error {
|
||||
if len(expressions) < 2 {
|
||||
|
|
|
|||
|
|
@ -50,11 +50,11 @@ var RTRIM = jet.RTRIM
|
|||
var CHR = jet.CHR
|
||||
|
||||
var CONCAT = func(expressions ...Expression) StringExpression {
|
||||
return jet.CONCAT(explicitCasts(expressions...)...)
|
||||
return jet.CONCAT(explicitLiteralCasts(expressions...)...)
|
||||
}
|
||||
|
||||
func CONCAT_WS(expressions ...Expression) StringExpression {
|
||||
return jet.CONCAT_WS(explicitCasts(expressions...)...)
|
||||
return jet.CONCAT_WS(explicitLiteralCasts(expressions...)...)
|
||||
}
|
||||
|
||||
var CONVERT = jet.CONVERT
|
||||
|
|
@ -64,7 +64,7 @@ var ENCODE = jet.ENCODE
|
|||
var DECODE = jet.DECODE
|
||||
|
||||
func FORMAT(formatStr StringExpression, formatArgs ...Expression) StringExpression {
|
||||
return jet.FORMAT(formatStr, explicitCasts(formatArgs...)...)
|
||||
return jet.FORMAT(formatStr, explicitLiteralCasts(formatArgs...)...)
|
||||
}
|
||||
|
||||
var INITCAP = jet.INITCAP
|
||||
|
|
@ -107,17 +107,17 @@ var LEAST = jet.LEAST
|
|||
var EXISTS = jet.EXISTS
|
||||
var CASE = jet.CASE
|
||||
|
||||
func explicitCasts(expressions ...Expression) []jet.Expression {
|
||||
func explicitLiteralCasts(expressions ...Expression) []jet.Expression {
|
||||
ret := []jet.Expression{}
|
||||
|
||||
for _, exp := range expressions {
|
||||
ret = append(ret, explicitCast(exp))
|
||||
ret = append(ret, explicitLiteralCast(exp))
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func explicitCast(expresion Expression) jet.Expression {
|
||||
func explicitLiteralCast(expresion Expression) jet.Expression {
|
||||
if _, ok := expresion.(jet.LiteralExpression); !ok {
|
||||
return expresion
|
||||
}
|
||||
|
|
|
|||
73
postgres/insert_statement.go
Normal file
73
postgres/insert_statement.go
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
package postgres
|
||||
|
||||
import "github.com/go-jet/jet/internal/jet"
|
||||
|
||||
// InsertStatement is interface for SQL INSERT statements
|
||||
type InsertStatement interface {
|
||||
jet.Statement
|
||||
|
||||
// Insert row of values
|
||||
VALUES(value interface{}, values ...interface{}) InsertStatement
|
||||
// Insert row of values, where value for each column is extracted from filed of structure data.
|
||||
// If data is not struct or there is no field for every column selected, this method will panic.
|
||||
MODEL(data interface{}) InsertStatement
|
||||
|
||||
MODELS(data interface{}) InsertStatement
|
||||
|
||||
QUERY(selectStatement SelectStatement) InsertStatement
|
||||
|
||||
RETURNING(projections ...jet.Projection) InsertStatement
|
||||
}
|
||||
|
||||
func newInsertStatement(table WritableTable, columns []jet.IColumn) InsertStatement {
|
||||
newInsert := &insertStatementImpl{}
|
||||
newInsert.StatementImpl = jet.NewStatementImpl(Dialect, jet.DeleteStatementType, newInsert,
|
||||
&newInsert.Insert, &newInsert.Values, &newInsert.Select, &newInsert.Returning)
|
||||
|
||||
newInsert.Insert.Table = table
|
||||
newInsert.Insert.Columns = columns
|
||||
|
||||
return newInsert
|
||||
}
|
||||
|
||||
type insertStatementImpl struct {
|
||||
jet.StatementImpl
|
||||
|
||||
Insert jet.ClauseInsert
|
||||
Values jet.ClauseValues
|
||||
Select jet.ClauseQuery
|
||||
Returning jet.ClauseReturning
|
||||
}
|
||||
|
||||
func (i *insertStatementImpl) VALUES(value interface{}, values ...interface{}) InsertStatement {
|
||||
i.Values.Rows = append(i.Values.Rows, jet.UnwindRowFromValues(value, values))
|
||||
return i
|
||||
}
|
||||
|
||||
func (i *insertStatementImpl) MODEL(data interface{}) InsertStatement {
|
||||
i.Values.Rows = append(i.Values.Rows, jet.UnwindRowFromModel(i.getColumns(), data))
|
||||
return i
|
||||
}
|
||||
|
||||
func (i *insertStatementImpl) MODELS(data interface{}) InsertStatement {
|
||||
i.Values.Rows = append(i.Values.Rows, jet.UnwindRowsFromModels(i.getColumns(), data)...)
|
||||
return i
|
||||
}
|
||||
|
||||
func (i *insertStatementImpl) RETURNING(projections ...jet.Projection) InsertStatement {
|
||||
i.Returning.Projections = projections
|
||||
return i
|
||||
}
|
||||
|
||||
func (i *insertStatementImpl) QUERY(selectStatement SelectStatement) InsertStatement {
|
||||
i.Select.Query = selectStatement
|
||||
return i
|
||||
}
|
||||
|
||||
func (i *insertStatementImpl) getColumns() []jet.IColumn {
|
||||
if len(i.Insert.Columns) > 0 {
|
||||
return i.Insert.Columns
|
||||
}
|
||||
|
||||
return i.Insert.Table.Columns()
|
||||
}
|
||||
148
postgres/insert_statement_test.go
Normal file
148
postgres/insert_statement_test.go
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
package postgres
|
||||
|
||||
import (
|
||||
"gotest.tools/assert"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
//TODO:
|
||||
//func TestInvalidInsert(t *testing.T) {
|
||||
// assertStatementErr(t, table1.INSERT(table1Col1), "jet: no row values or query specified")
|
||||
// assertStatementErr(t, table1.INSERT(nil).VALUES(1), "jet: nil column in columns list")
|
||||
//}
|
||||
|
||||
func TestInsertNilValue(t *testing.T) {
|
||||
assertStatement(t, table1.INSERT(table1Col1).VALUES(nil), `
|
||||
INSERT INTO db.table1 (col1) VALUES
|
||||
($1);
|
||||
`, nil)
|
||||
}
|
||||
|
||||
func TestInsertSingleValue(t *testing.T) {
|
||||
assertStatement(t, table1.INSERT(table1Col1).VALUES(1), `
|
||||
INSERT INTO db.table1 (col1) VALUES
|
||||
($1);
|
||||
`, int(1))
|
||||
}
|
||||
|
||||
func TestInsertWithColumnList(t *testing.T) {
|
||||
columnList := ColumnList(table3ColInt, table3StrCol)
|
||||
|
||||
assertStatement(t, table3.INSERT(columnList).VALUES(1, 3), `
|
||||
INSERT INTO db.table3 (col_int, col2) VALUES
|
||||
($1, $2);
|
||||
`, 1, 3)
|
||||
}
|
||||
|
||||
func TestInsertDate(t *testing.T) {
|
||||
date := time.Date(1999, 1, 2, 3, 4, 5, 0, time.UTC)
|
||||
|
||||
assertStatement(t, table1.INSERT(table1ColTime).VALUES(date), `
|
||||
INSERT INTO db.table1 (col_time) VALUES
|
||||
($1);
|
||||
`, date)
|
||||
}
|
||||
|
||||
func TestInsertMultipleValues(t *testing.T) {
|
||||
assertStatement(t, table1.INSERT(table1Col1, table1ColFloat, table1Col3).VALUES(1, 2, 3), `
|
||||
INSERT INTO db.table1 (col1, col_float, col3) VALUES
|
||||
($1, $2, $3);
|
||||
`, 1, 2, 3)
|
||||
}
|
||||
|
||||
func TestInsertMultipleRows(t *testing.T) {
|
||||
stmt := table1.INSERT(table1Col1, table1ColFloat).
|
||||
VALUES(1, 2).
|
||||
VALUES(11, 22).
|
||||
VALUES(111, 222)
|
||||
|
||||
assertStatement(t, stmt, `
|
||||
INSERT INTO db.table1 (col1, col_float) VALUES
|
||||
($1, $2),
|
||||
($3, $4),
|
||||
($5, $6);
|
||||
`, 1, 2, 11, 22, 111, 222)
|
||||
}
|
||||
|
||||
func TestInsertValuesFromModel(t *testing.T) {
|
||||
type Table1Model struct {
|
||||
Col1 *int
|
||||
ColFloat float64
|
||||
}
|
||||
|
||||
one := 1
|
||||
|
||||
toInsert := Table1Model{
|
||||
Col1: &one,
|
||||
ColFloat: 1.11,
|
||||
}
|
||||
|
||||
stmt := table1.INSERT(table1Col1, table1ColFloat).
|
||||
MODEL(toInsert).
|
||||
MODEL(&toInsert)
|
||||
|
||||
expectedSQL := `
|
||||
INSERT INTO db.table1 (col1, col_float) VALUES
|
||||
($1, $2),
|
||||
($3, $4);
|
||||
`
|
||||
|
||||
assertStatement(t, stmt, expectedSQL, int(1), float64(1.11), int(1), float64(1.11))
|
||||
}
|
||||
|
||||
func TestInsertValuesFromModelColumnMismatch(t *testing.T) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
assert.Equal(t, r, "missing struct field for column : col1")
|
||||
}()
|
||||
type Table1Model struct {
|
||||
Col1Prim int
|
||||
Col2 string
|
||||
}
|
||||
|
||||
newData := Table1Model{
|
||||
Col1Prim: 1,
|
||||
Col2: "one",
|
||||
}
|
||||
|
||||
table1.
|
||||
INSERT(table1Col1, table1ColFloat).
|
||||
MODEL(newData)
|
||||
}
|
||||
|
||||
func TestInsertFromNonStructModel(t *testing.T) {
|
||||
|
||||
defer func() {
|
||||
r := recover()
|
||||
assert.Equal(t, r, "argument mismatch: expected struct, got []int")
|
||||
}()
|
||||
|
||||
table2.INSERT(table2ColInt).MODEL([]int{})
|
||||
}
|
||||
|
||||
func TestInsertQuery(t *testing.T) {
|
||||
|
||||
stmt := table1.INSERT(table1Col1).
|
||||
QUERY(table1.SELECT(table1Col1))
|
||||
|
||||
var expectedSQL = `
|
||||
INSERT INTO db.table1 (col1) (
|
||||
SELECT table1.col1 AS "table1.col1"
|
||||
FROM db.table1
|
||||
);
|
||||
`
|
||||
assertStatement(t, stmt, expectedSQL)
|
||||
}
|
||||
|
||||
func TestInsertDefaultValue(t *testing.T) {
|
||||
stmt := table1.INSERT(table1Col1, table1ColFloat).
|
||||
VALUES(DEFAULT, "two")
|
||||
|
||||
var expectedSQL = `
|
||||
INSERT INTO db.table1 (col1, col_float) VALUES
|
||||
(DEFAULT, $1);
|
||||
`
|
||||
|
||||
assertStatement(t, stmt, expectedSQL, "two")
|
||||
}
|
||||
|
|
@ -2,20 +2,52 @@ package postgres
|
|||
|
||||
import "github.com/go-jet/jet/internal/jet"
|
||||
|
||||
type TableLockMode jet.TableLockMode
|
||||
type TableLockMode string
|
||||
|
||||
// Lock types for LockStatement.
|
||||
const (
|
||||
LOCK_ACCESS_SHARE = "ACCESS SHARE"
|
||||
LOCK_ROW_SHARE = "ROW SHARE"
|
||||
LOCK_ROW_EXCLUSIVE = "ROW EXCLUSIVE"
|
||||
LOCK_SHARE_UPDATE_EXCLUSIVE = "SHARE UPDATE EXCLUSIVE"
|
||||
LOCK_SHARE = "SHARE"
|
||||
LOCK_SHARE_ROW_EXCLUSIVE = "SHARE ROW EXCLUSIVE"
|
||||
LOCK_EXCLUSIVE = "EXCLUSIVE"
|
||||
LOCK_ACCESS_EXCLUSIVE = "ACCESS EXCLUSIVE"
|
||||
LOCK_ACCESS_SHARE TableLockMode = "ACCESS SHARE"
|
||||
LOCK_ROW_SHARE TableLockMode = "ROW SHARE"
|
||||
LOCK_ROW_EXCLUSIVE TableLockMode = "ROW EXCLUSIVE"
|
||||
LOCK_SHARE_UPDATE_EXCLUSIVE TableLockMode = "SHARE UPDATE EXCLUSIVE"
|
||||
LOCK_SHARE TableLockMode = "SHARE"
|
||||
LOCK_SHARE_ROW_EXCLUSIVE TableLockMode = "SHARE ROW EXCLUSIVE"
|
||||
LOCK_EXCLUSIVE TableLockMode = "EXCLUSIVE"
|
||||
LOCK_ACCESS_EXCLUSIVE TableLockMode = "ACCESS EXCLUSIVE"
|
||||
)
|
||||
|
||||
type LockStatement jet.LockStatement
|
||||
type LockStatement interface {
|
||||
jet.Statement
|
||||
|
||||
var LOCK = jet.LOCK
|
||||
IN(lockMode TableLockMode) LockStatement
|
||||
NOWAIT() LockStatement
|
||||
}
|
||||
|
||||
func LOCK(tables ...jet.SerializerTable) LockStatement {
|
||||
newLock := &lockStatementImpl{}
|
||||
newLock.StatementImpl = jet.NewStatementImpl(Dialect, jet.DeleteStatementType, newLock,
|
||||
&newLock.StatementBegin, &newLock.In, &newLock.NoWait)
|
||||
|
||||
newLock.StatementBegin.Name = "LOCK TABLE"
|
||||
newLock.StatementBegin.Tables = tables
|
||||
newLock.NoWait.Name = "NOWAIT"
|
||||
return newLock
|
||||
}
|
||||
|
||||
type lockStatementImpl struct {
|
||||
jet.StatementImpl
|
||||
|
||||
StatementBegin jet.ClauseStatementBegin
|
||||
In jet.ClauseIn
|
||||
NoWait jet.ClauseOptional
|
||||
}
|
||||
|
||||
func (l *lockStatementImpl) IN(lockMode TableLockMode) LockStatement {
|
||||
l.In.LockMode = string(lockMode)
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *lockStatementImpl) NOWAIT() LockStatement {
|
||||
l.NoWait.Show = true
|
||||
return l
|
||||
}
|
||||
|
|
|
|||
32
postgres/lock_statement_test.go
Normal file
32
postgres/lock_statement_test.go
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
package postgres
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLockTable(t *testing.T) {
|
||||
assertStatement(t, table1.LOCK().IN(LOCK_ACCESS_SHARE), `
|
||||
LOCK TABLE db.table1 IN ACCESS SHARE MODE;
|
||||
`)
|
||||
assertStatement(t, table1.LOCK().IN(LOCK_ROW_SHARE), `
|
||||
LOCK TABLE db.table1 IN ROW SHARE MODE;
|
||||
`)
|
||||
assertStatement(t, table1.LOCK().IN(LOCK_ROW_EXCLUSIVE), `
|
||||
LOCK TABLE db.table1 IN ROW EXCLUSIVE MODE;
|
||||
`)
|
||||
assertStatement(t, table1.LOCK().IN(LOCK_SHARE_UPDATE_EXCLUSIVE), `
|
||||
LOCK TABLE db.table1 IN SHARE UPDATE EXCLUSIVE MODE;
|
||||
`)
|
||||
assertStatement(t, table1.LOCK().IN(LOCK_SHARE), `
|
||||
LOCK TABLE db.table1 IN SHARE MODE;
|
||||
`)
|
||||
assertStatement(t, table1.LOCK().IN(LOCK_SHARE_ROW_EXCLUSIVE), `
|
||||
LOCK TABLE db.table1 IN SHARE ROW EXCLUSIVE MODE;
|
||||
`)
|
||||
assertStatement(t, table1.LOCK().IN(LOCK_EXCLUSIVE), `
|
||||
LOCK TABLE db.table1 IN EXCLUSIVE MODE;
|
||||
`)
|
||||
assertStatement(t, table1.LOCK().IN(LOCK_ACCESS_EXCLUSIVE).NOWAIT(), `
|
||||
LOCK TABLE db.table1 IN ACCESS EXCLUSIVE MODE NOWAIT;
|
||||
`)
|
||||
}
|
||||
144
postgres/select_statement.go
Normal file
144
postgres/select_statement.go
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
package postgres
|
||||
|
||||
import "github.com/go-jet/jet/internal/jet"
|
||||
|
||||
type SelectLock = jet.SelectLock
|
||||
|
||||
var (
|
||||
UPDATE = jet.NewSelectLock("UPDATE")
|
||||
NO_KEY_UPDATE = jet.NewSelectLock("NO KEY UPDATE")
|
||||
SHARE = jet.NewSelectLock("SHARE")
|
||||
KEY_SHARE = jet.NewSelectLock("KEY SHARE")
|
||||
)
|
||||
|
||||
type SelectStatement interface {
|
||||
jet.Statement
|
||||
jet.HasProjections
|
||||
jet.IExpression
|
||||
|
||||
DISTINCT() SelectStatement
|
||||
FROM(table ReadableTable) SelectStatement
|
||||
WHERE(expression BoolExpression) SelectStatement
|
||||
GROUP_BY(groupByClauses ...jet.GroupByClause) SelectStatement
|
||||
HAVING(boolExpression BoolExpression) SelectStatement
|
||||
ORDER_BY(orderByClauses ...jet.OrderByClause) SelectStatement
|
||||
LIMIT(limit int64) SelectStatement
|
||||
OFFSET(offset int64) SelectStatement
|
||||
FOR(lock SelectLock) SelectStatement
|
||||
|
||||
UNION(rhs SelectStatement) SetStatement
|
||||
UNION_ALL(rhs SelectStatement) SetStatement
|
||||
INTERSECT(rhs SelectStatement) SetStatement
|
||||
INTERSECT_ALL(rhs SelectStatement) SetStatement
|
||||
EXCEPT(rhs SelectStatement) SetStatement
|
||||
EXCEPT_ALL(rhs SelectStatement) SetStatement
|
||||
|
||||
AsTable(alias string) SelectTable
|
||||
}
|
||||
|
||||
//SELECT creates new SelectStatement with list of projections
|
||||
func SELECT(projection jet.Projection, projections ...jet.Projection) SelectStatement {
|
||||
return newSelectStatement(nil, append([]jet.Projection{projection}, projections...))
|
||||
}
|
||||
|
||||
func newSelectStatement(table ReadableTable, projections []jet.Projection) SelectStatement {
|
||||
newSelect := &selectStatementImpl{}
|
||||
newSelect.ExpressionStatementImpl.StatementImpl = jet.NewStatementImpl(Dialect, jet.SelectStatementType, newSelect, &newSelect.Select,
|
||||
&newSelect.From, &newSelect.Where, &newSelect.GroupBy, &newSelect.Having, &newSelect.OrderBy,
|
||||
&newSelect.Limit, &newSelect.Offset, &newSelect.For)
|
||||
|
||||
newSelect.ExpressionStatementImpl.ExpressionInterfaceImpl.Parent = newSelect
|
||||
|
||||
newSelect.Select.Projections = projections
|
||||
newSelect.From.Table = table
|
||||
newSelect.Limit.Count = -1
|
||||
newSelect.Offset.Count = -1
|
||||
|
||||
newSelect.setOperatorsImpl.parent = newSelect
|
||||
|
||||
return newSelect
|
||||
}
|
||||
|
||||
type selectStatementImpl struct {
|
||||
jet.ExpressionStatementImpl
|
||||
setOperatorsImpl
|
||||
|
||||
Select jet.ClauseSelect
|
||||
From jet.ClauseFrom
|
||||
Where jet.ClauseWhere
|
||||
GroupBy jet.ClauseGroupBy
|
||||
Having jet.ClauseHaving
|
||||
OrderBy jet.ClauseOrderBy
|
||||
Limit jet.ClauseLimit
|
||||
Offset jet.ClauseOffset
|
||||
For jet.ClauseFor
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) DISTINCT() SelectStatement {
|
||||
s.Select.Distinct = true
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) FROM(table ReadableTable) SelectStatement {
|
||||
s.From.Table = table
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) WHERE(condition BoolExpression) SelectStatement {
|
||||
s.Where.Condition = condition
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) GROUP_BY(groupByClauses ...jet.GroupByClause) SelectStatement {
|
||||
s.GroupBy.List = groupByClauses
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) HAVING(boolExpression BoolExpression) SelectStatement {
|
||||
s.Having.Condition = boolExpression
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) ORDER_BY(orderByClauses ...jet.OrderByClause) SelectStatement {
|
||||
s.OrderBy.List = orderByClauses
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) LIMIT(limit int64) SelectStatement {
|
||||
s.Limit.Count = limit
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) OFFSET(offset int64) SelectStatement {
|
||||
s.Offset.Count = offset
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) FOR(lock SelectLock) SelectStatement {
|
||||
s.For.Lock = lock
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *selectStatementImpl) AsTable(alias string) SelectTable {
|
||||
return newSelectTable(s, alias)
|
||||
}
|
||||
|
||||
type SelectTable interface {
|
||||
ReadableTable
|
||||
jet.SelectTable
|
||||
}
|
||||
|
||||
type selectTableImpl struct {
|
||||
jet.SelectTableImpl2
|
||||
readableTableInterfaceImpl
|
||||
}
|
||||
|
||||
func newSelectTable(selectStmt jet.StatementWithProjections, alias string) SelectTable {
|
||||
subQuery := &selectTableImpl{
|
||||
SelectTableImpl2: jet.NewSelectTable(selectStmt, alias),
|
||||
}
|
||||
|
||||
subQuery.readableTableInterfaceImpl.parent = subQuery
|
||||
|
||||
return subQuery
|
||||
}
|
||||
137
postgres/select_statement_test.go
Normal file
137
postgres/select_statement_test.go
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
package postgres
|
||||
|
||||
import (
|
||||
"github.com/go-jet/jet/internal/testutils"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestInvalidSelect(t *testing.T) {
|
||||
assertStatementErr(t, SELECT(nil), "jet: Projection is nil")
|
||||
}
|
||||
|
||||
func TestSelectColumnList(t *testing.T) {
|
||||
columnList := ColumnList(table2ColInt, table2ColFloat, table3ColInt)
|
||||
|
||||
assertStatement(t, SELECT(columnList).FROM(table2), `
|
||||
SELECT table2.col_int AS "table2.col_int",
|
||||
table2.col_float AS "table2.col_float",
|
||||
table3.col_int AS "table3.col_int"
|
||||
FROM db.table2;
|
||||
`)
|
||||
}
|
||||
|
||||
func TestSelectLiterals(t *testing.T) {
|
||||
assertStatement(t, SELECT(Int(1), Float(2.2), Bool(false)).FROM(table1), `
|
||||
SELECT $1,
|
||||
$2,
|
||||
$3
|
||||
FROM db.table1;
|
||||
`, int64(1), 2.2, false)
|
||||
}
|
||||
|
||||
func TestSelectDistinct(t *testing.T) {
|
||||
assertStatement(t, SELECT(table1ColBool).DISTINCT().FROM(table1), `
|
||||
SELECT DISTINCT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1;
|
||||
`)
|
||||
}
|
||||
|
||||
func TestSelectFrom(t *testing.T) {
|
||||
assertStatement(t, SELECT(table1ColInt, table2ColFloat).FROM(table1), `
|
||||
SELECT table1.col_int AS "table1.col_int",
|
||||
table2.col_float AS "table2.col_float"
|
||||
FROM db.table1;
|
||||
`)
|
||||
assertStatement(t, SELECT(table1ColInt, table2ColFloat).FROM(table1.INNER_JOIN(table2, table1ColInt.EQ(table2ColInt))), `
|
||||
SELECT table1.col_int AS "table1.col_int",
|
||||
table2.col_float AS "table2.col_float"
|
||||
FROM db.table1
|
||||
INNER JOIN db.table2 ON (table1.col_int = table2.col_int);
|
||||
`)
|
||||
assertStatement(t, table1.INNER_JOIN(table2, table1ColInt.EQ(table2ColInt)).SELECT(table1ColInt, table2ColFloat), `
|
||||
SELECT table1.col_int AS "table1.col_int",
|
||||
table2.col_float AS "table2.col_float"
|
||||
FROM db.table1
|
||||
INNER JOIN db.table2 ON (table1.col_int = table2.col_int);
|
||||
`)
|
||||
}
|
||||
|
||||
func TestSelectWhere(t *testing.T) {
|
||||
assertStatement(t, SELECT(table1ColInt).FROM(table1).WHERE(Bool(true)), `
|
||||
SELECT table1.col_int AS "table1.col_int"
|
||||
FROM db.table1
|
||||
WHERE $1;
|
||||
`, true)
|
||||
assertStatement(t, SELECT(table1ColInt).FROM(table1).WHERE(table1ColInt.GT_EQ(Int(10))), `
|
||||
SELECT table1.col_int AS "table1.col_int"
|
||||
FROM db.table1
|
||||
WHERE table1.col_int >= $1;
|
||||
`, int64(10))
|
||||
}
|
||||
|
||||
func TestSelectGroupBy(t *testing.T) {
|
||||
assertStatement(t, SELECT(table2ColInt).FROM(table2).GROUP_BY(table2ColFloat), `
|
||||
SELECT table2.col_int AS "table2.col_int"
|
||||
FROM db.table2
|
||||
GROUP BY table2.col_float;
|
||||
`)
|
||||
}
|
||||
|
||||
func TestSelectHaving(t *testing.T) {
|
||||
assertStatement(t, SELECT(table3ColInt).FROM(table3).HAVING(table1ColBool.EQ(Bool(true))), `
|
||||
SELECT table3.col_int AS "table3.col_int"
|
||||
FROM db.table3
|
||||
HAVING table1.col_bool = $1;
|
||||
`, true)
|
||||
}
|
||||
|
||||
func TestSelectOrderBy(t *testing.T) {
|
||||
assertStatement(t, SELECT(table2ColFloat).FROM(table2).ORDER_BY(table2ColInt.DESC()), `
|
||||
SELECT table2.col_float AS "table2.col_float"
|
||||
FROM db.table2
|
||||
ORDER BY table2.col_int DESC;
|
||||
`)
|
||||
assertStatement(t, SELECT(table2ColFloat).FROM(table2).ORDER_BY(table2ColInt.DESC(), table2ColInt.ASC()), `
|
||||
SELECT table2.col_float AS "table2.col_float"
|
||||
FROM db.table2
|
||||
ORDER BY table2.col_int DESC, table2.col_int ASC;
|
||||
`)
|
||||
}
|
||||
|
||||
func TestSelectLimitOffset(t *testing.T) {
|
||||
assertStatement(t, SELECT(table2ColInt).FROM(table2).LIMIT(10), `
|
||||
SELECT table2.col_int AS "table2.col_int"
|
||||
FROM db.table2
|
||||
LIMIT $1;
|
||||
`, int64(10))
|
||||
assertStatement(t, SELECT(table2ColInt).FROM(table2).LIMIT(10).OFFSET(2), `
|
||||
SELECT table2.col_int AS "table2.col_int"
|
||||
FROM db.table2
|
||||
LIMIT $1
|
||||
OFFSET $2;
|
||||
`, int64(10), int64(2))
|
||||
}
|
||||
|
||||
func TestSelectLock(t *testing.T) {
|
||||
testutils.AssertStatementSql(t, SELECT(table1ColBool).FROM(table1).FOR(UPDATE()), `
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
FOR UPDATE;
|
||||
`)
|
||||
testutils.AssertStatementSql(t, SELECT(table1ColBool).FROM(table1).FOR(SHARE().NOWAIT()), `
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
FOR SHARE NOWAIT;
|
||||
`)
|
||||
|
||||
testutils.AssertStatementSql(t, SELECT(table1ColBool).FROM(table1).FOR(KEY_SHARE().NOWAIT()), `
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
FOR KEY SHARE NOWAIT;
|
||||
`)
|
||||
testutils.AssertStatementSql(t, SELECT(table1ColBool).FROM(table1).FOR(NO_KEY_UPDATE().SKIP_LOCKED()), `
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
FOR NO KEY UPDATE SKIP LOCKED;
|
||||
`)
|
||||
}
|
||||
147
postgres/set_statement.go
Normal file
147
postgres/set_statement.go
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
package postgres
|
||||
|
||||
import "github.com/go-jet/jet/internal/jet"
|
||||
|
||||
// UNION effectively appends the result of sub-queries(select statements) into single query.
|
||||
// It eliminates duplicate rows from its result.
|
||||
func UNION(lhs, rhs jet.StatementWithProjections, selects ...jet.StatementWithProjections) SetStatement {
|
||||
return newSetStatementImpl(Union, false, toSelectList(lhs, rhs, selects...))
|
||||
}
|
||||
|
||||
// UNION_ALL effectively appends the result of sub-queries(select statements) into single query.
|
||||
// It does not eliminates duplicate rows from its result.
|
||||
func UNION_ALL(lhs, rhs jet.StatementWithProjections, selects ...jet.StatementWithProjections) SetStatement {
|
||||
return newSetStatementImpl(Union, true, toSelectList(lhs, rhs, selects...))
|
||||
}
|
||||
|
||||
// INTERSECT returns all rows that are in query results.
|
||||
// It eliminates duplicate rows from its result.
|
||||
func INTERSECT(lhs, rhs jet.StatementWithProjections, selects ...jet.StatementWithProjections) SetStatement {
|
||||
return newSetStatementImpl(Intersect, false, toSelectList(lhs, rhs, selects...))
|
||||
}
|
||||
|
||||
// INTERSECT_ALL returns all rows that are in query results.
|
||||
// It does not eliminates duplicate rows from its result.
|
||||
func INTERSECT_ALL(lhs, rhs jet.StatementWithProjections, selects ...jet.StatementWithProjections) SetStatement {
|
||||
return newSetStatementImpl(Intersect, true, toSelectList(lhs, rhs, selects...))
|
||||
}
|
||||
|
||||
// EXCEPT returns all rows that are in the result of query lhs but not in the result of query rhs.
|
||||
// It eliminates duplicate rows from its result.
|
||||
func EXCEPT(lhs, rhs jet.StatementWithProjections) SetStatement {
|
||||
return newSetStatementImpl(Except, false, toSelectList(lhs, rhs))
|
||||
}
|
||||
|
||||
// EXCEPT_ALL returns all rows that are in the result of query lhs but not in the result of query rhs.
|
||||
// It does not eliminates duplicate rows from its result.
|
||||
func EXCEPT_ALL(lhs, rhs jet.StatementWithProjections) SetStatement {
|
||||
return newSetStatementImpl(Except, true, toSelectList(lhs, rhs))
|
||||
}
|
||||
|
||||
type SetStatement interface {
|
||||
SetOperators
|
||||
|
||||
ORDER_BY(orderByClauses ...jet.OrderByClause) SetStatement
|
||||
|
||||
LIMIT(limit int64) SetStatement
|
||||
OFFSET(offset int64) SetStatement
|
||||
|
||||
AsTable(alias string) SelectTable
|
||||
}
|
||||
|
||||
type SetOperators interface {
|
||||
jet.Statement
|
||||
jet.HasProjections
|
||||
jet.IExpression
|
||||
|
||||
UNION(rhs SelectStatement) SetStatement
|
||||
UNION_ALL(rhs SelectStatement) SetStatement
|
||||
INTERSECT(rhs SelectStatement) SetStatement
|
||||
INTERSECT_ALL(rhs SelectStatement) SetStatement
|
||||
EXCEPT(rhs SelectStatement) SetStatement
|
||||
EXCEPT_ALL(rhs SelectStatement) SetStatement
|
||||
}
|
||||
|
||||
type setOperatorsImpl struct {
|
||||
parent SetOperators
|
||||
}
|
||||
|
||||
func (s *setOperatorsImpl) UNION(rhs SelectStatement) SetStatement {
|
||||
return UNION(s.parent, rhs)
|
||||
}
|
||||
|
||||
func (s *setOperatorsImpl) UNION_ALL(rhs SelectStatement) SetStatement {
|
||||
return UNION_ALL(s.parent, rhs)
|
||||
}
|
||||
|
||||
func (s *setOperatorsImpl) INTERSECT(rhs SelectStatement) SetStatement {
|
||||
return INTERSECT(s.parent, rhs)
|
||||
}
|
||||
|
||||
func (s *setOperatorsImpl) INTERSECT_ALL(rhs SelectStatement) SetStatement {
|
||||
return INTERSECT_ALL(s.parent, rhs)
|
||||
}
|
||||
|
||||
func (s *setOperatorsImpl) EXCEPT(rhs SelectStatement) SetStatement {
|
||||
return EXCEPT(s.parent, rhs)
|
||||
}
|
||||
|
||||
func (s *setOperatorsImpl) EXCEPT_ALL(rhs SelectStatement) SetStatement {
|
||||
return EXCEPT_ALL(s.parent, rhs)
|
||||
}
|
||||
|
||||
type setStatementImpl struct {
|
||||
jet.ExpressionStatementImpl
|
||||
|
||||
setOperatorsImpl
|
||||
|
||||
setOperator jet.ClauseSetStmtOperator
|
||||
}
|
||||
|
||||
func newSetStatementImpl(operator string, all bool, selects []jet.StatementWithProjections) SetStatement {
|
||||
newSetStatement := &setStatementImpl{}
|
||||
newSetStatement.ExpressionStatementImpl.StatementImpl = jet.NewStatementImpl(Dialect, jet.SetStatementType, newSetStatement,
|
||||
&newSetStatement.setOperator)
|
||||
newSetStatement.ExpressionStatementImpl.ExpressionInterfaceImpl.Parent = newSetStatement
|
||||
|
||||
newSetStatement.setOperator.Operator = operator
|
||||
newSetStatement.setOperator.All = all
|
||||
newSetStatement.setOperator.Selects = selects
|
||||
newSetStatement.setOperator.Limit.Count = -1
|
||||
newSetStatement.setOperator.Offset.Count = -1
|
||||
|
||||
newSetStatement.setOperatorsImpl.parent = newSetStatement
|
||||
|
||||
newSetStatement.Clauses = []jet.Clause{&newSetStatement.setOperator}
|
||||
|
||||
return newSetStatement
|
||||
}
|
||||
|
||||
func (s *setStatementImpl) ORDER_BY(orderByClauses ...jet.OrderByClause) SetStatement {
|
||||
s.setOperator.OrderBy.List = orderByClauses
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *setStatementImpl) LIMIT(limit int64) SetStatement {
|
||||
s.setOperator.Limit.Count = limit
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *setStatementImpl) OFFSET(offset int64) SetStatement {
|
||||
s.setOperator.Offset.Count = offset
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *setStatementImpl) AsTable(alias string) SelectTable {
|
||||
return newSelectTable(s, alias)
|
||||
}
|
||||
|
||||
const (
|
||||
Union = "UNION"
|
||||
Intersect = "INTERSECT"
|
||||
Except = "EXCEPT"
|
||||
)
|
||||
|
||||
func toSelectList(lhs, rhs jet.StatementWithProjections, selects ...jet.StatementWithProjections) []jet.StatementWithProjections {
|
||||
return append([]jet.StatementWithProjections{lhs, rhs}, selects...)
|
||||
}
|
||||
81
postgres/set_statement_test.go
Normal file
81
postgres/set_statement_test.go
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
package postgres
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSelectSets(t *testing.T) {
|
||||
select1 := SELECT(table1ColBool).FROM(table1)
|
||||
select2 := SELECT(table2ColBool).FROM(table2)
|
||||
|
||||
assertStatement(t, select1.UNION(select2), `
|
||||
(
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
)
|
||||
UNION
|
||||
(
|
||||
SELECT table2.col_bool AS "table2.col_bool"
|
||||
FROM db.table2
|
||||
);
|
||||
`)
|
||||
assertStatement(t, select1.UNION_ALL(select2), `
|
||||
(
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
)
|
||||
UNION ALL
|
||||
(
|
||||
SELECT table2.col_bool AS "table2.col_bool"
|
||||
FROM db.table2
|
||||
);
|
||||
`)
|
||||
|
||||
assertStatement(t, select1.INTERSECT(select2), `
|
||||
(
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
)
|
||||
INTERSECT
|
||||
(
|
||||
SELECT table2.col_bool AS "table2.col_bool"
|
||||
FROM db.table2
|
||||
);
|
||||
`)
|
||||
|
||||
assertStatement(t, select1.INTERSECT_ALL(select2), `
|
||||
(
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
)
|
||||
INTERSECT ALL
|
||||
(
|
||||
SELECT table2.col_bool AS "table2.col_bool"
|
||||
FROM db.table2
|
||||
);
|
||||
`)
|
||||
assertStatement(t, select1.EXCEPT(select2), `
|
||||
(
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
)
|
||||
EXCEPT
|
||||
(
|
||||
SELECT table2.col_bool AS "table2.col_bool"
|
||||
FROM db.table2
|
||||
);
|
||||
`)
|
||||
|
||||
assertStatement(t, select1.EXCEPT_ALL(select2), `
|
||||
(
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
)
|
||||
EXCEPT ALL
|
||||
(
|
||||
SELECT table2.col_bool AS "table2.col_bool"
|
||||
FROM db.table2
|
||||
);
|
||||
`)
|
||||
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
package postgres
|
||||
|
||||
import "github.com/go-jet/jet/internal/jet"
|
||||
|
||||
type SelectStatement jet.SelectStatement
|
||||
type SelectTable jet.SelectTable
|
||||
type SelectLock jet.SelectLock
|
||||
|
||||
var (
|
||||
UPDATE = jet.NewSelectLock("UPDATE")
|
||||
NO_KEY_UPDATE = jet.NewSelectLock("NO KEY UPDATE")
|
||||
SHARE = jet.NewSelectLock("SHARE")
|
||||
KEY_SHARE = jet.NewSelectLock("KEY SHARE")
|
||||
)
|
||||
|
||||
var SELECT = jet.SELECT
|
||||
|
||||
func UNION(lhs, rhs SelectStatement, selects ...SelectStatement) SelectStatement {
|
||||
return jet.UNION(lhs, rhs, toJetSelects(selects...)...)
|
||||
}
|
||||
|
||||
func UNION_ALL(lhs, rhs SelectStatement, selects ...SelectStatement) SelectStatement {
|
||||
return jet.UNION_ALL(lhs, rhs, toJetSelects(selects...)...)
|
||||
}
|
||||
|
||||
func INTERSECT(lhs, rhs SelectStatement, selects ...SelectStatement) SelectStatement {
|
||||
return jet.INTERSECT(lhs, rhs, toJetSelects(selects...)...)
|
||||
}
|
||||
|
||||
func INTERSECT_ALL(lhs, rhs SelectStatement, selects ...SelectStatement) SelectStatement {
|
||||
return jet.INTERSECT_ALL(lhs, rhs, toJetSelects(selects...)...)
|
||||
}
|
||||
|
||||
func toJetSelects(selects ...SelectStatement) []jet.SelectStatement {
|
||||
ret := []jet.SelectStatement{}
|
||||
|
||||
for _, sel := range selects {
|
||||
ret = append(ret, sel)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
package postgres
|
||||
|
||||
import (
|
||||
"github.com/go-jet/jet/internal/testutils"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSelectLock(t *testing.T) {
|
||||
testutils.AssertStatementSql(t, SELECT(table1ColBool).FROM(table1).FOR(UPDATE()), `
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
FOR UPDATE;
|
||||
`)
|
||||
testutils.AssertStatementSql(t, SELECT(table1ColBool).FROM(table1).FOR(SHARE().NOWAIT()), `
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
FOR SHARE NOWAIT;
|
||||
`)
|
||||
|
||||
testutils.AssertStatementSql(t, SELECT(table1ColBool).FROM(table1).FOR(KEY_SHARE().NOWAIT()), `
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
FOR KEY SHARE NOWAIT;
|
||||
`)
|
||||
testutils.AssertStatementSql(t, SELECT(table1ColBool).FROM(table1).FOR(NO_KEY_UPDATE().SKIP_LOCKED()), `
|
||||
SELECT table1.col_bool AS "table1.col_bool"
|
||||
FROM db.table1
|
||||
FOR NO KEY UPDATE SKIP LOCKED;
|
||||
`)
|
||||
}
|
||||
|
|
@ -2,8 +2,145 @@ package postgres
|
|||
|
||||
import "github.com/go-jet/jet/internal/jet"
|
||||
|
||||
type Table jet.Table
|
||||
type readableTable interface {
|
||||
// Generates a select query on the current tableName.
|
||||
SELECT(projection jet.Projection, projections ...jet.Projection) SelectStatement
|
||||
|
||||
// Creates a inner join tableName Expression using onCondition.
|
||||
INNER_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable
|
||||
|
||||
// Creates a left join tableName Expression using onCondition.
|
||||
LEFT_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable
|
||||
|
||||
// Creates a right join tableName Expression using onCondition.
|
||||
RIGHT_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable
|
||||
|
||||
// Creates a full join tableName Expression using onCondition.
|
||||
FULL_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable
|
||||
|
||||
// Creates a cross join tableName Expression using onCondition.
|
||||
CROSS_JOIN(table ReadableTable) ReadableTable
|
||||
}
|
||||
|
||||
type writableTable interface {
|
||||
INSERT(columns ...jet.IColumn) InsertStatement
|
||||
UPDATE(column jet.IColumn, columns ...jet.IColumn) UpdateStatement
|
||||
DELETE() DeleteStatement
|
||||
LOCK() LockStatement
|
||||
}
|
||||
|
||||
// ReadableTable interface
|
||||
type ReadableTable interface {
|
||||
//table
|
||||
readableTable
|
||||
jet.Serializer
|
||||
//acceptsVisitor
|
||||
}
|
||||
|
||||
type WritableTable interface {
|
||||
jet.TableInterface
|
||||
writableTable
|
||||
jet.Serializer
|
||||
}
|
||||
|
||||
type Table interface {
|
||||
//table
|
||||
readableTable
|
||||
writableTable
|
||||
jet.Serializer
|
||||
//acceptsVisitor
|
||||
|
||||
SchemaName() string
|
||||
TableName() string
|
||||
AS(alias string)
|
||||
}
|
||||
|
||||
type readableTableInterfaceImpl struct {
|
||||
parent ReadableTable
|
||||
}
|
||||
|
||||
// Generates a select query on the current tableName.
|
||||
func (r *readableTableInterfaceImpl) SELECT(projection1 jet.Projection, projections ...jet.Projection) SelectStatement {
|
||||
return newSelectStatement(r.parent, append([]jet.Projection{projection1}, projections...))
|
||||
}
|
||||
|
||||
// Creates a inner join tableName Expression using onCondition.
|
||||
func (r *readableTableInterfaceImpl) INNER_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable {
|
||||
return newJoinTable(r.parent, table, jet.InnerJoin, onCondition)
|
||||
}
|
||||
|
||||
// Creates a left join tableName Expression using onCondition.
|
||||
func (r *readableTableInterfaceImpl) LEFT_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable {
|
||||
return newJoinTable(r.parent, table, jet.LeftJoin, onCondition)
|
||||
}
|
||||
|
||||
// Creates a right join tableName Expression using onCondition.
|
||||
func (r *readableTableInterfaceImpl) RIGHT_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable {
|
||||
return newJoinTable(r.parent, table, jet.RightJoin, onCondition)
|
||||
}
|
||||
|
||||
func (r *readableTableInterfaceImpl) FULL_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable {
|
||||
return newJoinTable(r.parent, table, jet.FullJoin, onCondition)
|
||||
}
|
||||
|
||||
func (r *readableTableInterfaceImpl) CROSS_JOIN(table ReadableTable) ReadableTable {
|
||||
return newJoinTable(r.parent, table, jet.CrossJoin, nil)
|
||||
}
|
||||
|
||||
type writableTableInterfaceImpl struct {
|
||||
parent WritableTable
|
||||
}
|
||||
|
||||
func (w *writableTableInterfaceImpl) INSERT(columns ...jet.IColumn) InsertStatement {
|
||||
return newInsertStatement(w.parent, jet.UnwidColumnList(columns))
|
||||
}
|
||||
|
||||
func (w *writableTableInterfaceImpl) UPDATE(column jet.IColumn, columns ...jet.IColumn) UpdateStatement {
|
||||
return newUpdateStatement(w.parent, jet.UnwindColumns(column, columns...))
|
||||
}
|
||||
|
||||
func (w *writableTableInterfaceImpl) DELETE() DeleteStatement {
|
||||
return newDeleteStatement(w.parent)
|
||||
}
|
||||
|
||||
func (w *writableTableInterfaceImpl) LOCK() LockStatement {
|
||||
return LOCK(w.parent)
|
||||
}
|
||||
|
||||
type table2Impl struct {
|
||||
readableTableInterfaceImpl
|
||||
writableTableInterfaceImpl
|
||||
|
||||
jet.TableImpl2
|
||||
}
|
||||
|
||||
func NewTable(schemaName, name string, columns ...jet.Column) Table {
|
||||
return jet.NewTable(Dialect, schemaName, name, columns...)
|
||||
|
||||
t := &table2Impl{
|
||||
TableImpl2: jet.NewTable2(Dialect, schemaName, name, columns...),
|
||||
}
|
||||
|
||||
for _, c := range columns {
|
||||
c.SetTableName(name)
|
||||
}
|
||||
|
||||
t.readableTableInterfaceImpl.parent = t
|
||||
t.writableTableInterfaceImpl.parent = t
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
type joinTable2 struct {
|
||||
readableTableInterfaceImpl
|
||||
jet.JoinTableImpl
|
||||
}
|
||||
|
||||
func newJoinTable(lhs jet.Serializer, rhs jet.Serializer, joinType jet.JoinType, onCondition BoolExpression) ReadableTable {
|
||||
newJoinTable := &joinTable2{
|
||||
JoinTableImpl: jet.NewJoinTableImpl(lhs, rhs, joinType, onCondition),
|
||||
}
|
||||
|
||||
newJoinTable.readableTableInterfaceImpl.parent = newJoinTable
|
||||
|
||||
return newJoinTable
|
||||
}
|
||||
|
|
|
|||
55
postgres/update_statement.go
Normal file
55
postgres/update_statement.go
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
package postgres
|
||||
|
||||
import "github.com/go-jet/jet/internal/jet"
|
||||
|
||||
// UpdateStatement is interface of SQL UPDATE statement
|
||||
type UpdateStatement interface {
|
||||
jet.Statement
|
||||
|
||||
SET(value interface{}, values ...interface{}) UpdateStatement
|
||||
MODEL(data interface{}) UpdateStatement
|
||||
|
||||
WHERE(expression BoolExpression) UpdateStatement
|
||||
RETURNING(projections ...jet.Projection) UpdateStatement
|
||||
}
|
||||
|
||||
type updateStatementImpl struct {
|
||||
jet.StatementImpl
|
||||
|
||||
Update jet.ClauseUpdate
|
||||
Set jet.ClauseSet
|
||||
Where jet.ClauseWhere
|
||||
Returning jet.ClauseReturning
|
||||
}
|
||||
|
||||
func newUpdateStatement(table WritableTable, columns []jet.IColumn) UpdateStatement {
|
||||
update := &updateStatementImpl{}
|
||||
update.StatementImpl = jet.NewStatementImpl(Dialect, jet.UpdateStatementType, update, &update.Update,
|
||||
&update.Set, &update.Where, &update.Returning)
|
||||
|
||||
update.Update.Table = table
|
||||
update.Set.Columns = columns
|
||||
update.Where.Mandatory = true
|
||||
|
||||
return update
|
||||
}
|
||||
|
||||
func (u *updateStatementImpl) SET(value interface{}, values ...interface{}) UpdateStatement {
|
||||
u.Set.Values = jet.UnwindRowFromValues(value, values)
|
||||
return u
|
||||
}
|
||||
|
||||
func (u *updateStatementImpl) MODEL(data interface{}) UpdateStatement {
|
||||
u.Set.Values = jet.UnwindRowFromModel(u.Set.Columns, data)
|
||||
return u
|
||||
}
|
||||
|
||||
func (u *updateStatementImpl) WHERE(expression BoolExpression) UpdateStatement {
|
||||
u.Where.Condition = expression
|
||||
return u
|
||||
}
|
||||
|
||||
func (u *updateStatementImpl) RETURNING(projections ...jet.Projection) UpdateStatement {
|
||||
u.Returning.Projections = projections
|
||||
return u
|
||||
}
|
||||
62
postgres/update_statement_test.go
Normal file
62
postgres/update_statement_test.go
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
package postgres
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUpdateWithOneValue(t *testing.T) {
|
||||
expectedSQL := `
|
||||
UPDATE db.table1
|
||||
SET col_int = $1
|
||||
WHERE table1.col_int >= $2;
|
||||
`
|
||||
stmt := table1.UPDATE(table1ColInt).
|
||||
SET(1).
|
||||
WHERE(table1ColInt.GT_EQ(Int(33)))
|
||||
|
||||
fmt.Println(stmt.Sql())
|
||||
|
||||
assertStatement(t, stmt, expectedSQL, 1, int64(33))
|
||||
}
|
||||
|
||||
func TestUpdateWithValues(t *testing.T) {
|
||||
expectedSQL := `
|
||||
UPDATE db.table1
|
||||
SET (col_int, col_float) = ($1, $2)
|
||||
WHERE table1.col_int >= $3;
|
||||
`
|
||||
stmt := table1.UPDATE(table1ColInt, table1ColFloat).
|
||||
SET(1, 22.2).
|
||||
WHERE(table1ColInt.GT_EQ(Int(33)))
|
||||
|
||||
fmt.Println(stmt.Sql())
|
||||
|
||||
assertStatement(t, stmt, expectedSQL, 1, 22.2, int64(33))
|
||||
}
|
||||
|
||||
func TestUpdateOneColumnWithSelect(t *testing.T) {
|
||||
expectedSQL := `
|
||||
UPDATE db.table1
|
||||
SET col_float = (
|
||||
SELECT table1.col_float AS "table1.col_float"
|
||||
FROM db.table1
|
||||
)
|
||||
WHERE table1.col1 = $1
|
||||
RETURNING table1.col1 AS "table1.col1";
|
||||
`
|
||||
stmt := table1.
|
||||
UPDATE(table1ColFloat).
|
||||
SET(
|
||||
table1.SELECT(table1ColFloat),
|
||||
).
|
||||
WHERE(table1Col1.EQ(Int(2))).
|
||||
RETURNING(table1Col1)
|
||||
|
||||
assertStatement(t, stmt, expectedSQL, int64(2))
|
||||
}
|
||||
|
||||
func TestInvalidInputs(t *testing.T) {
|
||||
assertStatementErr(t, table1.UPDATE(table1ColInt).SET(1), "jet: WHERE clause not set")
|
||||
assertStatementErr(t, table1.UPDATE(nil).SET(1), "jet: nil column in columns list")
|
||||
}
|
||||
|
|
@ -70,7 +70,7 @@ var table3 = NewTable(
|
|||
table3ColInt,
|
||||
table3StrCol)
|
||||
|
||||
func assertClauseSerialize(t *testing.T, clause jet.Clause, query string, args ...interface{}) {
|
||||
func assertClauseSerialize(t *testing.T, clause jet.Serializer, query string, args ...interface{}) {
|
||||
out := jet.SqlBuilder{Dialect: Dialect}
|
||||
err := jet.Serialize(clause, jet.SelectStatementType, &out)
|
||||
|
||||
|
|
@ -80,7 +80,7 @@ func assertClauseSerialize(t *testing.T, clause jet.Clause, query string, args .
|
|||
assert.DeepEqual(t, out.Args, args)
|
||||
}
|
||||
|
||||
func assertClauseSerializeErr(t *testing.T, clause jet.Clause, errString string) {
|
||||
func assertClauseSerializeErr(t *testing.T, clause jet.Serializer, errString string) {
|
||||
out := jet.SqlBuilder{Dialect: Dialect}
|
||||
err := jet.Serialize(clause, jet.SelectStatementType, &out)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue