foxhound 2.0.3 → 2.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,1029 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FoxHound MSSQL Dialect
|
|
3
|
+
*
|
|
4
|
+
* @license MIT
|
|
5
|
+
*
|
|
6
|
+
* For a MSSQL query override:
|
|
7
|
+
// An underscore template with the following values:
|
|
8
|
+
// <%= DataElements %> = Field1, Field2, Field3, Field4
|
|
9
|
+
// <%= Begin %> = 0
|
|
10
|
+
// <%= Cap %> = 10
|
|
11
|
+
// <%= Filter %> = WHERE StartDate > :MyStartDate
|
|
12
|
+
// <%= Sort %> = ORDER BY Field1
|
|
13
|
+
// The values are empty strings if they aren't set.
|
|
14
|
+
*
|
|
15
|
+
* @author Steven Velozo <steven@velozo.com>
|
|
16
|
+
* @class FoxHoundDialectMSSQL
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
var FoxHoundDialectMSSQL = function(pFable)
|
|
20
|
+
{
|
|
21
|
+
//Request time from SQL server with microseconds resolution
|
|
22
|
+
const SQL_NOW = "NOW(3)";
|
|
23
|
+
|
|
24
|
+
_Fable = pFable;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Generate a table name from the scope
|
|
28
|
+
*
|
|
29
|
+
* @method: generateTableName
|
|
30
|
+
* @param: {Object} pParameters SQL Query Parameters
|
|
31
|
+
* @return: {String} Returns the table name clause
|
|
32
|
+
*/
|
|
33
|
+
var generateTableName = function(pParameters)
|
|
34
|
+
{
|
|
35
|
+
// Every Foxhound query has a table name; this puts it on here even if there are no columns
|
|
36
|
+
// Which occurs when you generate a query like SELECT COUNT(*) FROM SomeTable;
|
|
37
|
+
if (!pParameters.query.hasOwnProperty('parameterTypes'))
|
|
38
|
+
{
|
|
39
|
+
pParameters.query.parameterTypes = {};
|
|
40
|
+
}
|
|
41
|
+
return ' '+pParameters.scope;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
var generateMSSQLParameterTypeEntry = function(pParameters, pColumnParameterName, pColumn)
|
|
45
|
+
{
|
|
46
|
+
// Lazily create the parameterTypes object if it doesn't exist
|
|
47
|
+
if (!pParameters.query.hasOwnProperty('parameterTypes'))
|
|
48
|
+
{
|
|
49
|
+
pParameters.query.parameterTypes = {};
|
|
50
|
+
}
|
|
51
|
+
// Find the column parameter type for our prepared statement
|
|
52
|
+
let tmpColumnParameterTypeString = 'VarChar';
|
|
53
|
+
if (typeof(pColumn) == 'object')
|
|
54
|
+
{
|
|
55
|
+
// See if it has a type, set the type string
|
|
56
|
+
tmpColumnParameterTypeString = pColumn.Type;
|
|
57
|
+
}
|
|
58
|
+
else if (typeof(pColumn) == 'string')
|
|
59
|
+
{
|
|
60
|
+
var tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];
|
|
61
|
+
for (let i = 0; i < tmpSchema.length; i++)
|
|
62
|
+
{
|
|
63
|
+
if (tmpSchema[i].Column == pColumn)
|
|
64
|
+
{
|
|
65
|
+
tmpColumnParameterTypeString = tmpSchema[i].Type;
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else
|
|
71
|
+
{
|
|
72
|
+
_Fable.log.warn(`Meadow MSSQL query attempted to add a parameter type but no valid column schema entry object or column name was passed; parameter name ${pColumnParameterName}.`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if ((tmpColumnParameterTypeString == null) || (tmpColumnParameterTypeString == undefined))
|
|
76
|
+
{
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
switch (tmpColumnParameterTypeString)
|
|
80
|
+
{
|
|
81
|
+
case 'AutoIdentity':
|
|
82
|
+
case 'CreateIDUser':
|
|
83
|
+
case 'UpdateIDUser':
|
|
84
|
+
case 'DeleteIDUser':
|
|
85
|
+
|
|
86
|
+
case 'Integer':
|
|
87
|
+
pParameters.query.parameterTypes[pColumnParameterName] = 'Int';
|
|
88
|
+
break;
|
|
89
|
+
|
|
90
|
+
case 'Deleted':
|
|
91
|
+
case 'Boolean':
|
|
92
|
+
pParameters.query.parameterTypes[pColumnParameterName] = 'TinyInt';
|
|
93
|
+
break;
|
|
94
|
+
|
|
95
|
+
case 'Decimal':
|
|
96
|
+
pParameters.query.parameterTypes[pColumnParameterName] = 'Decimal';
|
|
97
|
+
break;
|
|
98
|
+
|
|
99
|
+
case 'String':
|
|
100
|
+
case 'AutoGUID':
|
|
101
|
+
pParameters.query.parameterTypes[pColumnParameterName] = 'Char';
|
|
102
|
+
break;
|
|
103
|
+
|
|
104
|
+
case 'CreateDate':
|
|
105
|
+
case 'UpdateDate':
|
|
106
|
+
case 'DeleteDate':
|
|
107
|
+
|
|
108
|
+
case 'DateTime':
|
|
109
|
+
pParameters.query.parameterTypes[pColumnParameterName] = 'DateTime';
|
|
110
|
+
break;
|
|
111
|
+
|
|
112
|
+
default:
|
|
113
|
+
// TODO: This might should throw? It would mean a new type was added to stricture we don't know about.
|
|
114
|
+
pParameters.query.parameterTypes[pColumnParameterName] = tmpColumnParameterTypeString;
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Generate a field list from the array of dataElements
|
|
123
|
+
*
|
|
124
|
+
* Each entry in the dataElements is a simple string
|
|
125
|
+
*
|
|
126
|
+
* @method: generateFieldList
|
|
127
|
+
* @param: {Object} pParameters SQL Query Parameters
|
|
128
|
+
* @param {Boolean} pIsForCountClause (optional) If true, generate fields for use within a count clause.
|
|
129
|
+
* @return: {String} Returns the field list clause, or empty string if explicit fields are requested but cannot be fulfilled
|
|
130
|
+
* due to missing schema.
|
|
131
|
+
*/
|
|
132
|
+
var generateFieldList = function(pParameters, pIsForCountClause)
|
|
133
|
+
{
|
|
134
|
+
var tmpDataElements = pParameters.dataElements;
|
|
135
|
+
if (!Array.isArray(tmpDataElements) || tmpDataElements.length < 1)
|
|
136
|
+
{
|
|
137
|
+
const tmpTableName = generateTableName(pParameters);
|
|
138
|
+
if (!pIsForCountClause)
|
|
139
|
+
{
|
|
140
|
+
return tmpTableName + '.*';
|
|
141
|
+
}
|
|
142
|
+
// we need to list all of the table fields explicitly; get them from the schema
|
|
143
|
+
const tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];
|
|
144
|
+
if (tmpSchema.length < 1)
|
|
145
|
+
{
|
|
146
|
+
// this means we have no schema; returning an empty string here signals the calling code to handle this case
|
|
147
|
+
return '';
|
|
148
|
+
}
|
|
149
|
+
const idColumn = tmpSchema.find((entry) => entry.Type === 'AutoIdentity');
|
|
150
|
+
if (!idColumn)
|
|
151
|
+
{
|
|
152
|
+
// this means there is no autoincrementing unique ID column; treat as above
|
|
153
|
+
return '';
|
|
154
|
+
}
|
|
155
|
+
const qualifiedIDColumn = `${tmpTableName}.${idColumn.Column}`;
|
|
156
|
+
return ` ${generateSafeFieldName(qualifiedIDColumn)}`;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
var tmpFieldList = ' ';
|
|
160
|
+
for (var i = 0; i < tmpDataElements.length; i++)
|
|
161
|
+
{
|
|
162
|
+
if (i > 0)
|
|
163
|
+
{
|
|
164
|
+
tmpFieldList += ', ';
|
|
165
|
+
}
|
|
166
|
+
if (Array.isArray(tmpDataElements[i]))
|
|
167
|
+
{
|
|
168
|
+
tmpFieldList += generateSafeFieldName(tmpDataElements[i][0]);
|
|
169
|
+
if (tmpDataElements[i].length > 1 && tmpDataElements[i][1])
|
|
170
|
+
{
|
|
171
|
+
tmpFieldList += " AS " + generateSafeFieldName(tmpDataElements[i][1]);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
else
|
|
175
|
+
{
|
|
176
|
+
tmpFieldList += generateSafeFieldName(tmpDataElements[i]);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return tmpFieldList;
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Ensure a field name is properly escaped.
|
|
184
|
+
*/
|
|
185
|
+
var generateSafeFieldName = function(pFieldName)
|
|
186
|
+
{
|
|
187
|
+
return pFieldName;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Generate a query from the array of where clauses
|
|
192
|
+
*
|
|
193
|
+
* Each clause is an object like:
|
|
194
|
+
{
|
|
195
|
+
Column:'Name',
|
|
196
|
+
Operator:'EQ',
|
|
197
|
+
Value:'John',
|
|
198
|
+
Connector:'And',
|
|
199
|
+
Parameter:'Name'
|
|
200
|
+
}
|
|
201
|
+
*
|
|
202
|
+
* @method: generateWhere
|
|
203
|
+
* @param: {Object} pParameters SQL Query Parameters
|
|
204
|
+
* @return: {String} Returns the WHERE clause prefixed with WHERE, or an empty string if unnecessary
|
|
205
|
+
*/
|
|
206
|
+
var generateWhere = function(pParameters)
|
|
207
|
+
{
|
|
208
|
+
var tmpFilter = Array.isArray(pParameters.filter) ? pParameters.filter : [];
|
|
209
|
+
var tmpTableName = generateTableName(pParameters);
|
|
210
|
+
|
|
211
|
+
if (!pParameters.query.disableDeleteTracking)
|
|
212
|
+
{
|
|
213
|
+
// Check if there is a Deleted column on the Schema. If so, we add this to the filters automatically (if not already present)
|
|
214
|
+
var tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];
|
|
215
|
+
for (var i = 0; i < tmpSchema.length; i++)
|
|
216
|
+
{
|
|
217
|
+
// There is a schema entry for it. Process it accordingly.
|
|
218
|
+
var tmpSchemaEntry = tmpSchema[i];
|
|
219
|
+
|
|
220
|
+
if (tmpSchemaEntry.Type === 'Deleted')
|
|
221
|
+
{
|
|
222
|
+
var tmpHasDeletedParameter = false;
|
|
223
|
+
|
|
224
|
+
//first, check to see if filters are already looking for Deleted column
|
|
225
|
+
if (tmpFilter.length > 0)
|
|
226
|
+
{
|
|
227
|
+
for (var x = 0; x < tmpFilter.length; x++)
|
|
228
|
+
{
|
|
229
|
+
if (tmpFilter[x].Column === tmpSchemaEntry.Column)
|
|
230
|
+
{
|
|
231
|
+
tmpHasDeletedParameter = true;
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (!tmpHasDeletedParameter)
|
|
237
|
+
{
|
|
238
|
+
//if not, we need to add it
|
|
239
|
+
tmpFilter.push(
|
|
240
|
+
{
|
|
241
|
+
Column: tmpTableName + '.' + tmpSchemaEntry.Column,
|
|
242
|
+
Operator: '=',
|
|
243
|
+
Value: 0,
|
|
244
|
+
Connector: 'AND',
|
|
245
|
+
Parameter: 'Deleted'
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (tmpFilter.length < 1)
|
|
254
|
+
{
|
|
255
|
+
return '';
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
var tmpWhere = ' WHERE';
|
|
259
|
+
|
|
260
|
+
// This is used to disable the connectors for subsequent queries.
|
|
261
|
+
// Only the open parenthesis operator uses this, currently.
|
|
262
|
+
var tmpLastOperatorNoConnector = false;
|
|
263
|
+
|
|
264
|
+
for (var i = 0; i < tmpFilter.length; i++)
|
|
265
|
+
{
|
|
266
|
+
if ((tmpFilter[i].Connector != 'NONE') && (tmpFilter[i].Operator != ')') && (tmpWhere != ' WHERE') && (tmpLastOperatorNoConnector == false))
|
|
267
|
+
{
|
|
268
|
+
tmpWhere += ' '+tmpFilter[i].Connector;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
tmpLastOperatorNoConnector = false;
|
|
272
|
+
|
|
273
|
+
var tmpColumnParameter;
|
|
274
|
+
|
|
275
|
+
if (tmpFilter[i].Operator === '(')
|
|
276
|
+
{
|
|
277
|
+
// Open a logical grouping
|
|
278
|
+
tmpWhere += ' (';
|
|
279
|
+
tmpLastOperatorNoConnector = true;
|
|
280
|
+
}
|
|
281
|
+
else if (tmpFilter[i].Operator === ')')
|
|
282
|
+
{
|
|
283
|
+
// Close a logical grouping
|
|
284
|
+
tmpWhere += ' )';
|
|
285
|
+
}
|
|
286
|
+
else if (tmpFilter[i].Operator === 'IN' || tmpFilter[i].Operator === "NOT IN")
|
|
287
|
+
{
|
|
288
|
+
tmpColumnParameter = tmpFilter[i].Parameter+'_w'+i;
|
|
289
|
+
// Add the column name, operator and parameter name to the list of where value parenthetical
|
|
290
|
+
tmpWhere += ' '+tmpFilter[i].Column+' '+tmpFilter[i].Operator+' ( @'+tmpColumnParameter+' )';
|
|
291
|
+
pParameters.query.parameters[tmpColumnParameter] = tmpFilter[i].Value;
|
|
292
|
+
// Find the column in the schema
|
|
293
|
+
generateMSSQLParameterTypeEntry(pParameters, tmpColumnParameter, tmpFilter[i].Parameter)
|
|
294
|
+
}
|
|
295
|
+
else if (tmpFilter[i].Operator === 'IS NULL')
|
|
296
|
+
{
|
|
297
|
+
// IS NULL is a special operator which doesn't require a value, or parameter
|
|
298
|
+
tmpWhere += ' '+tmpFilter[i].Column+' '+tmpFilter[i].Operator;
|
|
299
|
+
}
|
|
300
|
+
else if (tmpFilter[i].Operator === 'IS NOT NULL')
|
|
301
|
+
{
|
|
302
|
+
// IS NOT NULL is a special operator which doesn't require a value, or parameter
|
|
303
|
+
tmpWhere += ' '+tmpFilter[i].Column+' '+tmpFilter[i].Operator;
|
|
304
|
+
}
|
|
305
|
+
else
|
|
306
|
+
{
|
|
307
|
+
tmpColumnParameter = tmpFilter[i].Parameter+'_w'+i;
|
|
308
|
+
// Add the column name, operator and parameter name to the list of where value parenthetical
|
|
309
|
+
tmpWhere += ' '+tmpFilter[i].Column+' '+tmpFilter[i].Operator+' @'+tmpColumnParameter;
|
|
310
|
+
pParameters.query.parameters[tmpColumnParameter] = tmpFilter[i].Value;
|
|
311
|
+
generateMSSQLParameterTypeEntry(pParameters, tmpColumnParameter, tmpFilter[i].Parameter)
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return tmpWhere;
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Generate an ORDER BY clause from the sort array
|
|
320
|
+
*
|
|
321
|
+
* Each entry in the sort is an object like:
|
|
322
|
+
* {Column:'Color',Direction:'Descending'}
|
|
323
|
+
*
|
|
324
|
+
* @method: generateOrderBy
|
|
325
|
+
* @param: {Object} pParameters SQL Query Parameters
|
|
326
|
+
* @return: {String} Returns the field list clause
|
|
327
|
+
*/
|
|
328
|
+
var generateOrderBy = function(pParameters)
|
|
329
|
+
{
|
|
330
|
+
var tmpOrderBy = pParameters.sort;
|
|
331
|
+
if (!Array.isArray(tmpOrderBy) || tmpOrderBy.length < 1)
|
|
332
|
+
{
|
|
333
|
+
return '';
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
var tmpOrderClause = ' ORDER BY';
|
|
337
|
+
for (var i = 0; i < tmpOrderBy.length; i++)
|
|
338
|
+
{
|
|
339
|
+
if (i > 0)
|
|
340
|
+
{
|
|
341
|
+
tmpOrderClause += ',';
|
|
342
|
+
}
|
|
343
|
+
tmpOrderClause += ' '+tmpOrderBy[i].Column;
|
|
344
|
+
|
|
345
|
+
if (tmpOrderBy[i].Direction == 'Descending')
|
|
346
|
+
{
|
|
347
|
+
tmpOrderClause += ' DESC';
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return tmpOrderClause;
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Generate the limit clause
|
|
355
|
+
*
|
|
356
|
+
* @method: generateLimit
|
|
357
|
+
* @param: {Object} pParameters SQL Query Parameters
|
|
358
|
+
* @return: {String} Returns the table name clause
|
|
359
|
+
*/
|
|
360
|
+
var generateLimit = function(pParameters)
|
|
361
|
+
{
|
|
362
|
+
if (!pParameters.cap)
|
|
363
|
+
{
|
|
364
|
+
return '';
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
var tmpLimit = ' OFFSET ';
|
|
368
|
+
// If there is a begin record, we'll pass that in as well.
|
|
369
|
+
if (pParameters.begin !== false)
|
|
370
|
+
{
|
|
371
|
+
tmpLimit += pParameters.begin;
|
|
372
|
+
}
|
|
373
|
+
else
|
|
374
|
+
{
|
|
375
|
+
tmpLimit += '0';
|
|
376
|
+
}
|
|
377
|
+
// Cap is required for a limit clause.
|
|
378
|
+
tmpLimit += ` ROWS FETCH NEXT ${pParameters.cap} ROWS ONLY`;
|
|
379
|
+
|
|
380
|
+
return tmpLimit;
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Generate the join clause
|
|
385
|
+
*
|
|
386
|
+
* @method: generateJoins
|
|
387
|
+
* @param: {Object} pParameters SQL Query Parameters
|
|
388
|
+
* @return: {String} Returns the join clause
|
|
389
|
+
*/
|
|
390
|
+
var generateJoins = function(pParameters)
|
|
391
|
+
{
|
|
392
|
+
var tmpJoins = pParameters.join;
|
|
393
|
+
if (!Array.isArray(tmpJoins) || tmpJoins.length < 1)
|
|
394
|
+
{
|
|
395
|
+
return '';
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
var tmpJoinClause = ''; //ex. ' INNER JOIN';
|
|
399
|
+
for (var i = 0; i < tmpJoins.length; i++)
|
|
400
|
+
{
|
|
401
|
+
var join = tmpJoins[i];
|
|
402
|
+
//verify that all required fields are valid
|
|
403
|
+
if (join.Type && join.Table && join.From && join.To)
|
|
404
|
+
{
|
|
405
|
+
tmpJoinClause += ` ${join.Type} ${join.Table} ON ${join.From} = ${join.To}`;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
return tmpJoinClause;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Generate the update SET clause
|
|
414
|
+
*
|
|
415
|
+
* @method: generateUpdateSetters
|
|
416
|
+
* @param: {Object} pParameters SQL Query Parameters
|
|
417
|
+
* @return: {String} Returns the table name clause
|
|
418
|
+
*/
|
|
419
|
+
var generateUpdateSetters = function(pParameters)
|
|
420
|
+
{
|
|
421
|
+
var tmpRecords = pParameters.query.records;
|
|
422
|
+
// We need to tell the query not to generate improperly if there are no values to set.
|
|
423
|
+
if (!Array.isArray(tmpRecords) || tmpRecords.length < 1)
|
|
424
|
+
{
|
|
425
|
+
return false;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.
|
|
429
|
+
var tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];
|
|
430
|
+
|
|
431
|
+
var tmpUpdate = '';
|
|
432
|
+
// If there is more than one record in records, we are going to ignore them for now.
|
|
433
|
+
var tmpCurrentColumn = 0;
|
|
434
|
+
for(var tmpColumn in tmpRecords[0])
|
|
435
|
+
{
|
|
436
|
+
// No hash table yet, so, we will just linear search it for now.
|
|
437
|
+
// This uses the schema to decide if we want to treat a column differently on insert
|
|
438
|
+
var tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};
|
|
439
|
+
for (var i = 0; i < tmpSchema.length; i++)
|
|
440
|
+
{
|
|
441
|
+
if (tmpColumn == tmpSchema[i].Column)
|
|
442
|
+
{
|
|
443
|
+
// There is a schema entry for it. Process it accordingly.
|
|
444
|
+
tmpSchemaEntry = tmpSchema[i];
|
|
445
|
+
break;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
if (pParameters.query.disableAutoDateStamp &&
|
|
450
|
+
tmpSchemaEntry.Type === 'UpdateDate')
|
|
451
|
+
{
|
|
452
|
+
// This is ignored if flag is set
|
|
453
|
+
continue;
|
|
454
|
+
}
|
|
455
|
+
if (pParameters.query.disableAutoUserStamp &&
|
|
456
|
+
tmpSchemaEntry.Type === 'UpdateIDUser')
|
|
457
|
+
{
|
|
458
|
+
// This is ignored if flag is set
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
switch (tmpSchemaEntry.Type)
|
|
463
|
+
{
|
|
464
|
+
case 'AutoIdentity':
|
|
465
|
+
case 'CreateDate':
|
|
466
|
+
case 'CreateIDUser':
|
|
467
|
+
case 'DeleteDate':
|
|
468
|
+
case 'DeleteIDUser':
|
|
469
|
+
// These are all ignored on update
|
|
470
|
+
continue;
|
|
471
|
+
}
|
|
472
|
+
if (tmpCurrentColumn > 0)
|
|
473
|
+
{
|
|
474
|
+
tmpUpdate += ',';
|
|
475
|
+
}
|
|
476
|
+
switch (tmpSchemaEntry.Type)
|
|
477
|
+
{
|
|
478
|
+
case 'UpdateDate':
|
|
479
|
+
// This is an autoidentity, so we don't parameterize it and just pass in NULL
|
|
480
|
+
tmpUpdate += ' '+tmpColumn+' = ' + SQL_NOW;
|
|
481
|
+
break;
|
|
482
|
+
case 'UpdateIDUser':
|
|
483
|
+
// This is the user ID, which we hope is in the query.
|
|
484
|
+
// This is how to deal with a normal column
|
|
485
|
+
var tmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;
|
|
486
|
+
tmpUpdate += ' '+tmpColumn+' = @'+tmpColumnParameter;
|
|
487
|
+
// Set the query parameter
|
|
488
|
+
pParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;
|
|
489
|
+
generateMSSQLParameterTypeEntry(pParameters, tmpColumnParameter, tmpColumn)
|
|
490
|
+
break;
|
|
491
|
+
default:
|
|
492
|
+
var tmpColumnDefaultParameter = tmpColumn+'_'+tmpCurrentColumn;
|
|
493
|
+
tmpUpdate += ' '+tmpColumn+' = @'+tmpColumnDefaultParameter;
|
|
494
|
+
|
|
495
|
+
// Set the query parameter
|
|
496
|
+
pParameters.query.parameters[tmpColumnDefaultParameter] = tmpRecords[0][tmpColumn];
|
|
497
|
+
generateMSSQLParameterTypeEntry(pParameters, tmpColumnDefaultParameter, tmpSchemaEntry)
|
|
498
|
+
break;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// We use a number to make sure parameters are unique.
|
|
502
|
+
tmpCurrentColumn++;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// We need to tell the query not to generate improperly if there are no values set.
|
|
506
|
+
if (tmpUpdate === '')
|
|
507
|
+
{
|
|
508
|
+
return false;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
return tmpUpdate;
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Generate the update-delete SET clause
|
|
516
|
+
*
|
|
517
|
+
* @method: generateUpdateDeleteSetters
|
|
518
|
+
* @param: {Object} pParameters SQL Query Parameters
|
|
519
|
+
* @return: {String} Returns the table name clause
|
|
520
|
+
*/
|
|
521
|
+
var generateUpdateDeleteSetters = function(pParameters)
|
|
522
|
+
{
|
|
523
|
+
if (pParameters.query.disableDeleteTracking)
|
|
524
|
+
{
|
|
525
|
+
//Don't generate an UPDATE query if Delete tracking is disabled
|
|
526
|
+
return false;
|
|
527
|
+
}
|
|
528
|
+
// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.
|
|
529
|
+
var tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];
|
|
530
|
+
|
|
531
|
+
var tmpCurrentColumn = 0;
|
|
532
|
+
var tmpHasDeletedField = false;
|
|
533
|
+
var tmpUpdate = '';
|
|
534
|
+
// No hash table yet, so, we will just linear search it for now.
|
|
535
|
+
// This uses the schema to decide if we want to treat a column differently on insert
|
|
536
|
+
var tmpSchemaEntry = {Type:'Default'};
|
|
537
|
+
for (var i = 0; i < tmpSchema.length; i++)
|
|
538
|
+
{
|
|
539
|
+
// There is a schema entry for it. Process it accordingly.
|
|
540
|
+
tmpSchemaEntry = tmpSchema[i];
|
|
541
|
+
|
|
542
|
+
var tmpUpdateSql = null;
|
|
543
|
+
|
|
544
|
+
switch (tmpSchemaEntry.Type)
|
|
545
|
+
{
|
|
546
|
+
case 'Deleted':
|
|
547
|
+
tmpUpdateSql = ' '+tmpSchemaEntry.Column+' = 1';
|
|
548
|
+
tmpHasDeletedField = true; //this field is required in order for query to be built
|
|
549
|
+
break;
|
|
550
|
+
case 'DeleteDate':
|
|
551
|
+
tmpUpdateSql = ' '+tmpSchemaEntry.Column+' = ' + SQL_NOW;
|
|
552
|
+
break;
|
|
553
|
+
case 'UpdateDate':
|
|
554
|
+
// Delete operation is an Update, so we should stamp the update time
|
|
555
|
+
tmpUpdateSql = ' '+tmpSchemaEntry.Column+' = ' + SQL_NOW;
|
|
556
|
+
break;
|
|
557
|
+
case 'DeleteIDUser':
|
|
558
|
+
// This is the user ID, which we hope is in the query.
|
|
559
|
+
// This is how to deal with a normal column
|
|
560
|
+
var tmpColumnParameter = tmpSchemaEntry.Column+'_'+tmpCurrentColumn;
|
|
561
|
+
tmpUpdateSql = ' '+tmpSchemaEntry.Column+' = @'+tmpColumnParameter;
|
|
562
|
+
// Set the query parameter
|
|
563
|
+
pParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;
|
|
564
|
+
generateMSSQLParameterTypeEntry(pParameters, tmpColumnParameter, tmpSchemaEntry)
|
|
565
|
+
break;
|
|
566
|
+
default:
|
|
567
|
+
//DON'T allow update of other fields in this query
|
|
568
|
+
continue;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
if (tmpCurrentColumn > 0)
|
|
572
|
+
{
|
|
573
|
+
tmpUpdate += ',';
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
tmpUpdate += tmpUpdateSql;
|
|
577
|
+
|
|
578
|
+
// We use a number to make sure parameters are unique.
|
|
579
|
+
tmpCurrentColumn++;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// We need to tell the query not to generate improperly if there are no values set.
|
|
583
|
+
if (!tmpHasDeletedField ||
|
|
584
|
+
tmpUpdate === '')
|
|
585
|
+
{
|
|
586
|
+
return false;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
return tmpUpdate;
|
|
590
|
+
};
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* Generate the update-undelete SET clause
|
|
594
|
+
*
|
|
595
|
+
* @method: generateUpdateUndeleteSetters
|
|
596
|
+
* @param: {Object} pParameters SQL Query Parameters
|
|
597
|
+
* @return: {String} Returns the table name clause
|
|
598
|
+
*/
|
|
599
|
+
var generateUpdateUndeleteSetters = function(pParameters)
|
|
600
|
+
{
|
|
601
|
+
// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.
|
|
602
|
+
var tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];
|
|
603
|
+
|
|
604
|
+
var tmpCurrentColumn = 0;
|
|
605
|
+
var tmpHasDeletedField = false;
|
|
606
|
+
var tmpUpdate = '';
|
|
607
|
+
// No hash table yet, so, we will just linear search it for now.
|
|
608
|
+
// This uses the schema to decide if we want to treat a column differently on insert
|
|
609
|
+
var tmpSchemaEntry = {Type:'Default'};
|
|
610
|
+
for (var i = 0; i < tmpSchema.length; i++)
|
|
611
|
+
{
|
|
612
|
+
// There is a schema entry for it. Process it accordingly.
|
|
613
|
+
tmpSchemaEntry = tmpSchema[i];
|
|
614
|
+
|
|
615
|
+
var tmpUpdateSql = null;
|
|
616
|
+
|
|
617
|
+
switch (tmpSchemaEntry.Type)
|
|
618
|
+
{
|
|
619
|
+
case 'Deleted':
|
|
620
|
+
tmpUpdateSql = ' '+tmpSchemaEntry.Column+' = 0';
|
|
621
|
+
tmpHasDeletedField = true; //this field is required in order for query to be built
|
|
622
|
+
break;
|
|
623
|
+
case 'UpdateDate':
|
|
624
|
+
// The undelete operation is an Update, so we should stamp the update time
|
|
625
|
+
tmpUpdateSql = ' '+tmpSchemaEntry.Column+' = ' + SQL_NOW;
|
|
626
|
+
break;
|
|
627
|
+
case 'UpdateIDUser':
|
|
628
|
+
var tmpColumnParameter = tmpSchemaEntry.Column+'_'+tmpCurrentColumn;
|
|
629
|
+
tmpUpdateSql = ' '+tmpSchemaEntry.Column+' = @'+tmpColumnParameter;
|
|
630
|
+
pParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;
|
|
631
|
+
generateMSSQLParameterTypeEntry(pParameters, tmpColumnParameter, tmpSchemaEntry)
|
|
632
|
+
break;
|
|
633
|
+
default:
|
|
634
|
+
//DON'T allow update of other fields in this query
|
|
635
|
+
continue;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
if (tmpCurrentColumn > 0)
|
|
639
|
+
{
|
|
640
|
+
tmpUpdate += ',';
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
tmpUpdate += tmpUpdateSql;
|
|
644
|
+
|
|
645
|
+
// We use a number to make sure parameters are unique.
|
|
646
|
+
tmpCurrentColumn++;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// We need to tell the query not to generate improperly if there are no values set.
|
|
650
|
+
if (!tmpHasDeletedField ||
|
|
651
|
+
tmpUpdate === '')
|
|
652
|
+
{
|
|
653
|
+
return false;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
return tmpUpdate;
|
|
657
|
+
};
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* Generate the create SET clause
|
|
661
|
+
*
|
|
662
|
+
* @method: generateCreateSetList
|
|
663
|
+
* @param: {Object} pParameters SQL Query Parameters
|
|
664
|
+
* @return: {String} Returns the table name clause
|
|
665
|
+
*/
|
|
666
|
+
var generateCreateSetValues = function(pParameters)
|
|
667
|
+
{
|
|
668
|
+
var tmpRecords = pParameters.query.records;
|
|
669
|
+
// We need to tell the query not to generate improperly if there are no values to set.
|
|
670
|
+
if (!Array.isArray(tmpRecords) || tmpRecords.length < 1)
|
|
671
|
+
{
|
|
672
|
+
return false;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.
|
|
676
|
+
var tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];
|
|
677
|
+
|
|
678
|
+
|
|
679
|
+
var tmpCreateSet = '';
|
|
680
|
+
// If there is more than one record in records, we are going to ignore them for now.
|
|
681
|
+
var tmpCurrentColumn = 0;
|
|
682
|
+
for(var tmpColumn in tmpRecords[0])
|
|
683
|
+
{
|
|
684
|
+
// No hash table yet, so, we will just linear search it for now.
|
|
685
|
+
// This uses the schema to decide if we want to treat a column differently on insert
|
|
686
|
+
var tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};
|
|
687
|
+
for (var i = 0; i < tmpSchema.length; i++)
|
|
688
|
+
{
|
|
689
|
+
if (tmpColumn == tmpSchema[i].Column)
|
|
690
|
+
{
|
|
691
|
+
// There is a schema entry for it. Process it accordingly.
|
|
692
|
+
tmpSchemaEntry = tmpSchema[i];
|
|
693
|
+
break;
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
if (!pParameters.query.disableDeleteTracking)
|
|
698
|
+
{
|
|
699
|
+
if (tmpSchemaEntry.Type === 'DeleteDate' ||
|
|
700
|
+
tmpSchemaEntry.Type === 'DeleteIDUser')
|
|
701
|
+
{
|
|
702
|
+
// These are all ignored on insert (if delete tracking is enabled as normal)
|
|
703
|
+
continue;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
if (tmpCurrentColumn > 0)
|
|
708
|
+
{
|
|
709
|
+
tmpCreateSet += ',';
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
//define a re-usable method for setting up field definitions in a default pattern
|
|
713
|
+
var buildDefaultDefinition = function()
|
|
714
|
+
{
|
|
715
|
+
var tmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;
|
|
716
|
+
tmpCreateSet += ' @'+tmpColumnParameter;
|
|
717
|
+
// Set the query parameter
|
|
718
|
+
pParameters.query.parameters[tmpColumnParameter] = tmpRecords[0][tmpColumn];
|
|
719
|
+
generateMSSQLParameterTypeEntry(pParameters, tmpColumnParameter, tmpSchemaEntry)
|
|
720
|
+
};
|
|
721
|
+
|
|
722
|
+
var tmpColumnParameter;
|
|
723
|
+
switch (tmpSchemaEntry.Type)
|
|
724
|
+
{
|
|
725
|
+
case 'AutoIdentity':
|
|
726
|
+
if (pParameters.query.disableAutoIdentity)
|
|
727
|
+
{
|
|
728
|
+
buildDefaultDefinition();
|
|
729
|
+
}
|
|
730
|
+
else
|
|
731
|
+
{
|
|
732
|
+
// This is an autoidentity, so we don't parameterize it and just pass in NULL
|
|
733
|
+
tmpCreateSet += ' NULL';
|
|
734
|
+
}
|
|
735
|
+
break;
|
|
736
|
+
case 'AutoGUID':
|
|
737
|
+
if (pParameters.query.disableAutoIdentity)
|
|
738
|
+
{
|
|
739
|
+
buildDefaultDefinition();
|
|
740
|
+
}
|
|
741
|
+
else if (tmpRecords[0][tmpColumn] &&
|
|
742
|
+
tmpRecords[0][tmpColumn].length >= 5 &&
|
|
743
|
+
tmpRecords[0][tmpColumn] !== '0x0000000000000000') //stricture default
|
|
744
|
+
{
|
|
745
|
+
// Allow consumer to override AutoGUID
|
|
746
|
+
buildDefaultDefinition();
|
|
747
|
+
}
|
|
748
|
+
else
|
|
749
|
+
{
|
|
750
|
+
// This is an autoidentity, so we don't parameterize it and just pass in NULL
|
|
751
|
+
tmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;
|
|
752
|
+
tmpCreateSet += ' @'+tmpColumnParameter;
|
|
753
|
+
// Set the query parameter
|
|
754
|
+
pParameters.query.parameters[tmpColumnParameter] = pParameters.query.UUID;
|
|
755
|
+
generateMSSQLParameterTypeEntry(pParameters, tmpColumnParameter, tmpSchemaEntry)
|
|
756
|
+
}
|
|
757
|
+
break;
|
|
758
|
+
case 'UpdateDate':
|
|
759
|
+
case 'CreateDate':
|
|
760
|
+
case 'DeleteDate':
|
|
761
|
+
if (pParameters.query.disableAutoDateStamp)
|
|
762
|
+
{
|
|
763
|
+
buildDefaultDefinition();
|
|
764
|
+
}
|
|
765
|
+
else
|
|
766
|
+
{
|
|
767
|
+
// This is an autoidentity, so we don't parameterize it and just pass in NULL
|
|
768
|
+
tmpCreateSet += ' ' + SQL_NOW;
|
|
769
|
+
}
|
|
770
|
+
break;
|
|
771
|
+
case 'DeleteIDUser':
|
|
772
|
+
case 'UpdateIDUser':
|
|
773
|
+
case 'CreateIDUser':
|
|
774
|
+
if (pParameters.query.disableAutoUserStamp)
|
|
775
|
+
{
|
|
776
|
+
buildDefaultDefinition();
|
|
777
|
+
}
|
|
778
|
+
else
|
|
779
|
+
{
|
|
780
|
+
// This is the user ID, which we hope is in the query.
|
|
781
|
+
// This is how to deal with a normal column
|
|
782
|
+
tmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;
|
|
783
|
+
tmpCreateSet += ' @'+tmpColumnParameter;
|
|
784
|
+
// Set the query parameter
|
|
785
|
+
pParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;
|
|
786
|
+
generateMSSQLParameterTypeEntry(pParameters, tmpColumnParameter, tmpSchemaEntry)
|
|
787
|
+
}
|
|
788
|
+
break;
|
|
789
|
+
default:
|
|
790
|
+
buildDefaultDefinition();
|
|
791
|
+
break;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
// We use an appended number to make sure parameters are unique.
|
|
795
|
+
tmpCurrentColumn++;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
// We need to tell the query not to generate improperly if there are no values set.
|
|
799
|
+
if (tmpCreateSet === '')
|
|
800
|
+
{
|
|
801
|
+
return false;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
return tmpCreateSet;
|
|
805
|
+
};
|
|
806
|
+
|
|
807
|
+
/**
|
|
808
|
+
* Generate the create SET clause
|
|
809
|
+
*
|
|
810
|
+
* @method: generateCreateSetList
|
|
811
|
+
* @param: {Object} pParameters SQL Query Parameters
|
|
812
|
+
* @return: {String} Returns the table name clause
|
|
813
|
+
*/
|
|
814
|
+
var generateCreateSetList = function(pParameters)
|
|
815
|
+
{
|
|
816
|
+
// The records were already validated by generateCreateSetValues
|
|
817
|
+
var tmpRecords = pParameters.query.records;
|
|
818
|
+
|
|
819
|
+
// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.
|
|
820
|
+
var tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];
|
|
821
|
+
|
|
822
|
+
var tmpCreateSet = '';
|
|
823
|
+
// If there is more than one record in records, we are going to ignore them for now.
|
|
824
|
+
for(var tmpColumn in tmpRecords[0])
|
|
825
|
+
{
|
|
826
|
+
// No hash table yet, so, we will just linear search it for now.
|
|
827
|
+
// This uses the schema to decide if we want to treat a column differently on insert
|
|
828
|
+
var tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};
|
|
829
|
+
for (var i = 0; i < tmpSchema.length; i++)
|
|
830
|
+
{
|
|
831
|
+
if (tmpColumn == tmpSchema[i].Column)
|
|
832
|
+
{
|
|
833
|
+
// There is a schema entry for it. Process it accordingly.
|
|
834
|
+
tmpSchemaEntry = tmpSchema[i];
|
|
835
|
+
break;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
if (!pParameters.query.disableDeleteTracking)
|
|
839
|
+
{
|
|
840
|
+
if (tmpSchemaEntry.Type === 'DeleteDate' ||
|
|
841
|
+
tmpSchemaEntry.Type === 'DeleteIDUser')
|
|
842
|
+
{
|
|
843
|
+
// These are all ignored on insert (if delete tracking is enabled as normal)
|
|
844
|
+
continue;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
switch (tmpSchemaEntry.Type)
|
|
848
|
+
{
|
|
849
|
+
default:
|
|
850
|
+
if (tmpCreateSet != '')
|
|
851
|
+
{
|
|
852
|
+
tmpCreateSet += ',';
|
|
853
|
+
}
|
|
854
|
+
tmpCreateSet += ' '+tmpColumn;
|
|
855
|
+
break;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
return tmpCreateSet;
|
|
860
|
+
};
|
|
861
|
+
|
|
862
|
+
|
|
863
|
+
var Create = function(pParameters)
|
|
864
|
+
{
|
|
865
|
+
var tmpTableName = generateTableName(pParameters);
|
|
866
|
+
var tmpCreateSetList = generateCreateSetList(pParameters);
|
|
867
|
+
var tmpCreateSetValues = generateCreateSetValues(pParameters);
|
|
868
|
+
|
|
869
|
+
if (!tmpCreateSetValues)
|
|
870
|
+
{
|
|
871
|
+
return false;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
return 'INSERT INTO'+tmpTableName+' ('+tmpCreateSetList+') VALUES ('+tmpCreateSetValues+');';
|
|
875
|
+
};
|
|
876
|
+
|
|
877
|
+
|
|
878
|
+
/**
|
|
879
|
+
* Read one or many records
|
|
880
|
+
*
|
|
881
|
+
* Some examples:
|
|
882
|
+
* SELECT * FROM WIDGETS;
|
|
883
|
+
* SELECT * FROM WIDGETS LIMIT 0, 20;
|
|
884
|
+
* SELECT * FROM WIDGETS LIMIT 5, 20;
|
|
885
|
+
* SELECT ID, Name, Cost FROM WIDGETS LIMIT 5, 20;
|
|
886
|
+
* SELECT ID, Name, Cost FROM WIDGETS LIMIT 5, 20 WHERE LastName = 'Smith';
|
|
887
|
+
*
|
|
888
|
+
* @method Read
|
|
889
|
+
* @param {Object} pParameters SQL Query parameters
|
|
890
|
+
* @return {String} Returns the current Query for chaining.
|
|
891
|
+
*/
|
|
892
|
+
var Read = function(pParameters)
|
|
893
|
+
{
|
|
894
|
+
var tmpFieldList = generateFieldList(pParameters);
|
|
895
|
+
var tmpTableName = generateTableName(pParameters);
|
|
896
|
+
var tmpWhere = generateWhere(pParameters);
|
|
897
|
+
var tmpJoin = generateJoins(pParameters);
|
|
898
|
+
var tmpOrderBy = generateOrderBy(pParameters);
|
|
899
|
+
var tmpLimit = generateLimit(pParameters);
|
|
900
|
+
const tmpOptDistinct = pParameters.distinct ? ' DISTINCT' : '';
|
|
901
|
+
|
|
902
|
+
if (pParameters.queryOverride)
|
|
903
|
+
{
|
|
904
|
+
try
|
|
905
|
+
{
|
|
906
|
+
var tmpQueryTemplate = _Fable.Utility.template(pParameters.queryOverride);
|
|
907
|
+
return tmpQueryTemplate({FieldList:tmpFieldList, TableName:tmpTableName, Where:tmpWhere, Join:tmpJoin, OrderBy:tmpOrderBy, Limit:tmpLimit, Distinct: tmpOptDistinct, _Params: pParameters});
|
|
908
|
+
}
|
|
909
|
+
catch (pError)
|
|
910
|
+
{
|
|
911
|
+
// This pokemon is here to give us a convenient way of not throwing up totally if the query fails.
|
|
912
|
+
console.log('Error with custom Read Query ['+pParameters.queryOverride+']: '+pError);
|
|
913
|
+
return false;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
return `SELECT${tmpOptDistinct}${tmpFieldList} FROM${tmpTableName}${tmpJoin}${tmpWhere}${tmpOrderBy}${tmpLimit};`;
|
|
918
|
+
};
|
|
919
|
+
|
|
920
|
+
var Update = function(pParameters)
|
|
921
|
+
{
|
|
922
|
+
var tmpTableName = generateTableName(pParameters);
|
|
923
|
+
var tmpWhere = generateWhere(pParameters);
|
|
924
|
+
var tmpUpdateSetters = generateUpdateSetters(pParameters);
|
|
925
|
+
|
|
926
|
+
if (!tmpUpdateSetters)
|
|
927
|
+
{
|
|
928
|
+
return false;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
return 'UPDATE'+tmpTableName+' SET'+tmpUpdateSetters+tmpWhere+';';
|
|
932
|
+
};
|
|
933
|
+
|
|
934
|
+
var Delete = function(pParameters)
|
|
935
|
+
{
|
|
936
|
+
var tmpTableName = generateTableName(pParameters);
|
|
937
|
+
var tmpWhere = generateWhere(pParameters);
|
|
938
|
+
var tmpUpdateDeleteSetters = generateUpdateDeleteSetters(pParameters);
|
|
939
|
+
|
|
940
|
+
if (tmpUpdateDeleteSetters)
|
|
941
|
+
{
|
|
942
|
+
//If it has a deleted bit, update it instead of actually deleting the record
|
|
943
|
+
return 'UPDATE'+tmpTableName+' SET'+tmpUpdateDeleteSetters+tmpWhere+';';
|
|
944
|
+
}
|
|
945
|
+
else
|
|
946
|
+
{
|
|
947
|
+
return 'DELETE FROM'+tmpTableName+tmpWhere+';';
|
|
948
|
+
}
|
|
949
|
+
};
|
|
950
|
+
|
|
951
|
+
var Undelete = function(pParameters)
|
|
952
|
+
{
|
|
953
|
+
var tmpTableName = generateTableName(pParameters);
|
|
954
|
+
// TODO: Fix these
|
|
955
|
+
let tmpDeleteTrackingState = pParameters.query.disableDeleteTracking;
|
|
956
|
+
pParameters.query.disableDeleteTracking = true;
|
|
957
|
+
var tmpWhere = generateWhere(pParameters);
|
|
958
|
+
var tmpUpdateUndeleteSetters = generateUpdateUndeleteSetters(pParameters);
|
|
959
|
+
pParameters.query.disableDeleteTracking = tmpDeleteTrackingState;
|
|
960
|
+
|
|
961
|
+
if (tmpUpdateUndeleteSetters)
|
|
962
|
+
{
|
|
963
|
+
//If the table has a deleted bit, go forward with the update to change things.
|
|
964
|
+
return 'UPDATE'+tmpTableName+' SET'+tmpUpdateUndeleteSetters+tmpWhere+';';
|
|
965
|
+
}
|
|
966
|
+
else
|
|
967
|
+
{
|
|
968
|
+
// This is a no-op because the record can't be undeleted.
|
|
969
|
+
// TODO: Should it throw instead?
|
|
970
|
+
return 'SELECT NULL;';
|
|
971
|
+
}
|
|
972
|
+
};
|
|
973
|
+
|
|
974
|
+
var Count = function(pParameters)
|
|
975
|
+
{
|
|
976
|
+
var tmpFieldList = pParameters.distinct ? generateFieldList(pParameters, true) : '*';
|
|
977
|
+
var tmpTableName = generateTableName(pParameters);
|
|
978
|
+
var tmpJoin = generateJoins(pParameters);
|
|
979
|
+
var tmpWhere = generateWhere(pParameters);
|
|
980
|
+
// here, we ignore the distinct keyword if no fields have been specified and
|
|
981
|
+
if (pParameters.distinct && tmpFieldList.length < 1)
|
|
982
|
+
{
|
|
983
|
+
console.warn('Distinct requested but no field list or schema are available, so not honoring distinct for count query.');
|
|
984
|
+
}
|
|
985
|
+
const tmpOptDistinct = pParameters.distinct && tmpFieldList.length > 0 ? 'DISTINCT' : '';
|
|
986
|
+
|
|
987
|
+
if (pParameters.queryOverride)
|
|
988
|
+
{
|
|
989
|
+
try
|
|
990
|
+
{
|
|
991
|
+
var tmpQueryTemplate = _Fable.Utility.template(pParameters.queryOverride);
|
|
992
|
+
return tmpQueryTemplate({FieldList:[], TableName:tmpTableName, Where:tmpWhere, OrderBy:'', Limit:'', Distinct: tmpOptDistinct, _Params: pParameters});
|
|
993
|
+
}
|
|
994
|
+
catch (pError)
|
|
995
|
+
{
|
|
996
|
+
// This pokemon is here to give us a convenient way of not throwing up totally if the query fails.
|
|
997
|
+
console.log('Error with custom Count Query ['+pParameters.queryOverride+']: '+pError);
|
|
998
|
+
return false;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
return `SELECT COUNT(${tmpOptDistinct}${tmpFieldList || '*'}) AS Row_Count FROM${tmpTableName}${tmpJoin}${tmpWhere};`;
|
|
1003
|
+
};
|
|
1004
|
+
|
|
1005
|
+
var tmpDialect = ({
|
|
1006
|
+
Create: Create,
|
|
1007
|
+
Read: Read,
|
|
1008
|
+
Update: Update,
|
|
1009
|
+
Delete: Delete,
|
|
1010
|
+
Undelete: Undelete,
|
|
1011
|
+
Count: Count
|
|
1012
|
+
});
|
|
1013
|
+
|
|
1014
|
+
/**
|
|
1015
|
+
* Dialect Name
|
|
1016
|
+
*
|
|
1017
|
+
* @property name
|
|
1018
|
+
* @type string
|
|
1019
|
+
*/
|
|
1020
|
+
Object.defineProperty(tmpDialect, 'name',
|
|
1021
|
+
{
|
|
1022
|
+
get: function() { return 'MSSQL'; },
|
|
1023
|
+
enumerable: true
|
|
1024
|
+
});
|
|
1025
|
+
|
|
1026
|
+
return tmpDialect;
|
|
1027
|
+
};
|
|
1028
|
+
|
|
1029
|
+
module.exports = FoxHoundDialectMSSQL;
|