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 {
column := newColumn(a.alias, "", nil)
column.parent = &column
column.Parent = &column
column.subQuery = subQuery
return &column

View file

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

View file

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

View file

@ -1,270 +1,702 @@
package jet
import (
"bytes"
"errors"
"github.com/go-jet/jet/internal/utils"
"github.com/google/uuid"
"strconv"
"strings"
"time"
)
type SerializeOption int
const (
noWrap SerializeOption = iota
)
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 {
return exp.serialize(statementType, out, options...)
type ClauseWithProjections interface {
Clause
projections() []Projection
}
func contains(options []SerializeOption, option SerializeOption) bool {
for _, opt := range options {
if opt == option {
return true
type ClauseSelect struct {
Distinct bool
Projections []Projection
}
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 false
return out.writeWhere(statementType, c.Condition)
}
type SqlBuilder struct {
Dialect Dialect
Buff bytes.Buffer
Args []interface{}
lastChar byte
ident int
type ClauseGroupBy struct {
List []GroupByClause
}
func (s *SqlBuilder) DebugSQL() string {
return queryStringToDebugString(s.Buff.String(), s.Args, s.Dialect)
}
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 {
func (c *ClauseGroupBy) Serialize(statementType StatementType, out *SqlBuilder) error {
if len(c.List) == 0 {
return nil
}
if !q.Dialect.SupportsReturning() {
panic("jet: " + q.Dialect.Name() + " dialect does not support RETURNING.")
out.newLine()
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()
q.WriteString("RETURNING")
q.increaseIdent()
return q.writeProjections(statement, returning)
return out.writeHaving(statementType, c.Condition)
}
func (q *SqlBuilder) newLine() {
q.write([]byte{'\n'})
q.write(bytes.Repeat([]byte{' '}, q.ident))
type ClauseOrderBy struct {
List []OrderByClause
}
func (q *SqlBuilder) write(data []byte) {
if len(data) == 0 {
func (o *ClauseOrderBy) Serialize(statementType StatementType, out *SqlBuilder) error {
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
}
if !isPreSeparator(q.lastChar) && !isPostSeparator(data[0]) && q.Buff.Len() > 0 {
q.Buff.WriteByte(' ')
out.newLine()
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)
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"
if utils.IsNil(t.rhs) {
return errors.New("jet: right hand side of join operation is nil table")
}
switch bindVal := value.(type) {
case bool:
if bindVal {
return "TRUE"
if err = t.rhs.serialize(statement, out); err != nil {
return
}
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 {
return `'` + strings.Replace(value, "'", "''", -1) + `'`
// SelectTable is interface for SELECT sub-queries
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.
type columnImpl struct {
expressionInterfaceImpl
ExpressionInterfaceImpl
noOpVisitorImpl
name string
@ -34,7 +34,7 @@ func newColumn(name string, tableName string, parent Column) columnImpl {
tableName: tableName,
}
bc.expressionInterfaceImpl.parent = parent
bc.ExpressionInterfaceImpl.Parent = parent
return bc
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -35,23 +35,23 @@ func newInsertStatement(t WritableTable, columns []IColumn) InsertStatement {
type insertStatementImpl struct {
table WritableTable
columns []IColumn
rows [][]Clause
rows [][]Serializer
query SelectStatement
returning []Projection
}
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
}
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
}
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
}
@ -113,6 +113,8 @@ func (i *insertStatementImpl) Sql(dialect ...Dialect) (query string, args []inte
out.WriteString(")")
}
//TODO:
if len(i.rows) == 0 && i.query == nil {
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
}

View file

@ -82,9 +82,9 @@ func TestInsertValuesFromModel(t *testing.T) {
MODEL(&toInsert)
expectedSQL := `
INSERT INTO db.table1 (col1, col_float) VALUES
($1, $2),
($3, $4);
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))

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,72 +1,70 @@
package jet
import "errors"
// SelectTable is interface for SELECT sub-queries
type SelectTable interface {
ReadableTable
Alias() string
AllColumns() ProjectionList
}
type selectTableImpl struct {
readableTableInterfaceImpl
selectStmt SelectStatement
alias string
projections []Projection
}
func newSelectTable(selectStmt SelectStatement, alias string) SelectTable {
expTable := &selectTableImpl{selectStmt: selectStmt, alias: alias}
expTable.readableTableInterfaceImpl.parent = expTable
for _, projection := range selectStmt.projections() {
newProjection := projection.fromImpl(expTable)
expTable.projections = append(expTable.projections, newProjection)
}
return expTable
}
func (s *selectTableImpl) Alias() string {
return s.alias
}
func (s *selectTableImpl) columns() []IColumn {
return nil
}
func (s *selectTableImpl) accept(visitor visitor) {
visitor.visit(s)
s.selectStmt.accept(visitor)
}
func (s *selectTableImpl) dialect() Dialect {
return detectDialect(s.selectStmt)
}
func (s *selectTableImpl) AllColumns() ProjectionList {
return s.projections
}
func (s *selectTableImpl) 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
}
//// SelectTable is interface for SELECT sub-queries
//type SelectTable interface {
// ReadableTable
//
// Alias() string
//
// AllColumns() ProjectionList
//}
//
//type selectTableImpl struct {
// readableTableInterfaceImpl
// selectStmt SelectStatement
// alias string
//
// projections []Projection
//}
//
//func newSelectTable(selectStmt SelectStatement, alias string) SelectTable {
// expTable := &selectTableImpl{selectStmt: selectStmt, alias: alias}
//
// expTable.readableTableInterfaceImpl.parent = expTable
//
// for _, projection := range selectStmt.projections() {
// newProjection := projection.fromImpl(expTable)
//
// expTable.projections = append(expTable.projections, newProjection)
// }
//
// return expTable
//}
//
//func (s *selectTableImpl) Alias() string {
// return s.alias
//}
//
//func (s *selectTableImpl) columns() []IColumn {
// return nil
//}
//
//func (s *selectTableImpl) accept(visitor visitor) {
// visitor.visit(s)
// s.selectStmt.accept(visitor)
//}
//
//func (s *selectTableImpl) dialect() Dialect {
// return detectDialect(s.selectStmt)
//}
//
//func (s *selectTableImpl) AllColumns() ProjectionList {
// return s.projections
//}
//
//func (s *selectTableImpl) 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

@ -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,
}
setStatement.selectStatementImpl.expressionInterfaceImpl.parent = setStatement
setStatement.selectStatementImpl.ExpressionInterfaceImpl.Parent = setStatement
setStatement.selectStatementImpl.parent = setStatement
setStatement.limit = -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 (
"context"
"database/sql"
"errors"
"github.com/go-jet/jet/execution"
"strings"
)
@ -31,9 +32,66 @@ type Statement interface {
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) {
dialect := detectDialect(statement, overrideDialect...)
sqlQuery, args, err := statement.Sql()
sqlQuery, args, err := statement.Sql(dialect)
if err != nil {
return "", err
@ -100,3 +158,68 @@ func execContext(context context.Context, statement Statement, db execution.DB)
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 {
expressionInterfaceImpl
ExpressionInterfaceImpl
stringInterfaceImpl
binaryOpExpression
@ -90,7 +90,7 @@ func newBinaryStringExpression(lhs, rhs Expression, operator string) StringExpre
boolExpression := binaryStringExpression{}
boolExpression.binaryOpExpression = newBinaryExpression(lhs, rhs, operator)
boolExpression.expressionInterfaceImpl.parent = &boolExpression
boolExpression.ExpressionInterfaceImpl.Parent = &boolExpression
boolExpression.stringInterfaceImpl.parent = &boolExpression
return &boolExpression

View file

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

View file

@ -72,7 +72,7 @@ var table3 = NewTable(
table3ColInt,
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}
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)
}
func assertClauseSerializeErr(t *testing.T, clause Clause, errString string) {
func assertClauseSerializeErr(t *testing.T, clause Serializer, errString string) {
out := SqlBuilder{Dialect: ANSII}
err := clause.serialize(SelectStatementType, &out)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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