2019-06-21 13:56:57 +02:00
|
|
|
package jet
|
2019-03-31 09:17:28 +02:00
|
|
|
|
2023-07-21 14:11:31 +02:00
|
|
|
import "github.com/go-jet/jet/v2/internal/utils/is"
|
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 {
|
2020-04-12 18:53:57 +02:00
|
|
|
Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption)
|
2019-08-11 09:52:02 +02:00
|
|
|
}
|
2019-05-31 14:37:51 +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-05-31 14:37:51 +02:00
|
|
|
|
2020-05-24 17:55:28 +02:00
|
|
|
Projections() ProjectionList
|
2019-08-11 09:52:02 +02:00
|
|
|
}
|
|
|
|
|
|
2022-09-29 13:33:00 +02:00
|
|
|
// OptimizerHint provides a way to optimize query execution per-statement basis
|
|
|
|
|
type OptimizerHint string
|
|
|
|
|
|
|
|
|
|
type optimizerHints []OptimizerHint
|
|
|
|
|
|
|
|
|
|
func (o optimizerHints) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
|
|
|
|
|
if len(o) == 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out.WriteString("/*+")
|
|
|
|
|
for i, hint := range o {
|
|
|
|
|
if i > 0 {
|
|
|
|
|
out.WriteByte(' ')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out.WriteString(string(hint))
|
|
|
|
|
}
|
|
|
|
|
out.WriteString("*/")
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-17 18:32:01 +02:00
|
|
|
// ClauseSelect struct
|
2019-08-11 09:52:02 +02:00
|
|
|
type ClauseSelect struct {
|
2022-01-06 18:11:26 +01:00
|
|
|
Distinct bool
|
|
|
|
|
DistinctOnColumns []ColumnExpression
|
|
|
|
|
ProjectionList []Projection
|
2022-09-29 13:33:00 +02:00
|
|
|
|
2025-03-08 19:01:37 +01:00
|
|
|
IsForRowToJson bool
|
|
|
|
|
|
2022-09-29 13:33:00 +02:00
|
|
|
// MySQL only
|
|
|
|
|
OptimizerHints optimizerHints
|
2019-08-11 09:52:02 +02:00
|
|
|
}
|
|
|
|
|
|
2020-05-24 17:55:28 +02:00
|
|
|
// Projections returns list of projections for select clause
|
|
|
|
|
func (s *ClauseSelect) Projections() ProjectionList {
|
|
|
|
|
return s.ProjectionList
|
2019-08-11 09:52:02 +02:00
|
|
|
}
|
|
|
|
|
|
2019-08-17 18:32:01 +02:00
|
|
|
// Serialize serializes clause into SQLBuilder
|
2020-04-12 18:53:57 +02:00
|
|
|
func (s *ClauseSelect) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
|
2025-02-21 19:55:01 +01:00
|
|
|
if len(s.ProjectionList) == 0 {
|
|
|
|
|
panic("jet: SELECT clause has to have at least one projection")
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-11 12:13:59 +02:00
|
|
|
out.NewLine()
|
2019-08-11 09:52:02 +02:00
|
|
|
out.WriteString("SELECT")
|
2022-09-29 13:33:00 +02:00
|
|
|
s.OptimizerHints.Serialize(statementType, out, options...)
|
2019-08-11 09:52:02 +02:00
|
|
|
|
|
|
|
|
if s.Distinct {
|
|
|
|
|
out.WriteString("DISTINCT")
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-06 18:11:26 +01:00
|
|
|
if len(s.DistinctOnColumns) > 0 {
|
|
|
|
|
out.WriteString("ON (")
|
|
|
|
|
SerializeColumnExpressions(s.DistinctOnColumns, statementType, out)
|
|
|
|
|
out.WriteByte(')')
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-08 19:01:37 +01:00
|
|
|
if s.IsForRowToJson {
|
|
|
|
|
out.IncreaseIdent()
|
|
|
|
|
out.WriteRowToJsonProjections(statementType, s.ProjectionList)
|
|
|
|
|
out.DecreaseIdent()
|
|
|
|
|
} else {
|
|
|
|
|
out.WriteProjections(statementType, s.ProjectionList)
|
|
|
|
|
}
|
2019-05-31 14:37:51 +02:00
|
|
|
}
|
|
|
|
|
|
2019-08-17 18:32:01 +02:00
|
|
|
// ClauseFrom struct
|
2019-08-11 09:52:02 +02:00
|
|
|
type ClauseFrom struct {
|
2021-12-08 18:13:58 +01:00
|
|
|
Name string
|
2021-05-03 18:48:15 +02:00
|
|
|
Tables []Serializer
|
2019-08-03 14:10:47 +02:00
|
|
|
}
|
|
|
|
|
|
2019-08-17 18:32:01 +02:00
|
|
|
// Serialize serializes clause into SQLBuilder
|
2020-04-12 18:53:57 +02:00
|
|
|
func (f *ClauseFrom) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
|
2021-05-03 18:48:15 +02:00
|
|
|
if len(f.Tables) == 0 { // SELECT statement does not have to have FROM clause
|
2019-08-13 13:57:26 +02:00
|
|
|
return
|
2019-08-11 09:52:02 +02:00
|
|
|
}
|
2019-08-13 13:57:26 +02:00
|
|
|
out.NewLine()
|
2021-12-08 18:13:58 +01:00
|
|
|
if f.Name != "" {
|
|
|
|
|
out.WriteString(f.Name)
|
|
|
|
|
} else {
|
|
|
|
|
out.WriteString("FROM")
|
|
|
|
|
}
|
2019-08-11 18:57:40 +02:00
|
|
|
|
2019-08-13 13:57:26 +02:00
|
|
|
out.IncreaseIdent()
|
2021-05-03 18:48:15 +02:00
|
|
|
for i, table := range f.Tables {
|
|
|
|
|
if i > 0 {
|
|
|
|
|
out.WriteString(",")
|
|
|
|
|
out.NewLine()
|
|
|
|
|
}
|
|
|
|
|
table.serialize(statementType, out, FallTrough(options)...)
|
|
|
|
|
}
|
2019-08-13 13:57:26 +02:00
|
|
|
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
|
2020-04-12 18:53:57 +02:00
|
|
|
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 {
|
2019-08-13 13:57:26 +02:00
|
|
|
panic("jet: WHERE clause not set")
|
2019-05-31 14:37:51 +02:00
|
|
|
}
|
2019-08-13 13:57:26 +02:00
|
|
|
return
|
2019-05-31 14:37:51 +02:00
|
|
|
}
|
2020-04-12 18:53:57 +02:00
|
|
|
if !contains(options, SkipNewLine) {
|
|
|
|
|
out.NewLine()
|
|
|
|
|
}
|
2019-08-13 13:57:26 +02:00
|
|
|
out.WriteString("WHERE")
|
2019-08-11 18:57:40 +02:00
|
|
|
|
2022-02-11 13:09:49 +01:00
|
|
|
out.IncreaseIdent(6)
|
2020-04-12 18:53:57 +02:00
|
|
|
c.Condition.serialize(statementType, out, NoWrap.WithFallTrough(options)...)
|
2022-02-11 13:09:49 +01:00
|
|
|
out.DecreaseIdent(6)
|
2019-08-11 09:52:02 +02:00
|
|
|
}
|
2019-05-31 14:37:51 +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-04-29 14:39:48 +02:00
|
|
|
}
|
|
|
|
|
|
2019-08-17 18:32:01 +02:00
|
|
|
// Serialize serializes clause into SQLBuilder
|
2020-04-12 18:53:57 +02:00
|
|
|
func (c *ClauseGroupBy) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
|
2019-08-11 09:52:02 +02:00
|
|
|
if len(c.List) == 0 {
|
2019-08-13 13:57:26 +02:00
|
|
|
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
|
2020-04-12 18:53:57 +02:00
|
|
|
func (c *ClauseHaving) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
|
2019-08-11 09:52:02 +02:00
|
|
|
if c.Condition == nil {
|
2019-08-13 13:57:26 +02:00
|
|
|
return
|
2019-08-11 09:52:02 +02:00
|
|
|
}
|
2019-05-08 13:47:01 +02:00
|
|
|
|
2019-08-13 13:57:26 +02:00
|
|
|
out.NewLine()
|
|
|
|
|
out.WriteString("HAVING")
|
2019-08-11 18:57:40 +02:00
|
|
|
|
2019-08-13 13:57:26 +02:00
|
|
|
out.IncreaseIdent()
|
2020-04-12 18:53:57 +02:00
|
|
|
c.Condition.serialize(statementType, out, NoWrap.WithFallTrough(options)...)
|
2019-08-13 13:57:26 +02:00
|
|
|
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 {
|
2019-09-17 13:34:47 +02:00
|
|
|
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
|
2020-04-12 18:53:57 +02:00
|
|
|
func (o *ClauseOrderBy) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
|
2019-08-11 09:52:02 +02:00
|
|
|
if o.List == nil {
|
2019-08-13 13:57:26 +02:00
|
|
|
return
|
2019-08-11 09:52:02 +02:00
|
|
|
}
|
|
|
|
|
|
2019-09-17 13:34:47 +02:00
|
|
|
if !o.SkipNewLine {
|
|
|
|
|
out.NewLine()
|
|
|
|
|
}
|
2019-08-13 13:57:26 +02:00
|
|
|
out.WriteString("ORDER BY")
|
2019-08-11 18:57:40 +02:00
|
|
|
|
2019-08-13 13:57:26 +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)
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-13 13:57:26 +02:00
|
|
|
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
|
2020-04-12 18:53:57 +02:00
|
|
|
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 {
|
2024-02-13 14:01:13 +01:00
|
|
|
Count IntegerExpression
|
2019-05-12 18:15:23 +02:00
|
|
|
}
|
|
|
|
|
|
2019-08-17 18:32:01 +02:00
|
|
|
// Serialize serializes clause into SQLBuilder
|
2020-04-12 18:53:57 +02:00
|
|
|
func (o *ClauseOffset) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
|
2024-02-13 14:01:13 +01:00
|
|
|
if is.Nil(o.Count) {
|
|
|
|
|
return
|
2019-08-11 09:52:02 +02:00
|
|
|
}
|
2024-02-13 14:01:13 +01:00
|
|
|
|
|
|
|
|
out.NewLine()
|
|
|
|
|
out.WriteString("OFFSET")
|
|
|
|
|
o.Count.serialize(statementType, out, options...)
|
2019-08-11 09:52:02 +02:00
|
|
|
}
|
2019-05-12 18:15:23 +02:00
|
|
|
|
2024-02-07 11:07:50 +01:00
|
|
|
// ClauseFetch struct
|
|
|
|
|
type ClauseFetch struct {
|
|
|
|
|
Count IntegerExpression
|
|
|
|
|
WithTies bool
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Serialize serializes ClauseFetch into sql builder output
|
|
|
|
|
func (o *ClauseFetch) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
|
|
|
|
|
if is.Nil(o.Count) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out.NewLine()
|
|
|
|
|
out.WriteString("FETCH FIRST")
|
|
|
|
|
o.Count.serialize(statementType, out, options...)
|
|
|
|
|
|
|
|
|
|
if o.WithTies {
|
|
|
|
|
out.WriteString("ROWS WITH TIES")
|
|
|
|
|
} else {
|
|
|
|
|
out.WriteString("ROWS ONLY")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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
|
2020-04-12 18:53:57 +02:00
|
|
|
func (f *ClauseFor) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
|
2019-08-11 09:52:02 +02:00
|
|
|
if f.Lock == nil {
|
2019-08-13 13:57:26 +02:00
|
|
|
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")
|
2020-04-12 18:53:57 +02:00
|
|
|
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 {
|
2021-10-21 13:31:54 +02:00
|
|
|
Operator string
|
|
|
|
|
All bool
|
|
|
|
|
Selects []SerializerStatement
|
|
|
|
|
OrderBy ClauseOrderBy
|
|
|
|
|
Limit ClauseLimit
|
|
|
|
|
Offset ClauseOffset
|
|
|
|
|
SkipSelectWrap bool
|
2019-05-03 12:51:57 +02:00
|
|
|
}
|
|
|
|
|
|
2020-05-24 17:55:28 +02:00
|
|
|
// Projections returns set of projections for ClauseSetStmtOperator
|
|
|
|
|
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
|
2020-04-12 18:53:57 +02:00
|
|
|
func (s *ClauseSetStmtOperator) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
|
2019-08-11 09:52:02 +02:00
|
|
|
if len(s.Selects) < 2 {
|
2019-08-13 13:57:26 +02:00
|
|
|
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 {
|
2021-10-21 13:31:54 +02:00
|
|
|
if s.SkipSelectWrap {
|
|
|
|
|
out.NewLine()
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-11 09:52:02 +02:00
|
|
|
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 {
|
2019-08-13 13:57:26 +02:00
|
|
|
panic("jet: select statement of '" + s.Operator + "' is nil")
|
2019-08-11 09:52:02 +02:00
|
|
|
}
|
|
|
|
|
|
2021-10-21 13:31:54 +02:00
|
|
|
if s.SkipSelectWrap {
|
|
|
|
|
options = append(FallTrough(options), NoWrap)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
selectStmt.serialize(statementType, out, options...)
|
2019-08-11 09:52:02 +02:00
|
|
|
}
|
|
|
|
|
|
2019-08-13 13:57:26 +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
|
2022-09-29 13:33:00 +02:00
|
|
|
|
|
|
|
|
// MySQL only
|
|
|
|
|
OptimizerHints optimizerHints
|
2019-08-11 09:52:02 +02:00
|
|
|
}
|
2019-05-12 18:15:23 +02:00
|
|
|
|
2019-08-17 18:32:01 +02:00
|
|
|
// Serialize serializes clause into SQLBuilder
|
2020-04-12 18:53:57 +02:00
|
|
|
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")
|
2022-09-29 13:33:00 +02:00
|
|
|
u.OptimizerHints.Serialize(statementType, out, options...)
|
2019-05-12 18:15:23 +02:00
|
|
|
|
2023-07-21 14:11:31 +02:00
|
|
|
if is.Nil(u.Table) {
|
2019-08-13 13:57:26 +02:00
|
|
|
panic("jet: table to update is nil")
|
2019-08-11 09:52:02 +02:00
|
|
|
}
|
|
|
|
|
|
2020-04-12 18:53:57 +02:00
|
|
|
u.Table.serialize(statementType, out, FallTrough(options)...)
|
2019-05-03 12:51:57 +02:00
|
|
|
}
|
|
|
|
|
|
2020-05-09 10:49:09 +02:00
|
|
|
// SetClause struct
|
|
|
|
|
type SetClause 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
|
2020-05-09 10:49:09 +02:00
|
|
|
func (s *SetClause) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
|
|
|
|
|
if len(s.Values) == 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
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) {
|
2019-08-13 13:57:26 +02:00
|
|
|
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 {
|
2020-05-09 10:49:09 +02:00
|
|
|
out.WriteString(",")
|
2019-08-11 12:13:59 +02:00
|
|
|
out.NewLine()
|
|
|
|
|
}
|
2019-08-11 09:52:02 +02:00
|
|
|
|
2019-08-11 12:13:59 +02:00
|
|
|
if column == nil {
|
2019-08-13 13:57:26 +02:00
|
|
|
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
|
|
|
|
2021-05-09 17:17:14 +02:00
|
|
|
out.WriteIdentifier(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
|
|
|
|
2020-04-12 18:53:57 +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
|
2022-09-29 13:33:00 +02:00
|
|
|
|
|
|
|
|
// MySQL only
|
|
|
|
|
OptimizerHints optimizerHints
|
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
|
2020-04-12 18:53:57 +02:00
|
|
|
func (i *ClauseInsert) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
|
2023-07-21 14:11:31 +02:00
|
|
|
if is.Nil(i.Table) {
|
2019-08-13 13:57:26 +02:00
|
|
|
panic("jet: table is nil for INSERT clause")
|
2019-08-11 09:52:02 +02:00
|
|
|
}
|
|
|
|
|
|
2022-09-29 13:33:00 +02:00
|
|
|
out.NewLine()
|
|
|
|
|
out.WriteString("INSERT")
|
|
|
|
|
i.OptimizerHints.Serialize(statementType, out, options...)
|
|
|
|
|
out.WriteString("INTO")
|
|
|
|
|
|
2019-08-13 13:57:26 +02:00
|
|
|
i.Table.serialize(statementType, out)
|
2019-08-11 09:52:02 +02:00
|
|
|
|
|
|
|
|
if len(i.Columns) > 0 {
|
|
|
|
|
out.WriteString("(")
|
|
|
|
|
|
2019-08-13 13:57:26 +02:00
|
|
|
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
|
2020-04-12 18:53:57 +02:00
|
|
|
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 {
|
2019-08-13 13:57:26 +02:00
|
|
|
panic("jet: VALUES or QUERY has to be specified for INSERT statement")
|
2019-08-12 12:27:33 +02:00
|
|
|
}
|
|
|
|
|
|
2020-04-12 18:53:57 +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
|
2022-08-23 12:23:46 +02:00
|
|
|
As string
|
2019-05-12 18:15:23 +02:00
|
|
|
}
|
|
|
|
|
|
2019-08-17 18:32:01 +02:00
|
|
|
// Serialize serializes clause into SQLBuilder
|
2020-04-12 18:53:57 +02:00
|
|
|
func (v *ClauseValues) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
|
2019-08-11 09:52:02 +02:00
|
|
|
if len(v.Rows) == 0 {
|
2019-08-13 13:57:26 +02:00
|
|
|
return
|
2019-06-30 17:16:00 +02:00
|
|
|
}
|
|
|
|
|
|
2020-04-12 18:53:57 +02:00
|
|
|
out.NewLine()
|
2019-08-11 09:52:02 +02:00
|
|
|
out.WriteString("VALUES")
|
|
|
|
|
|
|
|
|
|
for rowIndex, row := range v.Rows {
|
|
|
|
|
if rowIndex > 0 {
|
|
|
|
|
out.WriteString(",")
|
2020-04-12 18:53:57 +02:00
|
|
|
out.NewLine()
|
|
|
|
|
} else {
|
|
|
|
|
out.IncreaseIdent(7)
|
2019-08-11 09:52:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out.WriteString("(")
|
|
|
|
|
|
2019-08-13 13:57:26 +02:00
|
|
|
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
|
|
|
}
|
2022-08-23 12:23:46 +02:00
|
|
|
|
|
|
|
|
if len(v.As) > 0 {
|
|
|
|
|
out.WriteString("AS")
|
|
|
|
|
out.WriteIdentifier(v.As)
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-12 18:53:57 +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 {
|
2021-10-21 13:31:54 +02:00
|
|
|
Query SerializerStatement
|
|
|
|
|
SkipSelectWrap bool
|
2019-08-11 09:52:02 +02:00
|
|
|
}
|
2019-06-30 17:16:00 +02:00
|
|
|
|
2019-08-17 18:32:01 +02:00
|
|
|
// Serialize serializes clause into SQLBuilder
|
2020-04-12 18:53:57 +02:00
|
|
|
func (v *ClauseQuery) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
|
2019-08-11 09:52:02 +02:00
|
|
|
if v.Query == nil {
|
2019-08-13 13:57:26 +02:00
|
|
|
return
|
2019-08-11 09:52:02 +02:00
|
|
|
}
|
|
|
|
|
|
2021-10-21 13:31:54 +02:00
|
|
|
if v.SkipSelectWrap {
|
|
|
|
|
options = append(FallTrough(options), NoWrap)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v.Query.serialize(statementType, out, options...)
|
2019-06-30 17:16:00 +02:00
|
|
|
}
|
|
|
|
|
|
2019-08-17 18:32:01 +02:00
|
|
|
// ClauseDelete struct
|
2019-08-11 09:52:02 +02:00
|
|
|
type ClauseDelete struct {
|
|
|
|
|
Table SerializerTable
|
2022-09-29 13:33:00 +02:00
|
|
|
|
|
|
|
|
// MySQL only
|
|
|
|
|
OptimizerHints optimizerHints
|
2019-04-29 14:39:48 +02:00
|
|
|
}
|
|
|
|
|
|
2019-08-17 18:32:01 +02:00
|
|
|
// Serialize serializes clause into SQLBuilder
|
2020-04-12 18:53:57 +02:00
|
|
|
func (d *ClauseDelete) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
|
2019-08-11 12:13:59 +02:00
|
|
|
out.NewLine()
|
2022-09-29 13:33:00 +02:00
|
|
|
out.WriteString("DELETE")
|
|
|
|
|
d.OptimizerHints.Serialize(statementType, out, options...)
|
|
|
|
|
out.WriteString("FROM")
|
2020-04-12 18:53:57 +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
|
2020-04-12 18:53:57 +02:00
|
|
|
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(", ")
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-12 18:53:57 +02:00
|
|
|
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
|
2020-04-12 18:53:57 +02:00
|
|
|
func (d *ClauseOptional) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
|
2019-08-11 09:52:02 +02:00
|
|
|
if !d.Show {
|
2019-08-13 13:57:26 +02:00
|
|
|
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
|
2020-04-12 18:53:57 +02:00
|
|
|
func (i *ClauseIn) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
|
2019-08-11 09:52:02 +02:00
|
|
|
if i.LockMode == "" {
|
2019-08-13 13:57:26 +02:00
|
|
|
return
|
2019-08-11 09:52:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out.WriteString("IN")
|
|
|
|
|
out.WriteString(string(i.LockMode))
|
|
|
|
|
out.WriteString("MODE")
|
|
|
|
|
}
|
2019-09-17 13:34:47 +02:00
|
|
|
|
|
|
|
|
// WindowDefinition struct
|
|
|
|
|
type WindowDefinition struct {
|
|
|
|
|
Name string
|
|
|
|
|
Window Window
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ClauseWindow struct
|
|
|
|
|
type ClauseWindow struct {
|
|
|
|
|
Definitions []WindowDefinition
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Serialize serializes clause into SQLBuilder
|
2020-04-12 18:53:57 +02:00
|
|
|
func (i *ClauseWindow) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
|
2019-09-17 13:34:47 +02:00
|
|
|
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
|
|
|
|
|
}
|
2020-04-12 18:53:57 +02:00
|
|
|
def.Window.serialize(statementType, out, FallTrough(options)...)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetPair clause
|
|
|
|
|
type SetPair struct {
|
|
|
|
|
Column ColumnSerializer
|
|
|
|
|
Value Serializer
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-09 10:49:09 +02:00
|
|
|
// SetClauseNew clause
|
|
|
|
|
type SetClauseNew []ColumnAssigment
|
2020-04-12 18:53:57 +02:00
|
|
|
|
2020-05-09 10:49:09 +02:00
|
|
|
// Serialize for SetClauseNew
|
|
|
|
|
func (s SetClauseNew) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
|
|
|
|
|
if len(s) == 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
2020-04-12 18:53:57 +02:00
|
|
|
out.NewLine()
|
|
|
|
|
out.WriteString("SET")
|
|
|
|
|
out.IncreaseIdent(4)
|
|
|
|
|
|
2020-05-03 20:46:21 +02:00
|
|
|
for i, assigment := range s {
|
2020-04-12 18:53:57 +02:00
|
|
|
if i > 0 {
|
|
|
|
|
out.WriteString(",")
|
|
|
|
|
out.NewLine()
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-03 20:46:21 +02:00
|
|
|
assigment.serialize(statementType, out, FallTrough(options)...)
|
2019-09-17 13:34:47 +02:00
|
|
|
}
|
2020-05-03 20:46:21 +02:00
|
|
|
|
2020-04-12 18:53:57 +02:00
|
|
|
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)...)
|
2019-09-17 13:34:47 +02:00
|
|
|
}
|
2021-10-21 13:31:54 +02:00
|
|
|
|
|
|
|
|
// ClauseReturning type
|
|
|
|
|
type ClauseReturning struct {
|
|
|
|
|
ProjectionList []Projection
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Serialize for ClauseReturning
|
|
|
|
|
func (r *ClauseReturning) Serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
|
|
|
|
|
if len(r.ProjectionList) == 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out.NewLine()
|
|
|
|
|
out.WriteString("RETURNING")
|
|
|
|
|
out.IncreaseIdent()
|
|
|
|
|
out.WriteProjections(statementType, r.ProjectionList)
|
|
|
|
|
out.DecreaseIdent()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Projections for ClauseReturning
|
|
|
|
|
func (r ClauseReturning) Projections() ProjectionList {
|
|
|
|
|
return r.ProjectionList
|
|
|
|
|
}
|