forked from go-jet/jet
/
with_statement.go
110 lines (89 loc) · 2.73 KB
/
with_statement.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package jet
import "fmt"
// WITH function creates new with statement from list of common table expressions for specified dialect
func WITH(dialect Dialect, recursive bool, cte ...*CommonTableExpression) func(statement Statement) Statement {
newWithImpl := &withImpl{
recursive: recursive,
ctes: cte,
serializerStatementInterfaceImpl: serializerStatementInterfaceImpl{
dialect: dialect,
statementType: WithStatementType,
},
}
newWithImpl.parent = newWithImpl
return func(primaryStatement Statement) Statement {
serializerStatement, ok := primaryStatement.(SerializerStatement)
if !ok {
panic("jet: unsupported main WITH statement.")
}
newWithImpl.primaryStatement = serializerStatement
return newWithImpl
}
}
type withImpl struct {
serializerStatementInterfaceImpl
recursive bool
ctes []*CommonTableExpression
primaryStatement SerializerStatement
}
func (w withImpl) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
out.NewLine()
out.WriteString("WITH")
if w.recursive {
out.WriteString("RECURSIVE")
}
for i, cte := range w.ctes {
if i > 0 {
out.WriteString(",")
}
cte.serialize(statement, out, FallTrough(options)...)
}
w.primaryStatement.serialize(statement, out, NoWrap.WithFallTrough(options)...)
}
func (w withImpl) projections() ProjectionList {
return ProjectionList{}
}
// CommonTableExpression contains information about a CTE.
type CommonTableExpression struct {
selectTableImpl
NotMaterialized bool
Columns []ColumnExpression
}
// CTE creates new named CommonTableExpression
func CTE(name string, columns ...ColumnExpression) CommonTableExpression {
cte := CommonTableExpression{
selectTableImpl: NewSelectTable(nil, name),
Columns: columns,
}
for _, column := range cte.Columns {
column.setSubQuery(cte)
}
return cte
}
func (c CommonTableExpression) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
if statement == WithStatementType { // serialize CTE definition
out.WriteIdentifier(c.alias)
if len(c.Columns) > 0 {
out.WriteByte('(')
SerializeColumnExpressionNames(c.Columns, out)
out.WriteByte(')')
}
out.WriteString("AS")
if c.NotMaterialized {
out.WriteString("NOT MATERIALIZED")
}
if c.Statement == nil {
panic(fmt.Sprintf("jet: '%s' CTE is not defined", c.alias))
}
c.Statement.serialize(statement, out, FallTrough(options)...)
} else { // serialize CTE in FROM clause
out.WriteIdentifier(c.alias)
}
}
// AllColumns returns list of all projections in the CTE
func (c CommonTableExpression) AllColumns() ProjectionList {
if len(c.Columns) > 0 {
return ColumnListToProjectionList(c.Columns)
}
return c.selectTableImpl.AllColumns()
}