Postgres refactor.

This commit is contained in:
go-jet 2019-08-11 09:52:02 +02:00
parent d00167cbba
commit 8519ccbdd0
57 changed files with 2451 additions and 598 deletions

View file

@ -14,7 +14,7 @@ func newAlias(expression Expression, aliasName string) Projection {
func (a *alias) fromImpl(subQuery SelectTable) Projection { func (a *alias) fromImpl(subQuery SelectTable) Projection {
column := newColumn(a.alias, "", nil) column := newColumn(a.alias, "", nil)
column.parent = &column column.Parent = &column
column.subQuery = subQuery column.subQuery = subQuery
return &column return &column

View file

@ -86,7 +86,7 @@ func (b *boolInterfaceImpl) IS_NOT_UNKNOWN() BoolExpression {
//---------------------------------------------------// //---------------------------------------------------//
type binaryBoolExpression struct { type binaryBoolExpression struct {
expressionInterfaceImpl ExpressionInterfaceImpl
boolInterfaceImpl boolInterfaceImpl
binaryOpExpression binaryOpExpression
@ -96,7 +96,7 @@ func newBinaryBoolOperator(lhs, rhs Expression, operator string) BoolExpression
binaryBoolExpression := binaryBoolExpression{} binaryBoolExpression := binaryBoolExpression{}
binaryBoolExpression.binaryOpExpression = newBinaryExpression(lhs, rhs, operator) binaryBoolExpression.binaryOpExpression = newBinaryExpression(lhs, rhs, operator)
binaryBoolExpression.expressionInterfaceImpl.parent = &binaryBoolExpression binaryBoolExpression.ExpressionInterfaceImpl.Parent = &binaryBoolExpression
binaryBoolExpression.boolInterfaceImpl.parent = &binaryBoolExpression binaryBoolExpression.boolInterfaceImpl.parent = &binaryBoolExpression
return &binaryBoolExpression return &binaryBoolExpression
@ -104,7 +104,7 @@ func newBinaryBoolOperator(lhs, rhs Expression, operator string) BoolExpression
//---------------------------------------------------// //---------------------------------------------------//
type prefixBoolExpression struct { type prefixBoolExpression struct {
expressionInterfaceImpl ExpressionInterfaceImpl
boolInterfaceImpl boolInterfaceImpl
prefixOpExpression prefixOpExpression
@ -114,7 +114,7 @@ func newPrefixBoolOperator(expression Expression, operator string) BoolExpressio
exp := prefixBoolExpression{} exp := prefixBoolExpression{}
exp.prefixOpExpression = newPrefixExpression(expression, operator) exp.prefixOpExpression = newPrefixExpression(expression, operator)
exp.expressionInterfaceImpl.parent = &exp exp.ExpressionInterfaceImpl.Parent = &exp
exp.boolInterfaceImpl.parent = &exp exp.boolInterfaceImpl.parent = &exp
return &exp return &exp
@ -122,7 +122,7 @@ func newPrefixBoolOperator(expression Expression, operator string) BoolExpressio
//---------------------------------------------------// //---------------------------------------------------//
type postfixBoolOpExpression struct { type postfixBoolOpExpression struct {
expressionInterfaceImpl ExpressionInterfaceImpl
boolInterfaceImpl boolInterfaceImpl
postfixOpExpression postfixOpExpression
@ -132,7 +132,7 @@ func newPostifxBoolExpression(expression Expression, operator string) BoolExpres
exp := postfixBoolOpExpression{} exp := postfixBoolOpExpression{}
exp.postfixOpExpression = newPostfixOpExpression(expression, operator) exp.postfixOpExpression = newPostfixOpExpression(expression, operator)
exp.expressionInterfaceImpl.parent = &exp exp.ExpressionInterfaceImpl.Parent = &exp
exp.boolInterfaceImpl.parent = &exp exp.boolInterfaceImpl.parent = &exp
return &exp return &exp

View file

@ -32,7 +32,7 @@ func (b *CastImpl) AS(castType string) Expression {
cast: string(castType), cast: string(castType),
} }
castExp.expressionInterfaceImpl.parent = castExp castExp.ExpressionInterfaceImpl.Parent = castExp
return castExp return castExp
} }
@ -61,7 +61,7 @@ func (b *CastImpl) AS_TIME() TimeExpression {
} }
type castExpression struct { type castExpression struct {
expressionInterfaceImpl ExpressionInterfaceImpl
expression Expression expression Expression
cast string cast string

View file

@ -1,270 +1,702 @@
package jet package jet
import ( import (
"bytes" "errors"
"github.com/go-jet/jet/internal/utils" "github.com/go-jet/jet/internal/utils"
"github.com/google/uuid"
"strconv"
"strings"
"time"
)
type SerializeOption int
const (
noWrap SerializeOption = iota
) )
type Clause interface { type Clause interface {
serialize(statement StatementType, out *SqlBuilder, options ...SerializeOption) error Serialize(statementType StatementType, out *SqlBuilder) error
} }
func Serialize(exp Clause, statementType StatementType, out *SqlBuilder, options ...SerializeOption) error { type ClauseWithProjections interface {
return exp.serialize(statementType, out, options...) Clause
projections() []Projection
} }
func contains(options []SerializeOption, option SerializeOption) bool { type ClauseSelect struct {
for _, opt := range options { Distinct bool
if opt == option { Projections []Projection
return true }
func (s *ClauseSelect) projections() []Projection {
return s.Projections
}
func (s *ClauseSelect) Serialize(statementType StatementType, out *SqlBuilder) error {
out.newLine()
out.WriteString("SELECT")
if s.Distinct {
out.WriteString("DISTINCT")
}
if len(s.Projections) == 0 {
return errors.New("jet: no column selected for Projection")
}
return out.writeProjections(statementType, s.Projections)
}
type ClauseFrom struct {
Table Serializer
}
func (f *ClauseFrom) Serialize(statementType StatementType, out *SqlBuilder) error {
if f.Table == nil {
return nil
}
return out.writeFrom(statementType, f.Table)
}
type ClauseWhere struct {
Condition BoolExpression
Mandatory bool
}
func (c *ClauseWhere) Serialize(statementType StatementType, out *SqlBuilder) error {
if c.Condition == nil {
if c.Mandatory {
return errors.New("jet: WHERE clause not set")
} }
return nil
} }
return out.writeWhere(statementType, c.Condition)
return false
} }
type SqlBuilder struct { type ClauseGroupBy struct {
Dialect Dialect List []GroupByClause
Buff bytes.Buffer
Args []interface{}
lastChar byte
ident int
} }
func (s *SqlBuilder) DebugSQL() string { func (c *ClauseGroupBy) Serialize(statementType StatementType, out *SqlBuilder) error {
return queryStringToDebugString(s.Buff.String(), s.Args, s.Dialect) if len(c.List) == 0 {
}
type StatementType string
const (
SelectStatementType StatementType = "SELECT"
InsertStatementType StatementType = "INSERT"
UpdateStatementType StatementType = "UPDATE"
DeleteStatementType StatementType = "DELETE"
SetStatementType StatementType = "SET"
LockStatementType StatementType = "LOCK"
)
const defaultIdent = 5
func (q *SqlBuilder) increaseIdent() {
q.ident += defaultIdent
}
func (q *SqlBuilder) decreaseIdent() {
if q.ident < defaultIdent {
q.ident = 0
}
q.ident -= defaultIdent
}
func (q *SqlBuilder) writeProjections(statement StatementType, projections []Projection) error {
q.increaseIdent()
err := SerializeProjectionList(statement, projections, q)
q.decreaseIdent()
return err
}
func (q *SqlBuilder) writeFrom(statement StatementType, table ReadableTable) error {
q.newLine()
q.WriteString("FROM")
q.increaseIdent()
err := table.serialize(statement, q)
q.decreaseIdent()
return err
}
func (q *SqlBuilder) writeWhere(statement StatementType, where Expression) error {
q.newLine()
q.WriteString("WHERE")
q.increaseIdent()
err := where.serialize(statement, q, noWrap)
q.decreaseIdent()
return err
}
func (q *SqlBuilder) writeGroupBy(statement StatementType, groupBy []groupByClause) error {
q.newLine()
q.WriteString("GROUP BY")
q.increaseIdent()
err := serializeGroupByClauseList(statement, groupBy, q)
q.decreaseIdent()
return err
}
func (q *SqlBuilder) writeOrderBy(statement StatementType, orderBy []orderByClause) error {
q.newLine()
q.WriteString("ORDER BY")
q.increaseIdent()
err := serializeOrderByClauseList(statement, orderBy, q)
q.decreaseIdent()
return err
}
func (q *SqlBuilder) writeHaving(statement StatementType, having Expression) error {
q.newLine()
q.WriteString("HAVING")
q.increaseIdent()
err := having.serialize(statement, q, noWrap)
q.decreaseIdent()
return err
}
func (q *SqlBuilder) writeReturning(statement StatementType, returning []Projection) error {
if len(returning) == 0 {
return nil return nil
} }
if !q.Dialect.SupportsReturning() { out.newLine()
panic("jet: " + q.Dialect.Name() + " dialect does not support RETURNING.") out.WriteString("GROUP BY")
out.increaseIdent()
err := serializeGroupByClauseList(statementType, c.List, out)
out.decreaseIdent()
return err
}
type ClauseHaving struct {
Condition BoolExpression
}
func (c *ClauseHaving) Serialize(statementType StatementType, out *SqlBuilder) error {
if c.Condition == nil {
return nil
} }
q.newLine() return out.writeHaving(statementType, c.Condition)
q.WriteString("RETURNING")
q.increaseIdent()
return q.writeProjections(statement, returning)
} }
func (q *SqlBuilder) newLine() { type ClauseOrderBy struct {
q.write([]byte{'\n'}) List []OrderByClause
q.write(bytes.Repeat([]byte{' '}, q.ident))
} }
func (q *SqlBuilder) write(data []byte) { func (o *ClauseOrderBy) Serialize(statementType StatementType, out *SqlBuilder) error {
if len(data) == 0 { if o.List == nil {
return nil
}
return out.writeOrderBy(statementType, o.List)
}
type ClauseLimit struct {
Count int64
}
func (l *ClauseLimit) Serialize(statementType StatementType, out *SqlBuilder) error {
if l.Count >= 0 {
out.newLine()
out.WriteString("LIMIT")
out.insertParametrizedArgument(l.Count)
}
return nil
}
type ClauseOffset struct {
Count int64
}
func (o *ClauseOffset) Serialize(statementType StatementType, out *SqlBuilder) error {
if o.Count >= 0 {
out.newLine()
out.WriteString("OFFSET")
out.insertParametrizedArgument(o.Count)
}
return nil
}
type ClauseFor struct {
Lock SelectLock
}
func (f *ClauseFor) Serialize(statementType StatementType, out *SqlBuilder) error {
if f.Lock == nil {
return nil
}
out.newLine()
out.WriteString("FOR")
return f.Lock.serialize(statementType, out)
}
type ClauseSetStmtOperator struct {
Operator string
All bool
Selects []StatementWithProjections
OrderBy ClauseOrderBy
Limit ClauseLimit
Offset ClauseOffset
}
func (s *ClauseSetStmtOperator) projections() []Projection {
if len(s.Selects) > 0 {
return s.Selects[0].projections()
}
return nil
}
func (s *ClauseSetStmtOperator) Serialize(statementType StatementType, out *SqlBuilder) error {
if len(s.Selects) < 2 {
return errors.New("jet: UNION Statement must have at least two SELECT statements")
}
wrap := s.OrderBy.List != nil || s.Limit.Count >= 0 || s.Offset.Count >= 0
//if wrap {
// out.WriteString("(")
// out.increaseIdent()
//}
if wrap {
out.newLine()
out.WriteString("(")
out.increaseIdent()
}
for i, selectStmt := range s.Selects {
out.newLine()
if i > 0 {
out.WriteString(s.Operator)
if s.All {
out.WriteString("ALL")
}
out.newLine()
}
if selectStmt == nil {
return errors.New("jet: select statement is nil")
}
err := selectStmt.serialize(statementType, out)
if err != nil {
return err
}
}
if wrap {
out.decreaseIdent()
out.newLine()
out.WriteString(")")
}
if err := s.OrderBy.Serialize(statementType, out); err != nil {
return err
}
if err := s.Limit.Serialize(statementType, out); err != nil {
return err
}
if err := s.Offset.Serialize(statementType, out); err != nil {
return err
}
//if wrap {
// out.decreaseIdent()
// out.newLine()
// out.WriteString(")")
//}
return nil
}
type ClauseUpdate struct {
Table SerializerTable
}
func (u *ClauseUpdate) Serialize(statementType StatementType, out *SqlBuilder) error {
out.newLine()
out.WriteString("UPDATE")
if utils.IsNil(u.Table) {
return errors.New("jet: table to update is nil")
}
if err := u.Table.serialize(statementType, out); err != nil {
return err
}
return nil
}
type ClauseSet struct {
Columns []IColumn
Values []Serializer
}
func (s *ClauseSet) Serialize(statementType StatementType, out *SqlBuilder) error {
out.newLine()
out.WriteString("SET")
if len(s.Columns) == 0 {
return errors.New("jet: no columns selected")
}
if len(s.Columns) > 1 {
out.WriteString("(")
}
err := SerializeColumnNames(s.Columns, out)
if err != nil {
return err
}
if len(s.Columns) > 1 {
out.WriteString(")")
}
out.WriteString("=")
if len(s.Values) > 1 {
out.WriteString("(")
}
err = SerializeClauseList(statementType, s.Values, out)
if err != nil {
return err
}
if len(s.Values) > 1 {
out.WriteString(")")
}
return nil
}
type ClauseReturning struct {
Projections []Projection
}
func (r *ClauseReturning) Serialize(statementType StatementType, out *SqlBuilder) error {
return out.WriteReturning(statementType, r.Projections)
}
type ClauseInsert struct {
Table SerializerTable
Columns []IColumn
}
func (i *ClauseInsert) Serialize(statementType StatementType, out *SqlBuilder) error {
out.newLine()
out.WriteString("INSERT INTO")
if utils.IsNil(i.Table) {
return errors.New("jet: table is nil")
}
err := i.Table.serialize(statementType, out)
if err != nil {
return err
}
if len(i.Columns) > 0 {
out.WriteString("(")
err = SerializeColumnNames(i.Columns, out)
if err != nil {
return err
}
out.WriteString(")")
}
return nil
}
type ClauseValues struct {
Rows [][]Serializer
}
func (v *ClauseValues) Serialize(statementType StatementType, out *SqlBuilder) error {
if len(v.Rows) == 0 {
return nil
}
out.WriteString("VALUES")
for rowIndex, row := range v.Rows {
if rowIndex > 0 {
out.WriteString(",")
}
out.increaseIdent()
out.newLine()
out.WriteString("(")
err := SerializeClauseList(statementType, row, out)
if err != nil {
return err
}
out.writeByte(')')
out.decreaseIdent()
}
return nil
}
type ClauseQuery struct {
Query SerializerStatement
}
func (v *ClauseQuery) Serialize(statementType StatementType, out *SqlBuilder) error {
if v.Query == nil {
return nil
}
return v.Query.serialize(statementType, out)
}
type ClauseDelete struct {
Table SerializerTable
}
func (d *ClauseDelete) Serialize(statementType StatementType, out *SqlBuilder) error {
out.newLine()
out.WriteString("DELETE FROM")
if d.Table == nil {
return errors.New("jet: nil tableName")
}
if err := d.Table.serialize(statementType, out); err != nil {
return err
}
return nil
}
type ClauseStatementBegin struct {
Name string
Tables []SerializerTable
}
func (d *ClauseStatementBegin) Serialize(statementType StatementType, out *SqlBuilder) error {
out.newLine()
out.WriteString(d.Name)
for i, table := range d.Tables {
if i > 0 {
out.WriteString(", ")
}
err := table.serialize(statementType, out)
if err != nil {
return err
}
}
return nil
}
type ClauseString struct {
Name string
Data string
}
func (d *ClauseString) Serialize(statementType StatementType, out *SqlBuilder) error {
out.newLine()
out.WriteString(d.Name)
out.WriteString(d.Data)
return nil
}
type ClauseOptional struct {
Name string
Show bool
}
func (d *ClauseOptional) Serialize(statementType StatementType, out *SqlBuilder) error {
if !d.Show {
return nil
}
//out.newLine()
out.WriteString(d.Name)
return nil
}
type ClauseIn struct {
LockMode string
}
func (i *ClauseIn) Serialize(statementType StatementType, out *SqlBuilder) error {
if i.LockMode == "" {
return nil
}
out.WriteString("IN")
out.WriteString(string(i.LockMode))
out.WriteString("MODE")
return nil
}
// NewTable creates new table with schema Name, table Name and list of columns
func NewTable2(Dialect Dialect, schemaName, name string, columns ...Column) TableImpl2 {
t := TableImpl2{
Dialect: Dialect,
schemaName: schemaName,
name: name,
columnList: columns,
}
for _, c := range columns {
c.SetTableName(name)
}
return t
}
type TableImpl2 struct {
Dialect Dialect
schemaName string
name string
alias string
columnList []Column
}
func (t *TableImpl2) AS(alias string) {
t.alias = alias
for _, c := range t.columnList {
c.SetTableName(alias)
}
}
func (t *TableImpl2) SchemaName() string {
return t.schemaName
}
func (t *TableImpl2) TableName() string {
return t.name
}
func (t *TableImpl2) Columns() []IColumn {
ret := []IColumn{}
for _, col := range t.columnList {
ret = append(ret, col)
}
return ret
}
func (t *TableImpl2) dialect() Dialect {
return t.Dialect
}
func (t *TableImpl2) accept(visitor visitor) {
visitor.visit(t)
}
func (t *TableImpl2) serialize(statement StatementType, out *SqlBuilder, options ...SerializeOption) error {
if t == nil {
return errors.New("jet: tableImpl is nil. ")
}
out.writeIdentifier(t.schemaName)
out.WriteString(".")
out.writeIdentifier(t.name)
if len(t.alias) > 0 {
out.WriteString("AS")
out.writeIdentifier(t.alias)
}
return nil
}
// Join expressions are pseudo readable tables.
type JoinTableImpl struct {
lhs Serializer
rhs Serializer
joinType JoinType
onCondition BoolExpression
}
func NewJoinTableImpl(lhs Serializer, rhs Serializer, joinType JoinType, onCondition BoolExpression) JoinTableImpl {
joinTable := JoinTableImpl{
lhs: lhs,
rhs: rhs,
joinType: joinType,
onCondition: onCondition,
}
return joinTable
}
func (t *JoinTableImpl) SchemaName() string {
return ""
}
func (t *JoinTableImpl) TableName() string {
return ""
}
func (t *JoinTableImpl) columns() []IColumn {
//return append(t.lhs.columns(), t.rhs.columns()...)
panic("Unimplemented")
}
func (t *JoinTableImpl) accept(visitor visitor) {
//t.lhs.accept(visitor)
//t.rhs.accept(visitor)
//TODO: uncoment
}
func (t *JoinTableImpl) dialect() Dialect {
return detectDialect(t)
}
func (t *JoinTableImpl) serialize(statement StatementType, out *SqlBuilder, options ...SerializeOption) (err error) {
if t == nil {
return errors.New("jet: Join table is nil. ")
}
if utils.IsNil(t.lhs) {
return errors.New("jet: left hand side of join operation is nil table")
}
if err = t.lhs.serialize(statement, out); err != nil {
return return
} }
if !isPreSeparator(q.lastChar) && !isPostSeparator(data[0]) && q.Buff.Len() > 0 { out.newLine()
q.Buff.WriteByte(' ')
switch t.joinType {
case InnerJoin:
out.WriteString("INNER JOIN")
case LeftJoin:
out.WriteString("LEFT JOIN")
case RightJoin:
out.WriteString("RIGHT JOIN")
case FullJoin:
out.WriteString("FULL JOIN")
case CrossJoin:
out.WriteString("CROSS JOIN")
} }
q.Buff.Write(data) if utils.IsNil(t.rhs) {
q.lastChar = data[len(data)-1] return errors.New("jet: right hand side of join operation is nil table")
}
func isPreSeparator(b byte) bool {
return b == ' ' || b == '.' || b == ',' || b == '(' || b == '\n' || b == ':'
}
func isPostSeparator(b byte) bool {
return b == ' ' || b == '.' || b == ',' || b == ')' || b == '\n' || b == ':'
}
func (q *SqlBuilder) writeAlias(str string) {
aliasQuoteChar := string(q.Dialect.AliasQuoteChar())
q.WriteString(aliasQuoteChar + str + aliasQuoteChar)
}
func (q *SqlBuilder) WriteString(str string) {
q.write([]byte(str))
}
func (q *SqlBuilder) writeIdentifier(name string, alwaysQuote ...bool) {
quoteWrap := name != strings.ToLower(name) || strings.ContainsAny(name, ". -")
if quoteWrap || len(alwaysQuote) > 0 {
identQuoteChar := string(q.Dialect.IdentifierQuoteChar())
q.WriteString(identQuoteChar + name + identQuoteChar)
} else {
q.WriteString(name)
}
}
func (q *SqlBuilder) writeByte(b byte) {
q.write([]byte{b})
}
func (q *SqlBuilder) finalize() (string, []interface{}) {
return q.Buff.String() + ";\n", q.Args
}
func (q *SqlBuilder) insertConstantArgument(arg interface{}) {
q.WriteString(argToString(arg))
}
func (q *SqlBuilder) insertParametrizedArgument(arg interface{}) {
q.Args = append(q.Args, arg)
argPlaceholder := q.Dialect.ArgumentPlaceholder()(len(q.Args))
q.WriteString(argPlaceholder)
}
func argToString(value interface{}) string {
if utils.IsNil(value) {
return "NULL"
} }
switch bindVal := value.(type) { if err = t.rhs.serialize(statement, out); err != nil {
case bool: return
if bindVal { }
return "TRUE"
if t.onCondition == nil && t.joinType != CrossJoin {
return errors.New("jet: join condition is nil")
}
if t.onCondition != nil {
out.WriteString("ON")
if err = t.onCondition.serialize(statement, out); err != nil {
return
} }
return "FALSE"
case int8:
return strconv.FormatInt(int64(bindVal), 10)
case int:
return strconv.FormatInt(int64(bindVal), 10)
case int16:
return strconv.FormatInt(int64(bindVal), 10)
case int32:
return strconv.FormatInt(int64(bindVal), 10)
case int64:
return strconv.FormatInt(int64(bindVal), 10)
case uint8:
return strconv.FormatUint(uint64(bindVal), 10)
case uint:
return strconv.FormatUint(uint64(bindVal), 10)
case uint16:
return strconv.FormatUint(uint64(bindVal), 10)
case uint32:
return strconv.FormatUint(uint64(bindVal), 10)
case uint64:
return strconv.FormatUint(uint64(bindVal), 10)
case float32:
return strconv.FormatFloat(float64(bindVal), 'f', -1, 64)
case float64:
return strconv.FormatFloat(float64(bindVal), 'f', -1, 64)
case string:
return stringQuote(bindVal)
case []byte:
return stringQuote(string(bindVal))
case uuid.UUID:
return stringQuote(bindVal.String())
case time.Time:
return stringQuote(string(utils.FormatTimestamp(bindVal)))
default:
return "[Unsupported type]"
} }
return nil
} }
func stringQuote(value string) string { // SelectTable is interface for SELECT sub-queries
return `'` + strings.Replace(value, "'", "''", -1) + `'` type SelectTable interface {
Alias() string
AllColumns() ProjectionList
}
type SelectTableImpl2 struct {
selectStmt StatementWithProjections
alias string
projections []Projection
}
func NewSelectTable(selectStmt StatementWithProjections, alias string) SelectTableImpl2 {
selectTable := SelectTableImpl2{selectStmt: selectStmt, alias: alias}
for _, projection := range selectStmt.projections() {
newProjection := projection.fromImpl(&selectTable)
selectTable.projections = append(selectTable.projections, newProjection)
}
return selectTable
}
func (s *SelectTableImpl2) Alias() string {
return s.alias
}
func (s *SelectTableImpl2) columns() []IColumn {
return nil
}
func (s *SelectTableImpl2) accept(visitor visitor) {
visitor.visit(s)
s.selectStmt.accept(visitor)
}
func (s *SelectTableImpl2) dialect() Dialect {
return detectDialect(s.selectStmt)
}
func (s *SelectTableImpl2) AllColumns() ProjectionList {
return s.projections
}
func (s *SelectTableImpl2) serialize(statement StatementType, out *SqlBuilder, options ...SerializeOption) error {
if s == nil {
return errors.New("jet: Expression table is nil. ")
}
err := s.selectStmt.serialize(statement, out)
if err != nil {
return err
}
out.WriteString("AS")
out.writeIdentifier(s.alias)
return nil
} }

View file

@ -19,7 +19,7 @@ type Column interface {
// The base type for real materialized columns. // The base type for real materialized columns.
type columnImpl struct { type columnImpl struct {
expressionInterfaceImpl ExpressionInterfaceImpl
noOpVisitorImpl noOpVisitorImpl
name string name string
@ -34,7 +34,7 @@ func newColumn(name string, tableName string, parent Column) columnImpl {
tableName: tableName, tableName: tableName,
} }
bc.expressionInterfaceImpl.parent = parent bc.ExpressionInterfaceImpl.Parent = parent
return bc return bc
} }

View file

@ -4,7 +4,7 @@ import "testing"
func TestColumn(t *testing.T) { func TestColumn(t *testing.T) {
column := newColumn("col", "", nil) column := newColumn("col", "", nil)
column.expressionInterfaceImpl.parent = &column column.ExpressionInterfaceImpl.Parent = &column
assertClauseSerialize(t, column, "col") assertClauseSerialize(t, column, "col")
column.SetTableName("table1") column.SetTableName("table1")

View file

@ -67,7 +67,7 @@ func (d *deleteStatementImpl) serializeImpl(out *SqlBuilder) error {
return err return err
} }
if err := out.writeReturning(DeleteStatementType, d.returning); err != nil { if err := out.WriteReturning(DeleteStatementType, d.returning); err != nil {
return err return err
} }

View file

@ -21,7 +21,7 @@ type Dialect interface {
AliasQuoteChar() byte AliasQuoteChar() byte
IdentifierQuoteChar() byte IdentifierQuoteChar() byte
ArgumentPlaceholder() QueryPlaceholderFunc ArgumentPlaceholder() QueryPlaceholderFunc
SetClause() func(columns []IColumn, values []Clause, out *SqlBuilder) (err error) SetClause() func(columns []IColumn, values []Serializer, out *SqlBuilder) (err error)
SupportsReturning() bool SupportsReturning() bool
} }
@ -29,7 +29,7 @@ type SerializeFunc func(statement StatementType, out *SqlBuilder, options ...Ser
type SerializeOverride func(expressions ...Expression) SerializeFunc type SerializeOverride func(expressions ...Expression) SerializeFunc
type QueryPlaceholderFunc func(ord int) string type QueryPlaceholderFunc func(ord int) string
type UpdateAssigmentFunc func(columns []IColumn, values []Clause, out *SqlBuilder) (err error) type UpdateAssigmentFunc func(columns []IColumn, values []Serializer, out *SqlBuilder) (err error)
type DialectParams struct { type DialectParams struct {
Name string Name string
@ -38,7 +38,7 @@ type DialectParams struct {
AliasQuoteChar byte AliasQuoteChar byte
IdentifierQuoteChar byte IdentifierQuoteChar byte
ArgumentPlaceholder QueryPlaceholderFunc ArgumentPlaceholder QueryPlaceholderFunc
SetClause func(columns []IColumn, values []Clause, out *SqlBuilder) (err error) SetClause func(columns []IColumn, values []Serializer, out *SqlBuilder) (err error)
SupportsReturning bool SupportsReturning bool
} }
@ -92,7 +92,7 @@ func (d *dialectImpl) ArgumentPlaceholder() QueryPlaceholderFunc {
return d.argumentPlaceholder return d.argumentPlaceholder
} }
func (d *dialectImpl) SetClause() func(columns []IColumn, values []Clause, out *SqlBuilder) (err error) { func (d *dialectImpl) SetClause() func(columns []IColumn, values []Serializer, out *SqlBuilder) (err error) {
if d.setClause != nil { if d.setClause != nil {
return d.setClause return d.setClause
} }
@ -103,7 +103,7 @@ func (d *dialectImpl) SupportsReturning() bool {
return d.supportsReturning return d.supportsReturning
} }
func setClause(columns []IColumn, values []Clause, out *SqlBuilder) (err error) { func setClause(columns []IColumn, values []Serializer, out *SqlBuilder) (err error) {
if len(columns) != len(values) { if len(columns) != len(values) {
return errors.New("jet: mismatch in numers of columns and values") return errors.New("jet: mismatch in numers of columns and values")

View file

@ -1,7 +1,7 @@
package jet package jet
type enumValue struct { type enumValue struct {
expressionInterfaceImpl ExpressionInterfaceImpl
stringInterfaceImpl stringInterfaceImpl
noOpVisitorImpl noOpVisitorImpl
@ -12,7 +12,7 @@ type enumValue struct {
func NewEnumValue(name string) StringExpression { func NewEnumValue(name string) StringExpression {
enumValue := &enumValue{name: name} enumValue := &enumValue{name: name}
enumValue.expressionInterfaceImpl.parent = enumValue enumValue.ExpressionInterfaceImpl.Parent = enumValue
enumValue.stringInterfaceImpl.parent = enumValue enumValue.stringInterfaceImpl.parent = enumValue
return enumValue return enumValue

View file

@ -9,14 +9,14 @@ import (
type Expression interface { type Expression interface {
acceptsVisitor acceptsVisitor
expression IExpression
} }
type expression interface { type IExpression interface {
Clause Serializer
Projection Projection
groupByClause GroupByClause
orderByClause OrderByClause
// Test expression whether it is a NULL value. // Test expression whether it is a NULL value.
IS_NULL() BoolExpression IS_NULL() BoolExpression
@ -32,57 +32,57 @@ type expression interface {
AS(alias string) Projection AS(alias string) Projection
// Expression will be used to sort query result in ascending order // Expression will be used to sort query result in ascending order
ASC() orderByClause ASC() OrderByClause
// Expression will be used to sort query result in ascending order // Expression will be used to sort query result in ascending order
DESC() orderByClause DESC() OrderByClause
} }
type expressionInterfaceImpl struct { type ExpressionInterfaceImpl struct {
parent Expression Parent Expression
} }
func (e *expressionInterfaceImpl) fromImpl(subQuery SelectTable) Projection { func (e *ExpressionInterfaceImpl) fromImpl(subQuery SelectTable) Projection {
return e.parent return e.Parent
} }
func (e *expressionInterfaceImpl) IS_NULL() BoolExpression { func (e *ExpressionInterfaceImpl) IS_NULL() BoolExpression {
return newPostifxBoolExpression(e.parent, "IS NULL") return newPostifxBoolExpression(e.Parent, "IS NULL")
} }
func (e *expressionInterfaceImpl) IS_NOT_NULL() BoolExpression { func (e *ExpressionInterfaceImpl) IS_NOT_NULL() BoolExpression {
return newPostifxBoolExpression(e.parent, "IS NOT NULL") return newPostifxBoolExpression(e.Parent, "IS NOT NULL")
} }
func (e *expressionInterfaceImpl) IN(expressions ...Expression) BoolExpression { func (e *ExpressionInterfaceImpl) IN(expressions ...Expression) BoolExpression {
return newBinaryBoolOperator(e.parent, WRAP(expressions...), "IN") return newBinaryBoolOperator(e.Parent, WRAP(expressions...), "IN")
} }
func (e *expressionInterfaceImpl) NOT_IN(expressions ...Expression) BoolExpression { func (e *ExpressionInterfaceImpl) NOT_IN(expressions ...Expression) BoolExpression {
return newBinaryBoolOperator(e.parent, WRAP(expressions...), "NOT IN") return newBinaryBoolOperator(e.Parent, WRAP(expressions...), "NOT IN")
} }
func (e *expressionInterfaceImpl) AS(alias string) Projection { func (e *ExpressionInterfaceImpl) AS(alias string) Projection {
return newAlias(e.parent, alias) return newAlias(e.Parent, alias)
} }
func (e *expressionInterfaceImpl) ASC() orderByClause { func (e *ExpressionInterfaceImpl) ASC() OrderByClause {
return newOrderByClause(e.parent, true) return newOrderByClause(e.Parent, true)
} }
func (e *expressionInterfaceImpl) DESC() orderByClause { func (e *ExpressionInterfaceImpl) DESC() OrderByClause {
return newOrderByClause(e.parent, false) return newOrderByClause(e.Parent, false)
} }
func (e *expressionInterfaceImpl) serializeForGroupBy(statement StatementType, out *SqlBuilder) error { func (e *ExpressionInterfaceImpl) serializeForGroupBy(statement StatementType, out *SqlBuilder) error {
return e.parent.serialize(statement, out, noWrap) return e.Parent.serialize(statement, out, noWrap)
} }
func (e *expressionInterfaceImpl) serializeForProjection(statement StatementType, out *SqlBuilder) error { func (e *ExpressionInterfaceImpl) serializeForProjection(statement StatementType, out *SqlBuilder) error {
return e.parent.serialize(statement, out, noWrap) return e.Parent.serialize(statement, out, noWrap)
} }
func (e *expressionInterfaceImpl) serializeForOrderBy(statement StatementType, out *SqlBuilder) error { func (e *ExpressionInterfaceImpl) serializeForOrderBy(statement StatementType, out *SqlBuilder) error {
return e.parent.serialize(statement, out, noWrap) return e.Parent.serialize(statement, out, noWrap)
} }
// Representation of binary operations (e.g. comparisons, arithmetic) // Representation of binary operations (e.g. comparisons, arithmetic)

View file

@ -86,7 +86,7 @@ func (n *floatInterfaceImpl) POW(expression NumericExpression) FloatExpression {
//---------------------------------------------------// //---------------------------------------------------//
type binaryFloatExpression struct { type binaryFloatExpression struct {
expressionInterfaceImpl ExpressionInterfaceImpl
floatInterfaceImpl floatInterfaceImpl
binaryOpExpression binaryOpExpression
@ -97,7 +97,7 @@ func newBinaryFloatExpression(lhs, rhs Expression, operator string) FloatExpress
floatExpression.binaryOpExpression = newBinaryExpression(lhs, rhs, operator) floatExpression.binaryOpExpression = newBinaryExpression(lhs, rhs, operator)
floatExpression.expressionInterfaceImpl.parent = &floatExpression floatExpression.ExpressionInterfaceImpl.Parent = &floatExpression
floatExpression.floatInterfaceImpl.parent = &floatExpression floatExpression.floatInterfaceImpl.parent = &floatExpression
return &floatExpression return &floatExpression

View file

@ -478,7 +478,7 @@ func LEAST(value Expression, values ...Expression) Expression {
//--------------------------------------------------------------------// //--------------------------------------------------------------------//
type funcExpressionImpl struct { type funcExpressionImpl struct {
expressionInterfaceImpl ExpressionInterfaceImpl
name string name string
expressions []Expression expressions []Expression
@ -492,9 +492,9 @@ func newFunc(name string, expressions []Expression, parent Expression) *funcExpr
} }
if parent != nil { if parent != nil {
funcExp.expressionInterfaceImpl.parent = parent funcExp.ExpressionInterfaceImpl.Parent = parent
} else { } else {
funcExp.expressionInterfaceImpl.parent = funcExp funcExp.ExpressionInterfaceImpl.Parent = funcExp
} }
return funcExp return funcExp

View file

@ -1,5 +1,5 @@
package jet package jet
type groupByClause interface { type GroupByClause interface {
serializeForGroupBy(statement StatementType, out *SqlBuilder) error serializeForGroupBy(statement StatementType, out *SqlBuilder) error
} }

View file

@ -35,23 +35,23 @@ func newInsertStatement(t WritableTable, columns []IColumn) InsertStatement {
type insertStatementImpl struct { type insertStatementImpl struct {
table WritableTable table WritableTable
columns []IColumn columns []IColumn
rows [][]Clause rows [][]Serializer
query SelectStatement query SelectStatement
returning []Projection returning []Projection
} }
func (i *insertStatementImpl) VALUES(value interface{}, values ...interface{}) InsertStatement { func (i *insertStatementImpl) VALUES(value interface{}, values ...interface{}) InsertStatement {
i.rows = append(i.rows, unwindRowFromValues(value, values)) i.rows = append(i.rows, UnwindRowFromValues(value, values))
return i return i
} }
func (i *insertStatementImpl) MODEL(data interface{}) InsertStatement { func (i *insertStatementImpl) MODEL(data interface{}) InsertStatement {
i.rows = append(i.rows, unwindRowFromModel(i.getColumns(), data)) i.rows = append(i.rows, UnwindRowFromModel(i.getColumns(), data))
return i return i
} }
func (i *insertStatementImpl) MODELS(data interface{}) InsertStatement { func (i *insertStatementImpl) MODELS(data interface{}) InsertStatement {
i.rows = append(i.rows, unwindRowsFromModels(i.getColumns(), data)...) i.rows = append(i.rows, UnwindRowsFromModels(i.getColumns(), data)...)
return i return i
} }
@ -113,6 +113,8 @@ func (i *insertStatementImpl) Sql(dialect ...Dialect) (query string, args []inte
out.WriteString(")") out.WriteString(")")
} }
//TODO:
if len(i.rows) == 0 && i.query == nil { if len(i.rows) == 0 && i.query == nil {
return "", nil, errors.New("jet: no row values or query specified") return "", nil, errors.New("jet: no row values or query specified")
} }
@ -152,7 +154,7 @@ func (i *insertStatementImpl) Sql(dialect ...Dialect) (query string, args []inte
} }
} }
if err = out.writeReturning(InsertStatementType, i.returning); err != nil { if err = out.WriteReturning(InsertStatementType, i.returning); err != nil {
return return
} }

View file

@ -82,9 +82,9 @@ func TestInsertValuesFromModel(t *testing.T) {
MODEL(&toInsert) MODEL(&toInsert)
expectedSQL := ` expectedSQL := `
INSERT INTO db.table1 (col1, col_float) VALUES INSERT INTO db.table1 (col1, col_float)
($1, $2), VALUES ($1, $2),
($3, $4); ($3, $4);
` `
assertStatement(t, stmt, expectedSQL, int(1), float64(1.11), int(1), float64(1.11)) assertStatement(t, stmt, expectedSQL, int(1), float64(1.11), int(1), float64(1.11))

View file

@ -131,7 +131,7 @@ func (i *integerInterfaceImpl) BIT_SHIFT_RIGHT(intExpression IntegerExpression)
//---------------------------------------------------// //---------------------------------------------------//
type binaryIntegerExpression struct { type binaryIntegerExpression struct {
expressionInterfaceImpl ExpressionInterfaceImpl
integerInterfaceImpl integerInterfaceImpl
binaryOpExpression binaryOpExpression
@ -140,7 +140,7 @@ type binaryIntegerExpression struct {
func newBinaryIntegerExpression(lhs, rhs IntegerExpression, operator string) IntegerExpression { func newBinaryIntegerExpression(lhs, rhs IntegerExpression, operator string) IntegerExpression {
integerExpression := binaryIntegerExpression{} integerExpression := binaryIntegerExpression{}
integerExpression.expressionInterfaceImpl.parent = &integerExpression integerExpression.ExpressionInterfaceImpl.Parent = &integerExpression
integerExpression.integerInterfaceImpl.parent = &integerExpression integerExpression.integerInterfaceImpl.parent = &integerExpression
integerExpression.binaryOpExpression = newBinaryExpression(lhs, rhs, operator) integerExpression.binaryOpExpression = newBinaryExpression(lhs, rhs, operator)
@ -150,7 +150,7 @@ func newBinaryIntegerExpression(lhs, rhs IntegerExpression, operator string) Int
//---------------------------------------------------// //---------------------------------------------------//
type prefixIntegerOpExpression struct { type prefixIntegerOpExpression struct {
expressionInterfaceImpl ExpressionInterfaceImpl
integerInterfaceImpl integerInterfaceImpl
prefixOpExpression prefixOpExpression
@ -160,7 +160,7 @@ func newPrefixIntegerOperator(expression IntegerExpression, operator string) Int
integerExpression := prefixIntegerOpExpression{} integerExpression := prefixIntegerOpExpression{}
integerExpression.prefixOpExpression = newPrefixExpression(expression, operator) integerExpression.prefixOpExpression = newPrefixExpression(expression, operator)
integerExpression.expressionInterfaceImpl.parent = &integerExpression integerExpression.ExpressionInterfaceImpl.Parent = &integerExpression
integerExpression.integerInterfaceImpl.parent = &integerExpression integerExpression.integerInterfaceImpl.parent = &integerExpression
return &integerExpression return &integerExpression
@ -168,7 +168,7 @@ func newPrefixIntegerOperator(expression IntegerExpression, operator string) Int
//---------------------------------------------------// //---------------------------------------------------//
type prefixFloatOpExpression struct { type prefixFloatOpExpression struct {
expressionInterfaceImpl ExpressionInterfaceImpl
floatInterfaceImpl floatInterfaceImpl
prefixOpExpression prefixOpExpression
@ -178,7 +178,7 @@ func newPrefixFloatOperator(expression FloatExpression, operator string) FloatEx
floatOpExpression := prefixFloatOpExpression{} floatOpExpression := prefixFloatOpExpression{}
floatOpExpression.prefixOpExpression = newPrefixExpression(expression, operator) floatOpExpression.prefixOpExpression = newPrefixExpression(expression, operator)
floatOpExpression.expressionInterfaceImpl.parent = &floatOpExpression floatOpExpression.ExpressionInterfaceImpl.Parent = &floatOpExpression
floatOpExpression.floatInterfaceImpl.parent = &floatOpExpression floatOpExpression.floatInterfaceImpl.parent = &floatOpExpression
return &floatOpExpression return &floatOpExpression

View file

@ -15,7 +15,7 @@ type LiteralExpression interface {
} }
type literalExpressionImpl struct { type literalExpressionImpl struct {
expressionInterfaceImpl ExpressionInterfaceImpl
noOpVisitorImpl noOpVisitorImpl
value interface{} value interface{}
@ -29,7 +29,7 @@ func literal(value interface{}, optionalConstant ...bool) *literalExpressionImpl
exp.constant = optionalConstant[0] exp.constant = optionalConstant[0]
} }
exp.expressionInterfaceImpl.parent = &exp exp.ExpressionInterfaceImpl.Parent = &exp
return &exp return &exp
} }
@ -73,7 +73,7 @@ func Int(value int64, constant ...bool) IntegerExpression {
numLiteral.constant = true numLiteral.constant = true
} }
numLiteral.literalExpressionImpl.parent = numLiteral numLiteral.literalExpressionImpl.Parent = numLiteral
numLiteral.integerInterfaceImpl.parent = numLiteral numLiteral.integerInterfaceImpl.parent = numLiteral
return numLiteral return numLiteral
@ -204,14 +204,14 @@ func DateT(t time.Time) DateExpression {
//--------------------------------------------------// //--------------------------------------------------//
type nullLiteral struct { type nullLiteral struct {
expressionInterfaceImpl ExpressionInterfaceImpl
noOpVisitorImpl noOpVisitorImpl
} }
func newNullLiteral() Expression { func newNullLiteral() Expression {
nullExpression := &nullLiteral{} nullExpression := &nullLiteral{}
nullExpression.expressionInterfaceImpl.parent = nullExpression nullExpression.ExpressionInterfaceImpl.Parent = nullExpression
return nullExpression return nullExpression
} }
@ -223,14 +223,14 @@ func (n *nullLiteral) serialize(statement StatementType, out *SqlBuilder, option
//--------------------------------------------------// //--------------------------------------------------//
type starLiteral struct { type starLiteral struct {
expressionInterfaceImpl ExpressionInterfaceImpl
noOpVisitorImpl noOpVisitorImpl
} }
func newStarLiteral() Expression { func newStarLiteral() Expression {
starExpression := &starLiteral{} starExpression := &starLiteral{}
starExpression.expressionInterfaceImpl.parent = starExpression starExpression.ExpressionInterfaceImpl.Parent = starExpression
return starExpression return starExpression
} }
@ -243,7 +243,7 @@ func (n *starLiteral) serialize(statement StatementType, out *SqlBuilder, option
//---------------------------------------------------// //---------------------------------------------------//
type wrap struct { type wrap struct {
expressionInterfaceImpl ExpressionInterfaceImpl
expressions []Expression expressions []Expression
} }
@ -263,7 +263,7 @@ func (n *wrap) serialize(statement StatementType, out *SqlBuilder, options ...Se
// WRAP wraps list of expressions with brackets '(' and ')' // WRAP wraps list of expressions with brackets '(' and ')'
func WRAP(expression ...Expression) Expression { func WRAP(expression ...Expression) Expression {
wrap := &wrap{expressions: expression} wrap := &wrap{expressions: expression}
wrap.expressionInterfaceImpl.parent = wrap wrap.ExpressionInterfaceImpl.Parent = wrap
return wrap return wrap
} }
@ -271,7 +271,7 @@ func WRAP(expression ...Expression) Expression {
//---------------------------------------------------// //---------------------------------------------------//
type rawExpression struct { type rawExpression struct {
expressionInterfaceImpl ExpressionInterfaceImpl
noOpVisitorImpl noOpVisitorImpl
raw string raw string
@ -286,7 +286,7 @@ func (n *rawExpression) serialize(statement StatementType, out *SqlBuilder, opti
// For example: Raw("current_database()") // For example: Raw("current_database()")
func Raw(raw string) Expression { func Raw(raw string) Expression {
rawExp := &rawExpression{raw: raw} rawExp := &rawExpression{raw: raw}
rawExp.expressionInterfaceImpl.parent = rawExp rawExp.ExpressionInterfaceImpl.Parent = rawExp
return rawExp return rawExp
} }

View file

@ -71,7 +71,7 @@ type CaseOperator interface {
} }
type caseOperatorImpl struct { type caseOperatorImpl struct {
expressionInterfaceImpl ExpressionInterfaceImpl
expression Expression expression Expression
when []Expression when []Expression
@ -87,7 +87,7 @@ func CASE(expression ...Expression) CaseOperator {
caseExp.expression = expression[0] caseExp.expression = expression[0]
} }
caseExp.expressionInterfaceImpl.parent = caseExp caseExp.ExpressionInterfaceImpl.Parent = caseExp
return caseExp return caseExp
} }

View file

@ -3,7 +3,7 @@ package jet
import "errors" import "errors"
// OrderByClause // OrderByClause
type orderByClause interface { type OrderByClause interface {
serializeForOrderBy(statement StatementType, out *SqlBuilder) error serializeForOrderBy(statement StatementType, out *SqlBuilder) error
} }
@ -30,6 +30,6 @@ func (o *orderByClauseImpl) serializeForOrderBy(statement StatementType, out *Sq
return nil return nil
} }
func newOrderByClause(expression Expression, ascent bool) orderByClause { func newOrderByClause(expression Expression, ascent bool) OrderByClause {
return &orderByClauseImpl{expression: expression, ascent: ascent} return &orderByClauseImpl{expression: expression, ascent: ascent}
} }

View file

@ -10,14 +10,14 @@ import (
// SelectStatement is interface for SQL SELECT statements // SelectStatement is interface for SQL SELECT statements
type SelectStatement interface { type SelectStatement interface {
Statement Statement
expression IExpression
DISTINCT() SelectStatement DISTINCT() SelectStatement
FROM(table ReadableTable) SelectStatement FROM(table ReadableTable) SelectStatement
WHERE(expression BoolExpression) SelectStatement WHERE(expression BoolExpression) SelectStatement
GROUP_BY(groupByClauses ...groupByClause) SelectStatement GROUP_BY(groupByClauses ...GroupByClause) SelectStatement
HAVING(boolExpression BoolExpression) SelectStatement HAVING(boolExpression BoolExpression) SelectStatement
ORDER_BY(orderByClauses ...orderByClause) SelectStatement ORDER_BY(orderByClauses ...OrderByClause) SelectStatement
LIMIT(limit int64) SelectStatement LIMIT(limit int64) SelectStatement
OFFSET(offset int64) SelectStatement OFFSET(offset int64) SelectStatement
FOR(lock SelectLock) SelectStatement FOR(lock SelectLock) SelectStatement
@ -40,17 +40,17 @@ func SELECT(projection1 Projection, projections ...Projection) SelectStatement {
} }
type selectStatementImpl struct { type selectStatementImpl struct {
expressionInterfaceImpl ExpressionInterfaceImpl
parent SelectStatement parent SelectStatement
table ReadableTable table ReadableTable
distinct bool distinct bool
projectionList []Projection projectionList []Projection
where BoolExpression where BoolExpression
groupBy []groupByClause groupBy []GroupByClause
having BoolExpression having BoolExpression
orderBy []orderByClause orderBy []OrderByClause
limit, offset int64 limit, offset int64
lockFor SelectLock lockFor SelectLock
@ -65,7 +65,7 @@ func newSelectStatement(table ReadableTable, projections []Projection) SelectSta
distinct: false, distinct: false,
} }
newSelect.expressionInterfaceImpl.parent = newSelect newSelect.ExpressionInterfaceImpl.Parent = newSelect
newSelect.parent = newSelect newSelect.parent = newSelect
return newSelect return newSelect
@ -77,7 +77,8 @@ func (s *selectStatementImpl) FROM(table ReadableTable) SelectStatement {
} }
func (s *selectStatementImpl) AsTable(alias string) SelectTable { func (s *selectStatementImpl) AsTable(alias string) SelectTable {
return newSelectTable(s.parent, alias) //return newSelectTable(s.parent, alias)
panic("UNimplemented.")
} }
func (s *selectStatementImpl) WHERE(expression BoolExpression) SelectStatement { func (s *selectStatementImpl) WHERE(expression BoolExpression) SelectStatement {
@ -85,7 +86,7 @@ func (s *selectStatementImpl) WHERE(expression BoolExpression) SelectStatement {
return s.parent return s.parent
} }
func (s *selectStatementImpl) GROUP_BY(groupByClauses ...groupByClause) SelectStatement { func (s *selectStatementImpl) GROUP_BY(groupByClauses ...GroupByClause) SelectStatement {
s.groupBy = groupByClauses s.groupBy = groupByClauses
return s.parent return s.parent
} }
@ -95,7 +96,7 @@ func (s *selectStatementImpl) HAVING(expression BoolExpression) SelectStatement
return s.parent return s.parent
} }
func (s *selectStatementImpl) ORDER_BY(clauses ...orderByClause) SelectStatement { func (s *selectStatementImpl) ORDER_BY(clauses ...OrderByClause) SelectStatement {
s.orderBy = clauses s.orderBy = clauses
return s.parent return s.parent
} }
@ -308,7 +309,7 @@ func (s *selectStatementImpl) ExecContext(context context.Context, db execution.
// SelectLock is interface for SELECT statement locks // SelectLock is interface for SELECT statement locks
type SelectLock interface { type SelectLock interface {
Clause Serializer
NOWAIT() SelectLock NOWAIT() SelectLock
SKIP_LOCKED() SelectLock SKIP_LOCKED() SelectLock

View file

@ -1,72 +1,70 @@
package jet package jet
import "errors" //// SelectTable is interface for SELECT sub-queries
//type SelectTable interface {
// SelectTable is interface for SELECT sub-queries // ReadableTable
type SelectTable interface { //
ReadableTable // Alias() string
//
Alias() string // AllColumns() ProjectionList
//}
AllColumns() ProjectionList //
} //type selectTableImpl struct {
// readableTableInterfaceImpl
type selectTableImpl struct { // selectStmt SelectStatement
readableTableInterfaceImpl // alias string
selectStmt SelectStatement //
alias string // projections []Projection
//}
projections []Projection //
} //func newSelectTable(selectStmt SelectStatement, alias string) SelectTable {
// expTable := &selectTableImpl{selectStmt: selectStmt, alias: alias}
func newSelectTable(selectStmt SelectStatement, alias string) SelectTable { //
expTable := &selectTableImpl{selectStmt: selectStmt, alias: alias} // expTable.readableTableInterfaceImpl.parent = expTable
//
expTable.readableTableInterfaceImpl.parent = expTable // for _, projection := range selectStmt.projections() {
// newProjection := projection.fromImpl(expTable)
for _, projection := range selectStmt.projections() { //
newProjection := projection.fromImpl(expTable) // expTable.projections = append(expTable.projections, newProjection)
// }
expTable.projections = append(expTable.projections, newProjection) //
} // return expTable
//}
return expTable //
} //func (s *selectTableImpl) Alias() string {
// return s.alias
func (s *selectTableImpl) Alias() string { //}
return s.alias //
} //func (s *selectTableImpl) columns() []IColumn {
// return nil
func (s *selectTableImpl) columns() []IColumn { //}
return nil //
} //func (s *selectTableImpl) accept(visitor visitor) {
// visitor.visit(s)
func (s *selectTableImpl) accept(visitor visitor) { // s.selectStmt.accept(visitor)
visitor.visit(s) //}
s.selectStmt.accept(visitor) //
} //func (s *selectTableImpl) dialect() Dialect {
// return detectDialect(s.selectStmt)
func (s *selectTableImpl) dialect() Dialect { //}
return detectDialect(s.selectStmt) //
} //func (s *selectTableImpl) AllColumns() ProjectionList {
// return s.projections
func (s *selectTableImpl) AllColumns() ProjectionList { //}
return s.projections //
} //func (s *selectTableImpl) serialize(statement StatementType, out *SqlBuilder, options ...SerializeOption) error {
// if s == nil {
func (s *selectTableImpl) serialize(statement StatementType, out *SqlBuilder, options ...SerializeOption) error { // return errors.New("jet: Expression table is nil. ")
if s == nil { // }
return errors.New("jet: Expression table is nil. ") //
} // err := s.selectStmt.serialize(statement, out)
//
err := s.selectStmt.serialize(statement, out) // if err != nil {
// return err
if err != nil { // }
return err //
} // out.WriteString("AS")
// out.writeIdentifier(s.alias)
out.WriteString("AS") //
out.writeIdentifier(s.alias) // return nil
//}
return nil
}

View file

@ -0,0 +1,36 @@
package jet
type SerializeOption int
const (
noWrap SerializeOption = iota
)
type StatementType string
const (
SelectStatementType StatementType = "SELECT"
InsertStatementType StatementType = "INSERT"
UpdateStatementType StatementType = "UPDATE"
DeleteStatementType StatementType = "DELETE"
SetStatementType StatementType = "SET"
LockStatementType StatementType = "LOCK"
)
type Serializer interface {
serialize(statement StatementType, out *SqlBuilder, options ...SerializeOption) error
}
func Serialize(exp Serializer, statementType StatementType, out *SqlBuilder, options ...SerializeOption) error {
return exp.serialize(statementType, out, options...)
}
func contains(options []SerializeOption, option SerializeOption) bool {
for _, opt := range options {
if opt == option {
return true
}
}
return false
}

View file

@ -66,7 +66,7 @@ func newSetStatementImpl(operator string, all bool, selects []SelectStatement) S
selects: selects, selects: selects,
} }
setStatement.selectStatementImpl.expressionInterfaceImpl.parent = setStatement setStatement.selectStatementImpl.ExpressionInterfaceImpl.Parent = setStatement
setStatement.selectStatementImpl.parent = setStatement setStatement.selectStatementImpl.parent = setStatement
setStatement.limit = -1 setStatement.limit = -1
setStatement.offset = -1 setStatement.offset = -1

235
internal/jet/sql_builder.go Normal file
View file

@ -0,0 +1,235 @@
package jet
import (
"bytes"
"github.com/go-jet/jet/internal/utils"
"github.com/google/uuid"
"strconv"
"strings"
"time"
)
type SqlBuilder struct {
Dialect Dialect
Buff bytes.Buffer
Args []interface{}
lastChar byte
ident int
}
func (s *SqlBuilder) DebugSQL() string {
return queryStringToDebugString(s.Buff.String(), s.Args, s.Dialect)
}
const defaultIdent = 5
func (q *SqlBuilder) increaseIdent() {
q.ident += defaultIdent
}
func (q *SqlBuilder) decreaseIdent() {
if q.ident < defaultIdent {
q.ident = 0
}
q.ident -= defaultIdent
}
func (q *SqlBuilder) writeProjections(statement StatementType, projections []Projection) error {
q.increaseIdent()
err := SerializeProjectionList(statement, projections, q)
q.decreaseIdent()
return err
}
func (q *SqlBuilder) writeFrom(statement StatementType, table Serializer) error {
q.newLine()
q.WriteString("FROM")
q.increaseIdent()
err := table.serialize(statement, q)
q.decreaseIdent()
return err
}
func (q *SqlBuilder) writeWhere(statement StatementType, where Expression) error {
q.newLine()
q.WriteString("WHERE")
q.increaseIdent()
err := where.serialize(statement, q, noWrap)
q.decreaseIdent()
return err
}
func (q *SqlBuilder) writeGroupBy(statement StatementType, groupBy []GroupByClause) error {
q.newLine()
q.WriteString("GROUP BY")
q.increaseIdent()
err := serializeGroupByClauseList(statement, groupBy, q)
q.decreaseIdent()
return err
}
func (q *SqlBuilder) writeOrderBy(statement StatementType, orderBy []OrderByClause) error {
q.newLine()
q.WriteString("ORDER BY")
q.increaseIdent()
err := serializeOrderByClauseList(statement, orderBy, q)
q.decreaseIdent()
return err
}
func (q *SqlBuilder) writeHaving(statement StatementType, having Expression) error {
q.newLine()
q.WriteString("HAVING")
q.increaseIdent()
err := having.serialize(statement, q, noWrap)
q.decreaseIdent()
return err
}
func (q *SqlBuilder) WriteReturning(statement StatementType, returning []Projection) error {
if len(returning) == 0 {
return nil
}
if !q.Dialect.SupportsReturning() {
panic("jet: " + q.Dialect.Name() + " dialect does not support RETURNING.")
}
q.newLine()
q.WriteString("RETURNING")
q.increaseIdent()
return q.writeProjections(statement, returning)
}
func (q *SqlBuilder) newLine() {
q.write([]byte{'\n'})
q.write(bytes.Repeat([]byte{' '}, q.ident))
}
func (q *SqlBuilder) write(data []byte) {
if len(data) == 0 {
return
}
if !isPreSeparator(q.lastChar) && !isPostSeparator(data[0]) && q.Buff.Len() > 0 {
q.Buff.WriteByte(' ')
}
q.Buff.Write(data)
q.lastChar = data[len(data)-1]
}
func isPreSeparator(b byte) bool {
return b == ' ' || b == '.' || b == ',' || b == '(' || b == '\n' || b == ':'
}
func isPostSeparator(b byte) bool {
return b == ' ' || b == '.' || b == ',' || b == ')' || b == '\n' || b == ':'
}
func (q *SqlBuilder) writeAlias(str string) {
aliasQuoteChar := string(q.Dialect.AliasQuoteChar())
q.WriteString(aliasQuoteChar + str + aliasQuoteChar)
}
func (q *SqlBuilder) WriteString(str string) {
q.write([]byte(str))
}
func (q *SqlBuilder) writeIdentifier(name string, alwaysQuote ...bool) {
quoteWrap := name != strings.ToLower(name) || strings.ContainsAny(name, ". -")
if quoteWrap || len(alwaysQuote) > 0 {
identQuoteChar := string(q.Dialect.IdentifierQuoteChar())
q.WriteString(identQuoteChar + name + identQuoteChar)
} else {
q.WriteString(name)
}
}
func (q *SqlBuilder) writeByte(b byte) {
q.write([]byte{b})
}
func (q *SqlBuilder) finalize() (string, []interface{}) {
return q.Buff.String() + ";\n", q.Args
}
func (q *SqlBuilder) insertConstantArgument(arg interface{}) {
q.WriteString(argToString(arg))
}
func (q *SqlBuilder) insertParametrizedArgument(arg interface{}) {
q.Args = append(q.Args, arg)
argPlaceholder := q.Dialect.ArgumentPlaceholder()(len(q.Args))
q.WriteString(argPlaceholder)
}
func argToString(value interface{}) string {
if utils.IsNil(value) {
return "NULL"
}
switch bindVal := value.(type) {
case bool:
if bindVal {
return "TRUE"
}
return "FALSE"
case int8:
return strconv.FormatInt(int64(bindVal), 10)
case int:
return strconv.FormatInt(int64(bindVal), 10)
case int16:
return strconv.FormatInt(int64(bindVal), 10)
case int32:
return strconv.FormatInt(int64(bindVal), 10)
case int64:
return strconv.FormatInt(int64(bindVal), 10)
case uint8:
return strconv.FormatUint(uint64(bindVal), 10)
case uint:
return strconv.FormatUint(uint64(bindVal), 10)
case uint16:
return strconv.FormatUint(uint64(bindVal), 10)
case uint32:
return strconv.FormatUint(uint64(bindVal), 10)
case uint64:
return strconv.FormatUint(uint64(bindVal), 10)
case float32:
return strconv.FormatFloat(float64(bindVal), 'f', -1, 64)
case float64:
return strconv.FormatFloat(float64(bindVal), 'f', -1, 64)
case string:
return stringQuote(bindVal)
case []byte:
return stringQuote(string(bindVal))
case uuid.UUID:
return stringQuote(bindVal.String())
case time.Time:
return stringQuote(string(utils.FormatTimestamp(bindVal)))
default:
return "[Unsupported type]"
}
}
func stringQuote(value string) string {
return `'` + strings.Replace(value, "'", "''", -1) + `'`
}

View file

@ -3,6 +3,7 @@ package jet
import ( import (
"context" "context"
"database/sql" "database/sql"
"errors"
"github.com/go-jet/jet/execution" "github.com/go-jet/jet/execution"
"strings" "strings"
) )
@ -31,9 +32,66 @@ type Statement interface {
ExecContext(context context.Context, db execution.DB) (sql.Result, error) ExecContext(context context.Context, db execution.DB) (sql.Result, error)
} }
type SerializerStatement interface {
Serializer
Statement
}
type StatementWithProjections interface {
Statement
HasProjections
Serializer
}
type HasProjections interface {
projections() []Projection
}
type SerializerStatementInterfaceImpl struct {
noOpVisitorImpl
Parent SerializerStatement
Dialect Dialect
StatementType StatementType
}
func (s *SerializerStatementInterfaceImpl) Sql(dialect ...Dialect) (query string, args []interface{}, err error) {
queryData := &SqlBuilder{Dialect: s.Dialect}
err = s.Parent.serialize(s.StatementType, queryData, noWrap)
if err != nil {
return "", nil, err
}
query, args = queryData.finalize()
return
}
func (s *SerializerStatementInterfaceImpl) DebugSql(dialect ...Dialect) (query string, err error) {
return debugSql(s.Parent, s.Dialect)
}
func (s *SerializerStatementInterfaceImpl) Query(db execution.DB, destination interface{}) error {
return query(s.Parent, db, destination)
}
func (s *SerializerStatementInterfaceImpl) QueryContext(context context.Context, db execution.DB, destination interface{}) error {
return queryContext(context, s.Parent, db, destination)
}
func (s *SerializerStatementInterfaceImpl) Exec(db execution.DB) (res sql.Result, err error) {
return exec(s.Parent, db)
}
func (s *SerializerStatementInterfaceImpl) ExecContext(context context.Context, db execution.DB) (res sql.Result, err error) {
return execContext(context, s.Parent, db)
}
func debugSql(statement Statement, overrideDialect ...Dialect) (string, error) { func debugSql(statement Statement, overrideDialect ...Dialect) (string, error) {
dialect := detectDialect(statement, overrideDialect...) dialect := detectDialect(statement, overrideDialect...)
sqlQuery, args, err := statement.Sql() sqlQuery, args, err := statement.Sql(dialect)
if err != nil { if err != nil {
return "", err return "", err
@ -100,3 +158,68 @@ func execContext(context context.Context, statement Statement, db execution.DB)
return db.ExecContext(context, query, args...) return db.ExecContext(context, query, args...)
} }
type ExpressionStatementImpl struct {
ExpressionInterfaceImpl
StatementImpl
}
func (s *ExpressionStatementImpl) serializeForProjection(statement StatementType, out *SqlBuilder) error {
return s.serialize(statement, out)
}
func NewStatementImpl(Dialect Dialect, statementType StatementType, parent SerializerStatement, clauses ...Clause) StatementImpl {
return StatementImpl{
SerializerStatementInterfaceImpl: SerializerStatementInterfaceImpl{
Parent: parent,
Dialect: Dialect,
StatementType: statementType,
},
Clauses: clauses,
}
}
type StatementImpl struct {
SerializerStatementInterfaceImpl
acceptsVisitor
Clauses []Clause
}
func (s *StatementImpl) projections() []Projection {
for _, clause := range s.Clauses {
if selectClause, ok := clause.(ClauseWithProjections); ok {
return selectClause.projections()
}
}
return nil
}
func (s *StatementImpl) serialize(statement StatementType, out *SqlBuilder, options ...SerializeOption) error {
if s == nil {
return errors.New("jet: Select expression is nil. ")
}
if !contains(options, noWrap) {
out.WriteString("(")
out.increaseIdent()
}
for _, clause := range s.Clauses {
err := clause.Serialize(statement, out)
if err != nil {
return err
}
}
if !contains(options, noWrap) {
out.decreaseIdent()
out.newLine()
out.WriteString(")")
}
return nil
}

View file

@ -80,7 +80,7 @@ func (s *stringInterfaceImpl) REGEXP_LIKE(pattern StringExpression, matchType ..
//---------------------------------------------------// //---------------------------------------------------//
type binaryStringExpression struct { type binaryStringExpression struct {
expressionInterfaceImpl ExpressionInterfaceImpl
stringInterfaceImpl stringInterfaceImpl
binaryOpExpression binaryOpExpression
@ -90,7 +90,7 @@ func newBinaryStringExpression(lhs, rhs Expression, operator string) StringExpre
boolExpression := binaryStringExpression{} boolExpression := binaryStringExpression{}
boolExpression.binaryOpExpression = newBinaryExpression(lhs, rhs, operator) boolExpression.binaryOpExpression = newBinaryExpression(lhs, rhs, operator)
boolExpression.expressionInterfaceImpl.parent = &boolExpression boolExpression.ExpressionInterfaceImpl.Parent = &boolExpression
boolExpression.stringInterfaceImpl.parent = &boolExpression boolExpression.stringInterfaceImpl.parent = &boolExpression
return &boolExpression return &boolExpression

View file

@ -5,7 +5,19 @@ import (
"github.com/go-jet/jet/internal/utils" "github.com/go-jet/jet/internal/utils"
) )
type table interface { type SerializerTable interface {
Serializer
Columns() []IColumn
//SchemaName() string
//TableName() string
//AS(alias string)
}
type TableInterface interface {
Columns() []IColumn
}
type TableBase interface {
dialect() Dialect dialect() Dialect
columns() []IColumn columns() []IColumn
} }
@ -40,26 +52,26 @@ type writableTable interface {
// ReadableTable interface // ReadableTable interface
type ReadableTable interface { type ReadableTable interface {
table TableBase
readableTable readableTable
Clause Serializer
acceptsVisitor acceptsVisitor
} }
// WritableTable interface // WritableTable interface
type WritableTable interface { type WritableTable interface {
table TableBase
writableTable writableTable
Clause Serializer
acceptsVisitor acceptsVisitor
} }
// Table interface // Table interface
type Table interface { type Table interface {
table TableBase
readableTable readableTable
writableTable writableTable
Clause Serializer
acceptsVisitor acceptsVisitor
SchemaName() string SchemaName() string
@ -78,25 +90,25 @@ func (r *readableTableInterfaceImpl) SELECT(projection1 Projection, projections
// Creates a inner join tableName Expression using onCondition. // Creates a inner join tableName Expression using onCondition.
func (r *readableTableInterfaceImpl) INNER_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable { func (r *readableTableInterfaceImpl) INNER_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable {
return newJoinTable(r.parent, table, innerJoin, onCondition) return newJoinTable(r.parent, table, InnerJoin, onCondition)
} }
// Creates a left join tableName Expression using onCondition. // Creates a left join tableName Expression using onCondition.
func (r *readableTableInterfaceImpl) LEFT_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable { func (r *readableTableInterfaceImpl) LEFT_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable {
return newJoinTable(r.parent, table, leftJoin, onCondition) return newJoinTable(r.parent, table, LeftJoin, onCondition)
} }
// Creates a right join tableName Expression using onCondition. // Creates a right join tableName Expression using onCondition.
func (r *readableTableInterfaceImpl) RIGHT_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable { func (r *readableTableInterfaceImpl) RIGHT_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable {
return newJoinTable(r.parent, table, rightJoin, onCondition) return newJoinTable(r.parent, table, RightJoin, onCondition)
} }
func (r *readableTableInterfaceImpl) FULL_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable { func (r *readableTableInterfaceImpl) FULL_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable {
return newJoinTable(r.parent, table, fullJoin, onCondition) return newJoinTable(r.parent, table, FullJoin, onCondition)
} }
func (r *readableTableInterfaceImpl) CROSS_JOIN(table ReadableTable) ReadableTable { func (r *readableTableInterfaceImpl) CROSS_JOIN(table ReadableTable) ReadableTable {
return newJoinTable(r.parent, table, crossJoin, nil) return newJoinTable(r.parent, table, CrossJoin, nil)
} }
type writableTableInterfaceImpl struct { type writableTableInterfaceImpl struct {
@ -104,11 +116,11 @@ type writableTableInterfaceImpl struct {
} }
func (w *writableTableInterfaceImpl) INSERT(columns ...IColumn) InsertStatement { func (w *writableTableInterfaceImpl) INSERT(columns ...IColumn) InsertStatement {
return newInsertStatement(w.parent, unwidColumnList(columns)) return newInsertStatement(w.parent, UnwidColumnList(columns))
} }
func (w *writableTableInterfaceImpl) UPDATE(column IColumn, columns ...IColumn) UpdateStatement { func (w *writableTableInterfaceImpl) UPDATE(column IColumn, columns ...IColumn) UpdateStatement {
return newUpdateStatement(w.parent, unwindColumns(column, columns...)) return newUpdateStatement(w.parent, UnwindColumns(column, columns...))
} }
func (w *writableTableInterfaceImpl) DELETE() DeleteStatement { func (w *writableTableInterfaceImpl) DELETE() DeleteStatement {
@ -200,14 +212,14 @@ func (t *tableImpl) serialize(statement StatementType, out *SqlBuilder, options
return nil return nil
} }
type joinType int type JoinType int
const ( const (
innerJoin joinType = iota InnerJoin JoinType = iota
leftJoin LeftJoin
rightJoin RightJoin
fullJoin FullJoin
crossJoin CrossJoin
) )
// Join expressions are pseudo readable tables. // Join expressions are pseudo readable tables.
@ -216,15 +228,15 @@ type joinTable struct {
lhs ReadableTable lhs ReadableTable
rhs ReadableTable rhs ReadableTable
joinType joinType joinType JoinType
onCondition BoolExpression onCondition BoolExpression
} }
func newJoinTable( func newJoinTable(
lhs ReadableTable, lhs ReadableTable,
rhs ReadableTable, rhs ReadableTable,
joinType joinType, joinType JoinType,
onCondition BoolExpression) ReadableTable { onCondition BoolExpression) *joinTable {
joinTable := &joinTable{ joinTable := &joinTable{
lhs: lhs, lhs: lhs,
@ -275,15 +287,15 @@ func (t *joinTable) serialize(statement StatementType, out *SqlBuilder, options
out.newLine() out.newLine()
switch t.joinType { switch t.joinType {
case innerJoin: case InnerJoin:
out.WriteString("INNER JOIN") out.WriteString("INNER JOIN")
case leftJoin: case LeftJoin:
out.WriteString("LEFT JOIN") out.WriteString("LEFT JOIN")
case rightJoin: case RightJoin:
out.WriteString("RIGHT JOIN") out.WriteString("RIGHT JOIN")
case fullJoin: case FullJoin:
out.WriteString("FULL JOIN") out.WriteString("FULL JOIN")
case crossJoin: case CrossJoin:
out.WriteString("CROSS JOIN") out.WriteString("CROSS JOIN")
} }
@ -295,7 +307,7 @@ func (t *joinTable) serialize(statement StatementType, out *SqlBuilder, options
return return
} }
if t.onCondition == nil && t.joinType != crossJoin { if t.onCondition == nil && t.joinType != CrossJoin {
return errors.New("jet: join condition is nil") return errors.New("jet: join condition is nil")
} }
@ -309,7 +321,7 @@ func (t *joinTable) serialize(statement StatementType, out *SqlBuilder, options
return nil return nil
} }
func unwindColumns(column1 IColumn, columns ...IColumn) []IColumn { func UnwindColumns(column1 IColumn, columns ...IColumn) []IColumn {
columnList := []IColumn{} columnList := []IColumn{}
if val, ok := column1.(IColumnList); ok { if val, ok := column1.(IColumnList); ok {
@ -325,7 +337,7 @@ func unwindColumns(column1 IColumn, columns ...IColumn) []IColumn {
return columnList return columnList
} }
func unwidColumnList(columns []IColumn) []IColumn { func UnwidColumnList(columns []IColumn) []IColumn {
ret := []IColumn{} ret := []IColumn{}
for _, col := range columns { for _, col := range columns {

View file

@ -72,7 +72,7 @@ var table3 = NewTable(
table3ColInt, table3ColInt,
table3StrCol) table3StrCol)
func assertClauseSerialize(t *testing.T, clause Clause, query string, args ...interface{}) { func assertClauseSerialize(t *testing.T, clause Serializer, query string, args ...interface{}) {
out := SqlBuilder{Dialect: ANSII} out := SqlBuilder{Dialect: ANSII}
err := clause.serialize(SelectStatementType, &out) err := clause.serialize(SelectStatementType, &out)
@ -82,7 +82,7 @@ func assertClauseSerialize(t *testing.T, clause Clause, query string, args ...in
assert.DeepEqual(t, out.Args, args) assert.DeepEqual(t, out.Args, args)
} }
func assertClauseSerializeErr(t *testing.T, clause Clause, errString string) { func assertClauseSerializeErr(t *testing.T, clause Serializer, errString string) {
out := SqlBuilder{Dialect: ANSII} out := SqlBuilder{Dialect: ANSII}
err := clause.serialize(SelectStatementType, &out) err := clause.serialize(SelectStatementType, &out)

View file

@ -53,7 +53,7 @@ func (t *timeInterfaceImpl) GT_EQ(rhs TimeExpression) BoolExpression {
//---------------------------------------------------// //---------------------------------------------------//
type prefixTimeExpression struct { type prefixTimeExpression struct {
expressionInterfaceImpl ExpressionInterfaceImpl
timeInterfaceImpl timeInterfaceImpl
prefixOpExpression prefixOpExpression
@ -63,8 +63,8 @@ type prefixTimeExpression struct {
// timeExpr := prefixTimeExpression{} // timeExpr := prefixTimeExpression{}
// timeExpr.prefixOpExpression = newPrefixExpression(expression, operator) // timeExpr.prefixOpExpression = newPrefixExpression(expression, operator)
// //
// timeExpr.expressionInterfaceImpl.parent = &timeExpr // timeExpr.ExpressionInterfaceImpl.Parent = &timeExpr
// timeExpr.timeInterfaceImpl.parent = &timeExpr // timeExpr.timeInterfaceImpl.Parent = &timeExpr
// //
// return &timeExpr // return &timeExpr
//} //}

View file

@ -54,7 +54,7 @@ func (t *timestampzInterfaceImpl) GT_EQ(rhs TimestampzExpression) BoolExpression
//---------------------------------------------------// //---------------------------------------------------//
type prefixTimestampzOperator struct { type prefixTimestampzOperator struct {
expressionInterfaceImpl ExpressionInterfaceImpl
timestampzInterfaceImpl timestampzInterfaceImpl
prefixOpExpression prefixOpExpression
@ -64,7 +64,7 @@ func NewPrefixTimestampOperator(operator string, expression Expression) Timestam
timeExpr := prefixTimestampzOperator{} timeExpr := prefixTimestampzOperator{}
timeExpr.prefixOpExpression = newPrefixExpression(expression, operator) timeExpr.prefixOpExpression = newPrefixExpression(expression, operator)
timeExpr.expressionInterfaceImpl.parent = &timeExpr timeExpr.ExpressionInterfaceImpl.Parent = &timeExpr
timeExpr.timestampzInterfaceImpl.parent = &timeExpr timeExpr.timestampzInterfaceImpl.parent = &timeExpr
return &timeExpr return &timeExpr

View file

@ -61,7 +61,7 @@ func (t *timezInterfaceImpl) GT_EQ(rhs TimezExpression) BoolExpression {
//---------------------------------------------------// //---------------------------------------------------//
type prefixTimezExpression struct { type prefixTimezExpression struct {
expressionInterfaceImpl ExpressionInterfaceImpl
timezInterfaceImpl timezInterfaceImpl
prefixOpExpression prefixOpExpression
@ -71,8 +71,8 @@ type prefixTimezExpression struct {
// timeExpr := prefixTimezExpression{} // timeExpr := prefixTimezExpression{}
// timeExpr.prefixOpExpression = newPrefixExpression(expression, operator) // timeExpr.prefixOpExpression = newPrefixExpression(expression, operator)
// //
// timeExpr.expressionInterfaceImpl.parent = &timeExpr // timeExpr.ExpressionInterfaceImpl.Parent = &timeExpr
// timeExpr.timezInterfaceImpl.parent = &timeExpr // timeExpr.timezInterfaceImpl.Parent = &timeExpr
// //
// return &timeExpr // return &timeExpr
//} //}

View file

@ -23,26 +23,26 @@ func newUpdateStatement(table WritableTable, columns []IColumn) UpdateStatement
return &updateStatementImpl{ return &updateStatementImpl{
table: table, table: table,
columns: columns, columns: columns,
values: make([]Clause, 0, len(columns)), values: make([]Serializer, 0, len(columns)),
} }
} }
type updateStatementImpl struct { type updateStatementImpl struct {
table WritableTable table WritableTable
columns []IColumn columns []IColumn
values []Clause values []Serializer
where BoolExpression where BoolExpression
returning []Projection returning []Projection
} }
func (u *updateStatementImpl) SET(value interface{}, values ...interface{}) UpdateStatement { func (u *updateStatementImpl) SET(value interface{}, values ...interface{}) UpdateStatement {
u.values = unwindRowFromValues(value, values) u.values = UnwindRowFromValues(value, values)
return u return u
} }
func (u *updateStatementImpl) MODEL(data interface{}) UpdateStatement { func (u *updateStatementImpl) MODEL(data interface{}) UpdateStatement {
u.values = unwindRowFromModel(u.columns, data) u.values = UnwindRowFromModel(u.columns, data)
return u return u
} }
@ -101,7 +101,7 @@ func (u *updateStatementImpl) Sql(dialect ...Dialect) (query string, args []inte
return return
} }
if err = out.writeReturning(UpdateStatementType, u.returning); err != nil { if err = out.WriteReturning(UpdateStatementType, u.returning); err != nil {
return return
} }

View file

@ -7,7 +7,7 @@ import (
"strings" "strings"
) )
func serializeOrderByClauseList(statement StatementType, orderByClauses []orderByClause, out *SqlBuilder) error { func serializeOrderByClauseList(statement StatementType, orderByClauses []OrderByClause, out *SqlBuilder) error {
for i, value := range orderByClauses { for i, value := range orderByClauses {
if i > 0 { if i > 0 {
@ -24,7 +24,7 @@ func serializeOrderByClauseList(statement StatementType, orderByClauses []orderB
return nil return nil
} }
func serializeGroupByClauseList(statement StatementType, clauses []groupByClause, out *SqlBuilder) (err error) { func serializeGroupByClauseList(statement StatementType, clauses []GroupByClause, out *SqlBuilder) (err error) {
for i, c := range clauses { for i, c := range clauses {
if i > 0 { if i > 0 {
@ -43,7 +43,7 @@ func serializeGroupByClauseList(statement StatementType, clauses []groupByClause
return nil return nil
} }
func SerializeClauseList(statement StatementType, clauses []Clause, out *SqlBuilder) (err error) { func SerializeClauseList(statement StatementType, clauses []Serializer, out *SqlBuilder) (err error) {
for i, c := range clauses { for i, c := range clauses {
if i > 0 { if i > 0 {
@ -124,18 +124,18 @@ func ColumnListToProjectionList(columns []Column) []Projection {
return ret return ret
} }
func valueToClause(value interface{}) Clause { func valueToClause(value interface{}) Serializer {
if clause, ok := value.(Clause); ok { if clause, ok := value.(Serializer); ok {
return clause return clause
} }
return literal(value) return literal(value)
} }
func unwindRowFromModel(columns []IColumn, data interface{}) []Clause { func UnwindRowFromModel(columns []IColumn, data interface{}) []Serializer {
structValue := reflect.Indirect(reflect.ValueOf(data)) structValue := reflect.Indirect(reflect.ValueOf(data))
row := []Clause{} row := []Serializer{}
mustBe(structValue, reflect.Struct) mustBe(structValue, reflect.Struct)
@ -163,23 +163,23 @@ func unwindRowFromModel(columns []IColumn, data interface{}) []Clause {
return row return row
} }
func unwindRowsFromModels(columns []IColumn, data interface{}) [][]Clause { func UnwindRowsFromModels(columns []IColumn, data interface{}) [][]Serializer {
sliceValue := reflect.Indirect(reflect.ValueOf(data)) sliceValue := reflect.Indirect(reflect.ValueOf(data))
mustBe(sliceValue, reflect.Slice) mustBe(sliceValue, reflect.Slice)
rows := [][]Clause{} rows := [][]Serializer{}
for i := 0; i < sliceValue.Len(); i++ { for i := 0; i < sliceValue.Len(); i++ {
structValue := sliceValue.Index(i) structValue := sliceValue.Index(i)
rows = append(rows, unwindRowFromModel(columns, structValue.Interface())) rows = append(rows, UnwindRowFromModel(columns, structValue.Interface()))
} }
return rows return rows
} }
func unwindRowFromValues(value interface{}, values []interface{}) []Clause { func UnwindRowFromValues(value interface{}, values []interface{}) []Serializer {
row := []Clause{} row := []Serializer{}
allValues := append([]interface{}{value}, values...) allValues := append([]interface{}{value}, values...)

View file

@ -45,7 +45,7 @@ func (f *DialectFinder) mustGetDialect() Dialect {
func (f *DialectFinder) visit(element acceptsVisitor) { func (f *DialectFinder) visit(element acceptsVisitor) {
if table, ok := element.(table); ok { if table, ok := element.(TableBase); ok {
dialect := table.dialect() dialect := table.dialect()
f.dialects[dialect.Name()] = dialect f.dialects[dialect.Name()] = dialect
} }

View file

@ -58,7 +58,7 @@ var table3 = NewTable(
table3ColInt, table3ColInt,
table3StrCol) 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} out := jet.SqlBuilder{Dialect: Dialect}
err := jet.Serialize(clause, jet.SelectStatementType, &out) err := jet.Serialize(clause, jet.SelectStatementType, &out)
@ -68,7 +68,7 @@ func assertClauseSerialize(t *testing.T, clause jet.Clause, query string, args .
assert.DeepEqual(t, out.Args, 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} out := jet.SqlBuilder{Dialect: Dialect}
err := jet.Serialize(clause, jet.SelectStatementType, &out) err := jet.Serialize(clause, jet.SelectStatementType, &out)

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

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

View file

@ -24,7 +24,7 @@ func NewDialect() jet.Dialect {
ArgumentPlaceholder: func(ord int) string { ArgumentPlaceholder: func(ord int) string {
return "$" + strconv.Itoa(ord) return "$" + strconv.Itoa(ord)
}, },
SetClause: postgresSetClause, //SetClause: postgresSetClause,
SupportsReturning: true, 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 { func postgres_REGEXP_LIKE_function(expressions ...jet.Expression) jet.SerializeFunc {
return func(statement jet.StatementType, out *jet.SqlBuilder, options ...jet.SerializeOption) error { return func(statement jet.StatementType, out *jet.SqlBuilder, options ...jet.SerializeOption) error {
if len(expressions) < 2 { if len(expressions) < 2 {

View file

@ -50,11 +50,11 @@ var RTRIM = jet.RTRIM
var CHR = jet.CHR var CHR = jet.CHR
var CONCAT = func(expressions ...Expression) StringExpression { var CONCAT = func(expressions ...Expression) StringExpression {
return jet.CONCAT(explicitCasts(expressions...)...) return jet.CONCAT(explicitLiteralCasts(expressions...)...)
} }
func CONCAT_WS(expressions ...Expression) StringExpression { func CONCAT_WS(expressions ...Expression) StringExpression {
return jet.CONCAT_WS(explicitCasts(expressions...)...) return jet.CONCAT_WS(explicitLiteralCasts(expressions...)...)
} }
var CONVERT = jet.CONVERT var CONVERT = jet.CONVERT
@ -64,7 +64,7 @@ var ENCODE = jet.ENCODE
var DECODE = jet.DECODE var DECODE = jet.DECODE
func FORMAT(formatStr StringExpression, formatArgs ...Expression) StringExpression { func FORMAT(formatStr StringExpression, formatArgs ...Expression) StringExpression {
return jet.FORMAT(formatStr, explicitCasts(formatArgs...)...) return jet.FORMAT(formatStr, explicitLiteralCasts(formatArgs...)...)
} }
var INITCAP = jet.INITCAP var INITCAP = jet.INITCAP
@ -107,17 +107,17 @@ var LEAST = jet.LEAST
var EXISTS = jet.EXISTS var EXISTS = jet.EXISTS
var CASE = jet.CASE var CASE = jet.CASE
func explicitCasts(expressions ...Expression) []jet.Expression { func explicitLiteralCasts(expressions ...Expression) []jet.Expression {
ret := []jet.Expression{} ret := []jet.Expression{}
for _, exp := range expressions { for _, exp := range expressions {
ret = append(ret, explicitCast(exp)) ret = append(ret, explicitLiteralCast(exp))
} }
return ret return ret
} }
func explicitCast(expresion Expression) jet.Expression { func explicitLiteralCast(expresion Expression) jet.Expression {
if _, ok := expresion.(jet.LiteralExpression); !ok { if _, ok := expresion.(jet.LiteralExpression); !ok {
return expresion return expresion
} }

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

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

View file

@ -2,20 +2,52 @@ package postgres
import "github.com/go-jet/jet/internal/jet" import "github.com/go-jet/jet/internal/jet"
type TableLockMode jet.TableLockMode type TableLockMode string
// Lock types for LockStatement. // Lock types for LockStatement.
const ( const (
LOCK_ACCESS_SHARE = "ACCESS SHARE" LOCK_ACCESS_SHARE TableLockMode = "ACCESS SHARE"
LOCK_ROW_SHARE = "ROW SHARE" LOCK_ROW_SHARE TableLockMode = "ROW SHARE"
LOCK_ROW_EXCLUSIVE = "ROW EXCLUSIVE" LOCK_ROW_EXCLUSIVE TableLockMode = "ROW EXCLUSIVE"
LOCK_SHARE_UPDATE_EXCLUSIVE = "SHARE UPDATE EXCLUSIVE" LOCK_SHARE_UPDATE_EXCLUSIVE TableLockMode = "SHARE UPDATE EXCLUSIVE"
LOCK_SHARE = "SHARE" LOCK_SHARE TableLockMode = "SHARE"
LOCK_SHARE_ROW_EXCLUSIVE = "SHARE ROW EXCLUSIVE" LOCK_SHARE_ROW_EXCLUSIVE TableLockMode = "SHARE ROW EXCLUSIVE"
LOCK_EXCLUSIVE = "EXCLUSIVE" LOCK_EXCLUSIVE TableLockMode = "EXCLUSIVE"
LOCK_ACCESS_EXCLUSIVE = "ACCESS 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
}

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

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

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

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

View file

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

View file

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

View file

@ -2,8 +2,145 @@ package postgres
import "github.com/go-jet/jet/internal/jet" 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 { 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
} }

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

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

View file

@ -70,7 +70,7 @@ var table3 = NewTable(
table3ColInt, table3ColInt,
table3StrCol) 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} out := jet.SqlBuilder{Dialect: Dialect}
err := jet.Serialize(clause, jet.SelectStatementType, &out) 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) 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} out := jet.SqlBuilder{Dialect: Dialect}
err := jet.Serialize(clause, jet.SelectStatementType, &out) err := jet.Serialize(clause, jet.SelectStatementType, &out)

View file

@ -678,8 +678,7 @@ func TestSubQueryColumnReference(t *testing.T) {
). ).
AsTable("subQuery") AsTable("subQuery")
unionexpectedSQL := ` unionexpectedSQL := ` (
(
( (
SELECT all_types.boolean AS "all_types.boolean", SELECT all_types.boolean AS "all_types.boolean",
all_types.integer AS "all_types.integer", all_types.integer AS "all_types.integer",
@ -775,8 +774,6 @@ FROM`
). ).
FROM(subQuery) FROM(subQuery)
//fmt.Println(stmt2.DebugSql())
testutils.AssertDebugStatementSql(t, stmt2, expectedSQL+expected.sql+";\n", expected.args...) testutils.AssertDebugStatementSql(t, stmt2, expectedSQL+expected.sql+";\n", expected.args...)
dest2 := []model.AllTypes{} dest2 := []model.AllTypes{}

View file

@ -15,7 +15,7 @@ func TestLockTable(t *testing.T) {
expectedSQL := ` expectedSQL := `
LOCK TABLE dvds.address IN` LOCK TABLE dvds.address IN`
var testData = []string{ var testData = []TableLockMode{
LOCK_ACCESS_SHARE, LOCK_ACCESS_SHARE,
LOCK_ROW_SHARE, LOCK_ROW_SHARE,
LOCK_ROW_EXCLUSIVE, LOCK_ROW_EXCLUSIVE,

View file

@ -1,6 +1,8 @@
package postgres package postgres
import ( import (
"fmt"
"github.com/go-jet/jet/internal/jet"
"github.com/go-jet/jet/internal/testutils" "github.com/go-jet/jet/internal/testutils"
. "github.com/go-jet/jet/postgres" . "github.com/go-jet/jet/postgres"
"github.com/go-jet/jet/tests/.gentestdata/jetdb/dvds/enum" "github.com/go-jet/jet/tests/.gentestdata/jetdb/dvds/enum"
@ -157,7 +159,12 @@ LIMIT 12;
). ).
LIMIT(12) LIMIT(12)
fmt.Println(query.DebugSql())
testutils.AssertDebugStatementSql(t, query, expectedSQL, int64(1), int64(1), int64(10), int64(1), int64(2), int64(1), int64(12)) testutils.AssertDebugStatementSql(t, query, expectedSQL, int64(1), int64(1), int64(10), int64(1), int64(2), int64(1), int64(12))
err := query.Query(db, &struct{}{})
assert.NilError(t, err)
} }
func TestJoinQueryStruct(t *testing.T) { func TestJoinQueryStruct(t *testing.T) {
@ -1240,6 +1247,8 @@ OFFSET 20;
LIMIT(10). LIMIT(10).
OFFSET(20) OFFSET(20)
fmt.Println(query.DebugSql())
testutils.AssertDebugStatementSql(t, query, expectedQuery, float64(100), float64(200), int64(10), int64(20)) testutils.AssertDebugStatementSql(t, query, expectedQuery, float64(100), float64(200), int64(10), int64(20))
dest := []model.Payment{} dest := []model.Payment{}
@ -1267,7 +1276,7 @@ func TestAllSetOperators(t *testing.T) {
select1 := Payment.SELECT(Payment.AllColumns).WHERE(Payment.PaymentID.GT_EQ(Int(17600)).AND(Payment.PaymentID.LT(Int(17610)))) select1 := Payment.SELECT(Payment.AllColumns).WHERE(Payment.PaymentID.GT_EQ(Int(17600)).AND(Payment.PaymentID.LT(Int(17610))))
select2 := Payment.SELECT(Payment.AllColumns).WHERE(Payment.PaymentID.GT_EQ(Int(17620)).AND(Payment.PaymentID.LT(Int(17630)))) select2 := Payment.SELECT(Payment.AllColumns).WHERE(Payment.PaymentID.GT_EQ(Int(17620)).AND(Payment.PaymentID.LT(Int(17630))))
type setOperator func(lhs, rhs SelectStatement, selects ...SelectStatement) SelectStatement type setOperator func(lhs, rhs jet.StatementWithProjections, selects ...jet.StatementWithProjections) SetStatement
operators := []setOperator{ operators := []setOperator{
UNION, UNION,
UNION_ALL, UNION_ALL,