jet/internal/jet/clause.go

550 lines
12 KiB
Go
Raw Normal View History

2019-06-21 13:56:57 +02:00
package jet
2019-03-31 09:17:28 +02:00
import (
2019-07-04 17:54:15 +02:00
"github.com/go-jet/jet/internal/utils"
)
2019-03-31 09:17:28 +02:00
2019-08-17 18:32:01 +02:00
// Clause interface
2019-08-11 09:52:02 +02:00
type Clause interface {
Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption)
2019-08-11 09:52:02 +02:00
}
2019-08-17 18:32:01 +02:00
// ClauseWithProjections interface
2019-08-11 09:52:02 +02:00
type ClauseWithProjections interface {
Clause
2019-08-14 10:11:43 +02:00
projections() ProjectionList
2019-08-11 09:52:02 +02:00
}
2019-08-17 18:32:01 +02:00
// ClauseSelect struct
2019-08-11 09:52:02 +02:00
type ClauseSelect struct {
Distinct bool
Projections []Projection
}
2019-08-14 10:11:43 +02:00
func (s *ClauseSelect) projections() ProjectionList {
2019-08-11 09:52:02 +02:00
return s.Projections
}
2019-08-17 18:32:01 +02:00
// Serialize serializes clause into SQLBuilder
func (s *ClauseSelect) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
2019-08-11 12:13:59 +02:00
out.NewLine()
2019-08-11 09:52:02 +02:00
out.WriteString("SELECT")
if s.Distinct {
out.WriteString("DISTINCT")
}
if len(s.Projections) == 0 {
panic("jet: SELECT clause has to have at least one projection")
2019-08-11 09:52:02 +02:00
}
out.WriteProjections(statementType, s.Projections)
}
2019-08-17 18:32:01 +02:00
// ClauseFrom struct
2019-08-11 09:52:02 +02:00
type ClauseFrom struct {
Table Serializer
2019-08-03 14:10:47 +02:00
}
2019-08-17 18:32:01 +02:00
// Serialize serializes clause into SQLBuilder
func (f *ClauseFrom) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
2019-08-11 09:52:02 +02:00
if f.Table == nil {
return
2019-08-11 09:52:02 +02:00
}
out.NewLine()
out.WriteString("FROM")
2019-08-11 18:57:40 +02:00
out.IncreaseIdent()
f.Table.serialize(statementType, out, FallTrough(options)...)
out.DecreaseIdent()
2019-08-11 09:52:02 +02:00
}
2019-08-17 18:32:01 +02:00
// ClauseWhere struct
2019-08-11 09:52:02 +02:00
type ClauseWhere struct {
Condition BoolExpression
Mandatory bool
}
2019-08-17 18:32:01 +02:00
// Serialize serializes clause into SQLBuilder
func (c *ClauseWhere) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
2019-08-11 09:52:02 +02:00
if c.Condition == nil {
if c.Mandatory {
panic("jet: WHERE clause not set")
}
return
}
if !contains(options, SkipNewLine) {
out.NewLine()
}
out.WriteString("WHERE")
2019-08-11 18:57:40 +02:00
out.IncreaseIdent()
c.Condition.serialize(statementType, out, NoWrap.WithFallTrough(options)...)
out.DecreaseIdent()
2019-08-11 09:52:02 +02:00
}
2019-08-17 18:32:01 +02:00
// ClauseGroupBy struct
2019-08-11 09:52:02 +02:00
type ClauseGroupBy struct {
List []GroupByClause
}
2019-08-17 18:32:01 +02:00
// Serialize serializes clause into SQLBuilder
func (c *ClauseGroupBy) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
2019-08-11 09:52:02 +02:00
if len(c.List) == 0 {
return
2019-08-11 09:52:02 +02:00
}
2019-08-11 12:13:59 +02:00
out.NewLine()
2019-08-11 09:52:02 +02:00
out.WriteString("GROUP BY")
2019-08-11 14:29:03 +02:00
out.IncreaseIdent()
2019-08-17 18:32:01 +02:00
for i, c := range c.List {
if i > 0 {
out.WriteString(", ")
}
if c == nil {
panic("jet: nil clause in GROUP BY list")
}
c.serializeForGroupBy(statementType, out)
}
2019-08-11 14:29:03 +02:00
out.DecreaseIdent()
2019-05-03 12:51:57 +02:00
}
2019-08-17 18:32:01 +02:00
// ClauseHaving struct
2019-08-11 09:52:02 +02:00
type ClauseHaving struct {
Condition BoolExpression
2019-08-03 14:10:47 +02:00
}
2019-08-17 18:32:01 +02:00
// Serialize serializes clause into SQLBuilder
func (c *ClauseHaving) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
2019-08-11 09:52:02 +02:00
if c.Condition == nil {
return
2019-08-11 09:52:02 +02:00
}
out.NewLine()
out.WriteString("HAVING")
2019-08-11 18:57:40 +02:00
out.IncreaseIdent()
c.Condition.serialize(statementType, out, NoWrap.WithFallTrough(options)...)
out.DecreaseIdent()
2019-08-11 09:52:02 +02:00
}
2019-08-17 18:32:01 +02:00
// ClauseOrderBy struct
2019-08-11 09:52:02 +02:00
type ClauseOrderBy struct {
List []OrderByClause
SkipNewLine bool
2019-08-11 09:52:02 +02:00
}
2019-05-03 12:51:57 +02:00
2019-08-17 18:32:01 +02:00
// Serialize serializes clause into SQLBuilder
func (o *ClauseOrderBy) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
2019-08-11 09:52:02 +02:00
if o.List == nil {
return
2019-08-11 09:52:02 +02:00
}
if !o.SkipNewLine {
out.NewLine()
}
out.WriteString("ORDER BY")
2019-08-11 18:57:40 +02:00
out.IncreaseIdent()
2019-08-17 18:32:01 +02:00
for i, value := range o.List {
if i > 0 {
out.WriteString(", ")
}
value.serializeForOrderBy(statementType, out)
}
out.DecreaseIdent()
2019-08-11 09:52:02 +02:00
}
2019-05-12 18:15:23 +02:00
2019-08-17 18:32:01 +02:00
// ClauseLimit struct
2019-08-11 09:52:02 +02:00
type ClauseLimit struct {
Count int64
2019-05-12 18:15:23 +02:00
}
2019-08-17 18:32:01 +02:00
// Serialize serializes clause into SQLBuilder
func (l *ClauseLimit) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
2019-08-11 09:52:02 +02:00
if l.Count >= 0 {
2019-08-11 12:13:59 +02:00
out.NewLine()
2019-08-11 09:52:02 +02:00
out.WriteString("LIMIT")
out.insertParametrizedArgument(l.Count)
2019-05-12 18:15:23 +02:00
}
}
2019-08-17 18:32:01 +02:00
// ClauseOffset struct
2019-08-11 09:52:02 +02:00
type ClauseOffset struct {
Count int64
2019-05-12 18:15:23 +02:00
}
2019-08-17 18:32:01 +02:00
// Serialize serializes clause into SQLBuilder
func (o *ClauseOffset) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
2019-08-11 09:52:02 +02:00
if o.Count >= 0 {
2019-08-11 12:13:59 +02:00
out.NewLine()
2019-08-11 09:52:02 +02:00
out.WriteString("OFFSET")
out.insertParametrizedArgument(o.Count)
}
}
2019-05-12 18:15:23 +02:00
2019-08-17 18:32:01 +02:00
// ClauseFor struct
2019-08-11 09:52:02 +02:00
type ClauseFor struct {
2019-08-17 10:43:16 +02:00
Lock RowLock
2019-05-03 12:51:57 +02:00
}
2019-08-17 18:32:01 +02:00
// Serialize serializes clause into SQLBuilder
func (f *ClauseFor) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
2019-08-11 09:52:02 +02:00
if f.Lock == nil {
return
2019-08-11 09:52:02 +02:00
}
2019-05-12 18:15:23 +02:00
2019-08-11 12:13:59 +02:00
out.NewLine()
2019-08-11 09:52:02 +02:00
out.WriteString("FOR")
f.Lock.serialize(statementType, out, FallTrough(options)...)
2019-08-11 09:52:02 +02:00
}
2019-05-12 18:15:23 +02:00
2019-08-17 18:32:01 +02:00
// ClauseSetStmtOperator struct
2019-08-11 09:52:02 +02:00
type ClauseSetStmtOperator struct {
Operator string
All bool
Selects []StatementWithProjections
OrderBy ClauseOrderBy
Limit ClauseLimit
Offset ClauseOffset
2019-05-03 12:51:57 +02:00
}
2019-08-14 10:11:43 +02:00
func (s *ClauseSetStmtOperator) projections() ProjectionList {
2019-08-11 09:52:02 +02:00
if len(s.Selects) > 0 {
return s.Selects[0].projections()
}
return nil
}
2019-05-03 12:51:57 +02:00
2019-08-17 18:32:01 +02:00
// Serialize serializes clause into SQLBuilder
func (s *ClauseSetStmtOperator) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
2019-08-11 09:52:02 +02:00
if len(s.Selects) < 2 {
panic("jet: UNION Statement must contain at least two SELECT statements")
2019-08-11 09:52:02 +02:00
}
2019-05-12 18:15:23 +02:00
2019-08-11 09:52:02 +02:00
for i, selectStmt := range s.Selects {
2019-08-11 12:13:59 +02:00
out.NewLine()
2019-08-11 09:52:02 +02:00
if i > 0 {
out.WriteString(s.Operator)
if s.All {
out.WriteString("ALL")
}
2019-08-11 12:13:59 +02:00
out.NewLine()
2019-08-11 09:52:02 +02:00
}
if selectStmt == nil {
panic("jet: select statement of '" + s.Operator + "' is nil")
2019-08-11 09:52:02 +02:00
}
selectStmt.serialize(statementType, out, FallTrough(options)...)
2019-08-11 09:52:02 +02:00
}
s.OrderBy.Serialize(statementType, out)
s.Limit.Serialize(statementType, out)
s.Offset.Serialize(statementType, out)
2019-05-03 12:51:57 +02:00
}
2019-08-17 18:32:01 +02:00
// ClauseUpdate struct
2019-08-11 09:52:02 +02:00
type ClauseUpdate struct {
Table SerializerTable
}
2019-05-12 18:15:23 +02:00
2019-08-17 18:32:01 +02:00
// Serialize serializes clause into SQLBuilder
func (u *ClauseUpdate) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
2019-08-11 12:13:59 +02:00
out.NewLine()
2019-08-11 09:52:02 +02:00
out.WriteString("UPDATE")
2019-05-12 18:15:23 +02:00
2019-08-11 09:52:02 +02:00
if utils.IsNil(u.Table) {
panic("jet: table to update is nil")
2019-08-11 09:52:02 +02:00
}
u.Table.serialize(statementType, out, FallTrough(options)...)
2019-05-03 12:51:57 +02:00
}
2019-08-17 18:32:01 +02:00
// ClauseSet struct
2019-08-11 09:52:02 +02:00
type ClauseSet struct {
2019-08-11 14:29:03 +02:00
Columns []Column
2019-08-11 09:52:02 +02:00
Values []Serializer
}
2019-05-12 18:15:23 +02:00
2019-08-17 18:32:01 +02:00
// Serialize serializes clause into SQLBuilder
func (s *ClauseSet) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
2019-08-11 12:13:59 +02:00
out.NewLine()
2019-08-11 09:52:02 +02:00
out.WriteString("SET")
2019-05-12 18:15:23 +02:00
2019-08-11 12:13:59 +02:00
if len(s.Columns) != len(s.Values) {
panic("jet: mismatch in numbers of columns and values for SET clause")
2019-08-11 09:52:02 +02:00
}
2019-08-11 14:29:03 +02:00
out.IncreaseIdent(4)
2019-08-11 12:13:59 +02:00
for i, column := range s.Columns {
if i > 0 {
out.WriteString(", ")
out.NewLine()
}
2019-08-11 09:52:02 +02:00
2019-08-11 12:13:59 +02:00
if column == nil {
panic("jet: nil column in columns list for SET clause")
2019-08-11 12:13:59 +02:00
}
2019-08-11 09:52:02 +02:00
2019-08-11 12:13:59 +02:00
out.WriteString(column.Name())
2019-08-11 09:52:02 +02:00
2019-08-11 12:13:59 +02:00
out.WriteString(" = ")
2019-08-11 09:52:02 +02:00
s.Values[i].serialize(UpdateStatementType, out, FallTrough(options)...)
2019-08-11 09:52:02 +02:00
}
2019-08-11 14:29:03 +02:00
out.DecreaseIdent(4)
2019-08-11 09:52:02 +02:00
}
2019-08-17 18:32:01 +02:00
// ClauseInsert struct
2019-08-11 14:29:03 +02:00
type ClauseInsert struct {
Table SerializerTable
Columns []Column
2019-08-11 09:52:02 +02:00
}
2019-08-17 18:32:01 +02:00
// GetColumns gets list of columns for insert
2019-08-11 14:29:03 +02:00
func (i *ClauseInsert) GetColumns() []Column {
if len(i.Columns) > 0 {
return i.Columns
}
2019-08-11 09:52:02 +02:00
2019-08-12 11:33:46 +02:00
return i.Table.columns()
2019-08-11 09:52:02 +02:00
}
2019-08-17 18:32:01 +02:00
// Serialize serializes clause into SQLBuilder
func (i *ClauseInsert) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
2019-08-11 12:13:59 +02:00
out.NewLine()
2019-08-11 09:52:02 +02:00
out.WriteString("INSERT INTO")
if utils.IsNil(i.Table) {
panic("jet: table is nil for INSERT clause")
2019-08-11 09:52:02 +02:00
}
i.Table.serialize(statementType, out)
2019-08-11 09:52:02 +02:00
if len(i.Columns) > 0 {
out.WriteString("(")
SerializeColumnNames(i.Columns, out)
2019-08-11 09:52:02 +02:00
out.WriteString(")")
}
}
2019-08-17 18:32:01 +02:00
// ClauseValuesQuery struct
2019-08-12 12:27:33 +02:00
type ClauseValuesQuery struct {
ClauseValues
ClauseQuery
}
2019-08-17 18:32:01 +02:00
// Serialize serializes clause into SQLBuilder
func (v *ClauseValuesQuery) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
2019-08-12 12:27:33 +02:00
if len(v.Rows) == 0 && v.Query == nil {
panic("jet: VALUES or QUERY has to be specified for INSERT statement")
2019-08-12 12:27:33 +02:00
}
if len(v.Rows) > 0 && v.Query != nil {
panic("jet: VALUES or QUERY has to be specified for INSERT statement")
2019-08-12 12:27:33 +02:00
}
v.ClauseValues.Serialize(statementType, out, FallTrough(options)...)
v.ClauseQuery.Serialize(statementType, out, FallTrough(options)...)
2019-08-12 12:27:33 +02:00
}
2019-08-17 18:32:01 +02:00
// ClauseValues struct
2019-08-11 09:52:02 +02:00
type ClauseValues struct {
Rows [][]Serializer
2019-05-12 18:15:23 +02:00
}
2019-08-17 18:32:01 +02:00
// Serialize serializes clause into SQLBuilder
func (v *ClauseValues) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
2019-08-11 09:52:02 +02:00
if len(v.Rows) == 0 {
return
}
out.NewLine()
2019-08-11 09:52:02 +02:00
out.WriteString("VALUES")
for rowIndex, row := range v.Rows {
if rowIndex > 0 {
out.WriteString(",")
out.NewLine()
} else {
out.IncreaseIdent(7)
2019-08-11 09:52:02 +02:00
}
out.WriteString("(")
SerializeClauseList(statementType, row, out)
2019-08-11 09:52:02 +02:00
2019-08-11 18:57:40 +02:00
out.WriteByte(')')
2019-08-01 17:45:11 +02:00
}
out.DecreaseIdent(7)
2019-08-11 09:52:02 +02:00
}
2019-08-01 17:45:11 +02:00
2019-08-17 18:32:01 +02:00
// ClauseQuery struct
2019-08-11 09:52:02 +02:00
type ClauseQuery struct {
Query SerializerStatement
}
2019-08-17 18:32:01 +02:00
// Serialize serializes clause into SQLBuilder
func (v *ClauseQuery) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
2019-08-11 09:52:02 +02:00
if v.Query == nil {
return
2019-08-11 09:52:02 +02:00
}
v.Query.serialize(statementType, out, FallTrough(options)...)
}
2019-08-17 18:32:01 +02:00
// ClauseDelete struct
2019-08-11 09:52:02 +02:00
type ClauseDelete struct {
Table SerializerTable
}
2019-08-17 18:32:01 +02:00
// Serialize serializes clause into SQLBuilder
func (d *ClauseDelete) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
2019-08-11 12:13:59 +02:00
out.NewLine()
2019-08-11 09:52:02 +02:00
out.WriteString("DELETE FROM")
if d.Table == nil {
panic("jet: nil table in DELETE clause")
2019-08-11 09:52:02 +02:00
}
d.Table.serialize(statementType, out, FallTrough(options)...)
2019-08-11 09:52:02 +02:00
}
2019-08-17 18:32:01 +02:00
// ClauseStatementBegin struct
2019-08-11 09:52:02 +02:00
type ClauseStatementBegin struct {
Name string
Tables []SerializerTable
}
2019-08-17 18:32:01 +02:00
// Serialize serializes clause into SQLBuilder
func (d *ClauseStatementBegin) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
2019-08-11 12:13:59 +02:00
out.NewLine()
2019-08-11 09:52:02 +02:00
out.WriteString(d.Name)
for i, table := range d.Tables {
if i > 0 {
out.WriteString(", ")
}
table.serialize(statementType, out, FallTrough(options)...)
2019-08-11 09:52:02 +02:00
}
}
2019-08-17 18:32:01 +02:00
// ClauseOptional struct
2019-08-11 09:52:02 +02:00
type ClauseOptional struct {
2019-08-15 11:59:17 +02:00
Name string
Show bool
InNewLine bool
2019-08-11 09:52:02 +02:00
}
2019-08-17 18:32:01 +02:00
// Serialize serializes clause into SQLBuilder
func (d *ClauseOptional) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
2019-08-11 09:52:02 +02:00
if !d.Show {
return
2019-08-11 09:52:02 +02:00
}
2019-08-15 11:59:17 +02:00
if d.InNewLine {
out.NewLine()
}
2019-08-11 09:52:02 +02:00
out.WriteString(d.Name)
}
2019-08-17 18:32:01 +02:00
// ClauseIn struct
2019-08-11 09:52:02 +02:00
type ClauseIn struct {
LockMode string
}
2019-08-17 18:32:01 +02:00
// Serialize serializes clause into SQLBuilder
func (i *ClauseIn) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
2019-08-11 09:52:02 +02:00
if i.LockMode == "" {
return
2019-08-11 09:52:02 +02:00
}
out.WriteString("IN")
out.WriteString(string(i.LockMode))
out.WriteString("MODE")
}
// WindowDefinition struct
type WindowDefinition struct {
Name string
Window Window
}
// ClauseWindow struct
type ClauseWindow struct {
Definitions []WindowDefinition
}
// Serialize serializes clause into SQLBuilder
func (i *ClauseWindow) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
if len(i.Definitions) == 0 {
return
}
out.NewLine()
out.WriteString("WINDOW")
for i, def := range i.Definitions {
if i > 0 {
out.WriteString(", ")
}
out.WriteString(def.Name)
out.WriteString("AS")
if def.Window == nil {
out.WriteString("()")
continue
}
def.Window.serialize(statementType, out, FallTrough(options)...)
}
}
// SetPair clause
type SetPair struct {
Column ColumnSerializer
Value Serializer
}
// SetClause clause
type SetClause []ColumnAssigment
// Serialize for SetClause
func (s SetClause) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
out.NewLine()
out.WriteString("SET")
out.IncreaseIdent(4)
for i, assigment := range s {
if i > 0 {
out.WriteString(",")
out.NewLine()
}
assigment.serialize(statementType, out, FallTrough(options)...)
}
out.DecreaseIdent(4)
}
// KeywordClause type
type KeywordClause struct {
Keyword
}
// Serialize for KeywordClause
func (k KeywordClause) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
k.serialize(statementType, out, FallTrough(options)...)
}