-
Notifications
You must be signed in to change notification settings - Fork 32
/
compile.go
157 lines (132 loc) · 5.74 KB
/
compile.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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package sqlite3
import (
"fmt"
"reflect"
"strings"
"github.com/yaoapp/xun"
"github.com/yaoapp/xun/dbal"
)
// CompileSelect Compile a select query into SQL.
func (grammarSQL SQLite3) CompileSelect(query *dbal.Query) string {
bindingOffset := 0
return grammarSQL.CompileSelectOffset(query, &bindingOffset)
}
// CompileSelectOffset Compile a select query into SQL.
func (grammarSQL SQLite3) CompileSelectOffset(query *dbal.Query, offset *int) string {
// SQL STMT
if query.SQL != "" {
if !strings.Contains(query.SQL, "limit") && !strings.Contains(query.SQL, "offset") {
limit := grammarSQL.CompileLimit(query, query.Limit, offset)
offset := grammarSQL.CompileOffset(query, query.Offset)
return strings.TrimSpace(fmt.Sprintf("%s %s %s", query.SQL, limit, offset))
}
return query.SQL
}
if len(query.Unions) > 0 && query.Aggregate.Func != "" {
return grammarSQL.CompileUnionAggregate(query)
}
sqls := map[string]string{}
// If the query does not have any columns set, we'll set the columns to the
// * character to just get all of the columns from the database. Then we
// can build the query and concatenate all the pieces together as one.
columns := query.Columns
if len(columns) == 0 {
query.AddColumn(grammarSQL.Raw("*"))
}
// To compile the query, we'll spin through each component of the query and
// see if that component exists. If it does we'll just call the compiler
// function for the component which is responsible for making the SQL.
sqls["aggregate"] = grammarSQL.CompileAggregate(query, query.Aggregate)
sqls["columns"] = grammarSQL.CompileColumns(query, query.Columns, offset)
sqls["from"] = grammarSQL.CompileFrom(query, query.From, offset)
sqls["joins"] = grammarSQL.CompileJoins(query, query.Joins, offset)
sqls["wheres"] = grammarSQL.CompileWheres(query, query.Wheres, offset)
sqls["groups"] = grammarSQL.CompileGroups(query, query.Groups, offset)
sqls["havings"] = grammarSQL.CompileHavings(query, query.Havings, offset)
sqls["orders"] = grammarSQL.CompileOrders(query, query.Orders, offset)
sqls["limit"] = grammarSQL.CompileLimit(query, query.Limit, offset)
sqls["offset"] = grammarSQL.CompileOffset(query, query.Offset)
sqls["lock"] = grammarSQL.CompileLock(query, query.Lock)
sql := ""
for _, name := range []string{"aggregate", "columns", "from", "joins", "wheres", "groups", "havings", "orders", "limit", "offset", "lock"} {
segment, has := sqls[name]
if has && segment != "" {
sql = sql + segment + " "
}
}
// Compile unions
if len(query.Unions) > 0 {
sql = fmt.Sprintf("%s %s", grammarSQL.WrapUnion(sql), grammarSQL.CompileUnions(query, query.Unions, offset))
}
// reset columns
query.Columns = columns
return strings.Trim(sql, " ")
}
// CompileWheres Compile an update statement into SQL.
func (grammarSQL SQLite3) CompileWheres(query *dbal.Query, wheres []dbal.Where, bindingOffset *int) string {
// Each type of where clauses has its own compiler function which is responsible
// for actually creating the where clauses SQL. This helps keep the code nice
// and maintainable since each clause has a very small method that it uses.
if len(wheres) == 0 {
return ""
}
clauses := []string{}
// If we actually have some where clauses, we will strip off the first boolean
// operator, which is added by the query builders for convenience so we can
// avoid checking for the first clauses in each of the compilers methods.
for _, where := range wheres {
boolen := strings.ToLower(where.Boolean)
typ := xun.UpperFirst(where.Type)
// WhereBasic, WhereDate, WhereTime ...
method := reflect.ValueOf(grammarSQL).MethodByName(fmt.Sprintf("Where%s", typ))
if method.Kind() == reflect.Func {
in := []reflect.Value{
reflect.ValueOf(query),
reflect.ValueOf(where),
reflect.ValueOf(bindingOffset),
}
out := method.Call(in)
clauses = append(clauses, fmt.Sprintf("%s %s", boolen, out[0].String()))
}
}
conjunction := "where"
if query.IsJoinClause {
conjunction = "on"
}
return fmt.Sprintf("%s %s", conjunction, grammarSQL.RemoveLeadingBoolean(strings.Join(clauses, " ")))
}
// WhereDate Compile a "where date" clause.
func (grammarSQL SQLite3) WhereDate(query *dbal.Query, where dbal.Where, bindingOffset *int) string {
return grammarSQL.WhereDateBased("%Y-%m-%d", query, where, bindingOffset)
}
// WhereTime Compile a "where time" clause.
func (grammarSQL SQLite3) WhereTime(query *dbal.Query, where dbal.Where, bindingOffset *int) string {
return grammarSQL.WhereDateBased("%H:%M:%S", query, where, bindingOffset)
}
// WhereDay Compile a "where day" clause.
func (grammarSQL SQLite3) WhereDay(query *dbal.Query, where dbal.Where, bindingOffset *int) string {
return grammarSQL.WhereDateBased("%d", query, where, bindingOffset)
}
// WhereMonth Compile a "where month" clause.
func (grammarSQL SQLite3) WhereMonth(query *dbal.Query, where dbal.Where, bindingOffset *int) string {
return grammarSQL.WhereDateBased("%m", query, where, bindingOffset)
}
// WhereYear Compile a "where year" clause.
func (grammarSQL SQLite3) WhereYear(query *dbal.Query, where dbal.Where, bindingOffset *int) string {
return grammarSQL.WhereDateBased("%Y", query, where, bindingOffset)
}
// WhereDateBased Compile a date based where clause.
func (grammarSQL SQLite3) WhereDateBased(typ string, query *dbal.Query, where dbal.Where, bindingOffset *int) string {
value := ""
if !dbal.IsExpression(where.Value) {
*bindingOffset = *bindingOffset + where.Offset
value = grammarSQL.Parameter(where.Value, *bindingOffset)
} else {
value = where.Value.(dbal.Expression).GetValue()
}
return fmt.Sprintf("strftime('%s',%s) %s cast(%s as text)", typ, grammarSQL.Wrap(where.Column), where.Operator, value)
}
// CompileLock the lock into SQL.
func (grammarSQL SQLite3) CompileLock(query *dbal.Query, lock interface{}) string {
return ""
}