-
Notifications
You must be signed in to change notification settings - Fork 0
/
SelectStatement.cfc
203 lines (159 loc) · 7.9 KB
/
SelectStatement.cfc
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
component accessors = "true" extends = "FilterStatement" {
property name = "aggregates" type = "array" setter = "false";
property name = "groupByString" type = "string" setter = "false" default = "";
property name = "groupBySQL" type = "string" setter = "false" default = "";
property name = "orderBySQL" type = "string" setter = "false" default = "";
property name = "orderCriteria" type = "array" setter = "false";
property name = "selectSQL" type = "string" setter = "false" default = "*";
SelectStatement function init(required IQueryable queryable) {
// init internals that don't have defaults
structAppend(
variables,
{
"aggregates": [],
"orderCriteria": [],
"orderBy": "",
"select": arguments.queryable.getFieldList()
}
);
return super.init(arguments.queryable);
}
query function execute(numeric limit = -1, numeric offset = 0) {
if(arrayLen(variables.aggregates) > 0) {
if(len(variables.groupBy) == 0) {
local.groupBy = variables.select;
// exclude all aggregates - in order to group on everything else
for(local.aggregate in variables.aggregates) {
local.groupBy = listDeleteAt(local.groupBy, listFindNoCase(local.groupBy, local.aggregate.alias));
}
if(len(local.groupBy) > 0) {
this.groupBy(local.groupBy);
}
}
// replace the alias with the actual calculated columns
for(local.aggregate in variables.aggregates) {
variables.selectSQL = variables.selectSQL.replaceNoCase(local.aggregate.alias, (local.aggregate.operation & "(" & local.aggregate.field & ") " & local.aggregate.alias));
}
}
arguments.selectStatement = this;
return getQueryable().executeSelect(argumentCollection = arguments);
}
string function getOrderBy() {
return variables.orderBy;
}
string function getSelect() {
return variables.select;
}
SelectStatement function groupBy(string groupBy = "") {
variables.groupBy = arguments.groupBy;
variables.groupBySQL = "";
if(variables.groupBy.listLen() > 0) {
for(local.groupBy in variables.groupBy) {
local.field = trim(local.groupBy);
if(!getQueryable().fieldExists(local.field)) {
throw(type = "lib.sql.UndefinedGroupByFieldException", message = "The field '#local.field#' does not exist in this IQueryable");
} else {
// append to our list of active fields
variables.activeFieldList = variables.activeFieldList.listAppend(local.field);
variables.groupBySQL = listAppend(variables.groupBySQL, local.field);
}
}
// remove any dupes in our list
variables.activeFieldList = variables.activeFieldList.listRemoveDuplicates();
}
variables.groupBySQL = "GROUP BY " & variables.groupBySQL;
return this;
}
SelectStatement function orderBy(string orderBy = "") {
variables.orderBy = arguments.orderBy;
variables.orderBySQL = "";
variables.orderCriteria = [];
if(variables.orderBy.listLen() > 0) {
for(local.orderBy in variables.orderBy) {
local.orderField = trim(local.orderBy);
if(local.orderField.listLen(" ") == 1) {
local.orderField = local.orderField & " ASC";
} else if(local.orderField.listLen(" ") > 2) {
throw(type = "lib.sql.ParseOrderErrorException", message = "The statement '#local.orderField#' could not be parsed");
}
local.field = local.orderField.listFirst(" ").trim();
local.direction = local.orderField.listLast(" ");
if((!getQueryable().fieldExists(local.field) || !getQueryable().fieldIsFilterable(local.field))
&& !listFindNoCase(variables.select, local.field)
) {
throw(type = "lib.sql.UndefinedOrderByFieldException", message = "The field '#local.field#' does not exist, or is not filterable");
} else if(local.direction != "ASC" && local.direction != "DESC") {
throw(type = "lib.sql.ParseOrderErrorException", message = "The direction '#local.direction#' is not supported");
} else {
if(getQueryable().fieldExists(local.field)) {
// preserve the case dictated within the IQueryable
local.field = listGetAt(variables.fieldList, listFindNoCase(variables.fieldList, local.field));
variables.orderBySQL = listAppend(variables.orderBySQL, (getQueryable().getFieldSQL(local.field).len() > 0 ? getQueryable().getFieldSQL(local.field) : local.field) & " " & local.direction);
} else {
local.field = listGetAt(variables.select, listFindNoCase(variables.select, local.field));
// a calculated field present in the select list
variables.orderBySQL = listAppend(variables.orderBySQL, local.field & " " & local.direction);
}
// append to our list of active fields
variables.activeFieldList = variables.activeFieldList.listAppend(local.field);
// update order criteria and our SQL
arrayAppend(variables.orderCriteria, local.field & " " & local.direction);
}
}
// remove any dupes in our list
variables.activeFieldList = variables.activeFieldList.listRemoveDuplicates();
variables.orderBySQL = "ORDER BY " & variables.orderBySQL;
}
return this;
}
SelectStatement function select(string select = "*") {
// assume that by calling select, the user is starting from the top
variables.activeFieldList = "";
variables.select = arguments.select;
variables.selectSQL = "";
if(variables.select == "*") {
variables.select = variables.fieldList;
}
variables.select = variables.select.REReplace("\s+", "", "all");
for(local.field in variables.select) {
if(getQueryable().fieldExists(local.field)) {
// preserve the case dictated within the IQueryable
local.field = listGetAt(variables.fieldList, listFindNoCase(variables.fieldList, local.field));
variables.selectSQL = variables.selectSQL.listAppend(getQueryable().getFieldSQL(local.field).len() > 0 ? getQueryable().getFieldSQL(local.field) & " " & local.field : local.field);
} else {
// check if it's a calculated column
local.aggregateCheck = REFindNoCase("^(AVG|COUNT|MAX|MIN|SUM)\s*\((\w+)\)$", local.field, 1, true);
if(arrayLen(local.aggregateCheck.len) == 3) {
local.rawField = local.field;
local.operation = uCase(mid(local.field, local.aggregateCheck.pos[2], local.aggregateCheck.len[2]));
local.field = mid(local.field, local.aggregateCheck.pos[3], local.aggregateCheck.len[3]);
if(getQueryable().fieldExists(local.field)) {
if(local.operation == "COUNT" || arrayFindNoCase([ "bigint", "date", "datetime", "decimal", "double", "float", "integer", "money", "numeric", "real", "smallint", "time", "timestamp", "tinyint" ], getQueryable().getFieldSQLType(local.field))) {
local.aggregate = {};
// preserve the case dictated within the IQueryable
local.aggregate.field = listGetAt(variables.fieldList, listFindNoCase(variables.fieldList, local.field));
local.aggregate.alias = lCase(local.operation) & uCase(mid(local.aggregate.field, 1, 1)) & mid(local.aggregate.field, 2, len(local.aggregate.field));
local.aggregate.operation = local.operation;
arrayAppend(variables.aggregates, local.aggregate);
// replace the computed value w/ the alias for now
variables.select = replaceNoCase(variables.select, local.rawField, local.aggregate.alias);
// the actual SQL will be dropped in just before exection
local.field = local.aggregate.alias;
variables.selectSQL = variables.selectSQL.listAppend(local.field);
} else {
throw(type = "lib.sql.InvalidAggregateFieldException", message = "The field '#local.field#' is not viable for aggregation");
}
} else {
throw(type = "lib.sql.UndefinedSelectFieldException", message = "The field '#local.field#' does not exist");
}
} else {
throw(type = "lib.sql.UndefinedSelectFieldException", message = "The field '#local.field#' does not exist");
}
}
variables.activeFieldList = variables.activeFieldList.listAppend(local.field);
}
variables.activeFieldList = variables.activeFieldList.listRemoveDuplicates();
variables.selectSQL = "SELECT " & variables.selectSQL;
return this;
}
}