foxhound 1.0.37 → 1.0.38

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.
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "optOut": false,
3
- "lastUpdateCheck": 1648063932373
3
+ "lastUpdateCheck": 1653489092676
4
4
  }
package/Dockerfile CHANGED
@@ -17,6 +17,20 @@ RUN echo "...mapping library specific volumes..."
17
17
  VOLUME /home/coder/foxhound
18
18
  # VOLUME /home/coder/foxhound/node_modules
19
19
 
20
+ RUN echo "...installing vscode extensions..."
21
+ RUN code-server --install-extension hbenl.vscode-mocha-test-adapter \
22
+ code-server --install-extension hbenl.vscode-test-explorer \
23
+ code-server --install-extension hbenl.test-adapter-converter \
24
+ code-server --install-extension cweijan.vscode-mysql-client2 \
25
+ code-server --install-extension daylerees.rainglow \
26
+ code-server --install-extension oderwat.indent-rainbow \
27
+ code-server --install-extension evan-buss.font-switcher \
28
+ code-server --install-extension vscode-icons-team.vscode-icons \
29
+ code-server --install-extension bengreenier.vscode-node-readme \
30
+ code-server --install-extension bierner.color-info \
31
+ code-server --install-extension dbaeumer.vscode-eslint \
32
+ code-server --install-extension PKief.material-icon-theme
33
+
20
34
  SHELL ["/bin/bash", "-c"]
21
35
  USER coder
22
36
 
package/debug/Harness.js CHANGED
@@ -24,8 +24,10 @@ var _AnimalSchemaWithoutDeleted = (
24
24
  { Column: "UpdatingIDUser", Type:"UpdateIDUser" }
25
25
  ]);
26
26
 
27
+ /*
27
28
  var tmpQuery = libFoxHound.new(libFable)
28
- .setDialect('MeadowEndpoints')
29
+ //.setDialect('MeadowEndpoints')
30
+ .setDialect('MySQL')
29
31
  .setScope('Animal')
30
32
  .setDataElements(['Name', 'Age', 'Cost'])
31
33
  .setCap(100)
@@ -39,7 +41,18 @@ var tmpQuery = libFoxHound.new(libFable)
39
41
  tmpQuery.setLogLevel(3).addSort('Age');
40
42
  // Build the query
41
43
  tmpQuery.buildReadQuery();
42
- // This is the query generated by the MeadowEndpoints dialect
44
+ // This is the query generated by the set dialect
43
45
  libFable.log.trace('Select Query', tmpQuery.query);
46
+ */
47
+ var tmpQuery = libFoxHound.new(libFable)
48
+ //.setDialect('MeadowEndpoints')
49
+ .setDialect('MySQL')
50
+ .setScope('Animal')
51
+ .addFilter('IDAnimal', 10);
52
+ tmpQuery.query.schema = _AnimalSchema;
53
+ // Build the query
54
+ tmpQuery.buildUndeleteQuery();
55
+ // This is the query generated by the set dialect
56
+ libFable.log.trace('Query: ', tmpQuery.query);
44
57
 
45
58
  console.log(tmpQuery.query.body);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foxhound",
3
- "version": "1.0.37",
3
+ "version": "1.0.38",
4
4
  "description": "A Database Query generation library.",
5
5
  "main": "source/FoxHound.js",
6
6
  "scripts": {
@@ -794,6 +794,13 @@ var FoxHound = function()
794
794
  return this;
795
795
  };
796
796
 
797
+ var buildUndeleteQuery = function()
798
+ {
799
+ checkDialect();
800
+ _Parameters.query.body = _Dialect.Undelete(_Parameters);
801
+ return this;
802
+ };
803
+
797
804
  var buildCountQuery = function()
798
805
  {
799
806
  checkDialect();
@@ -836,6 +843,7 @@ var FoxHound = function()
836
843
  buildReadQuery: buildReadQuery,
837
844
  buildUpdateQuery: buildUpdateQuery,
838
845
  buildDeleteQuery: buildDeleteQuery,
846
+ buildUndeleteQuery: buildUndeleteQuery,
839
847
  buildCountQuery: buildCountQuery,
840
848
 
841
849
  clone: clone,
@@ -20,24 +20,24 @@ var libUnderscore = require('underscore');
20
20
  var FoxHoundDialectALASQL = function()
21
21
  {
22
22
  /**
23
- * Generate a table name from the scope.
24
- *
25
- * Because ALASQL is all in-memory, and can be run in two modes (anonymous
26
- * working on arrays or table-based) we are going to make this a programmable
27
- * value. Then we can share the code across both providers.
28
- *
29
- * @method: generateTableName
30
- * @param: {Object} pParameters SQL Query Parameters
31
- * @return: {String} Returns the table name clause
32
- */
23
+ * Generate a table name from the scope.
24
+ *
25
+ * Because ALASQL is all in-memory, and can be run in two modes (anonymous
26
+ * working on arrays or table-based) we are going to make this a programmable
27
+ * value. Then we can share the code across both providers.
28
+ *
29
+ * @method: generateTableName
30
+ * @param: {Object} pParameters SQL Query Parameters
31
+ * @return: {String} Returns the table name clause
32
+ */
33
33
  var generateTableName = function(pParameters)
34
34
  {
35
35
  return ' '+pParameters.scope;
36
36
  };
37
37
 
38
38
  /**
39
- * Escape columns, because ALASQL has more reserved KWs than most SQL dialects
40
- */
39
+ * Escape columns, because ALASQL has more reserved KWs than most SQL dialects
40
+ */
41
41
  var escapeColumn = (pColumn, pParameters) =>
42
42
  {
43
43
  if (pColumn.indexOf('.') < 0)
@@ -61,16 +61,16 @@ var FoxHoundDialectALASQL = function()
61
61
  };
62
62
 
63
63
  /**
64
- * Generate a field list from the array of dataElements
65
- *
66
- * Each entry in the dataElements is a simple string
67
- *
68
- * @method: generateFieldList
69
- * @param: {Object} pParameters SQL Query Parameters
70
- * @param {Boolean} pIsForCountClause (optional) If true, generate fields for use within a count clause.
71
- * @return: {String} Returns the field list clause, or empty string if explicit fields are requested but cannot be fulfilled
72
- * due to missing schema.
73
- */
64
+ * Generate a field list from the array of dataElements
65
+ *
66
+ * Each entry in the dataElements is a simple string
67
+ *
68
+ * @method: generateFieldList
69
+ * @param: {Object} pParameters SQL Query Parameters
70
+ * @param {Boolean} pIsForCountClause (optional) If true, generate fields for use within a count clause.
71
+ * @return: {String} Returns the field list clause, or empty string if explicit fields are requested but cannot be fulfilled
72
+ * due to missing schema.
73
+ */
74
74
  var generateFieldList = function(pParameters, pIsForCountClause)
75
75
  {
76
76
  var tmpDataElements = pParameters.dataElements;
@@ -109,9 +109,9 @@ var FoxHoundDialectALASQL = function()
109
109
  };
110
110
 
111
111
  /**
112
- * Generate a query from the array of where clauses
113
- *
114
- * Each clause is an object like:
112
+ * Generate a query from the array of where clauses
113
+ *
114
+ * Each clause is an object like:
115
115
  {
116
116
  Column:'Name',
117
117
  Operator:'EQ',
@@ -119,11 +119,11 @@ var FoxHoundDialectALASQL = function()
119
119
  Connector:'And',
120
120
  Parameter:'Name'
121
121
  }
122
- *
123
- * @method: generateWhere
124
- * @param: {Object} pParameters SQL Query Parameters
125
- * @return: {String} Returns the WHERE clause prefixed with WHERE, or an empty string if unnecessary
126
- */
122
+ *
123
+ * @method: generateWhere
124
+ * @param: {Object} pParameters SQL Query Parameters
125
+ * @return: {String} Returns the WHERE clause prefixed with WHERE, or an empty string if unnecessary
126
+ */
127
127
  var generateWhere = function(pParameters)
128
128
  {
129
129
  var tmpFilter = Array.isArray(pParameters.filter) ? pParameters.filter : [];
@@ -229,15 +229,15 @@ var FoxHoundDialectALASQL = function()
229
229
  };
230
230
 
231
231
  /**
232
- * Generate an ORDER BY clause from the sort array
233
- *
234
- * Each entry in the sort is an object like:
235
- * {Column:'Color',Direction:'Descending'}
236
- *
237
- * @method: generateOrderBy
238
- * @param: {Object} pParameters SQL Query Parameters
239
- * @return: {String} Returns the field list clause
240
- */
232
+ * Generate an ORDER BY clause from the sort array
233
+ *
234
+ * Each entry in the sort is an object like:
235
+ * {Column:'Color',Direction:'Descending'}
236
+ *
237
+ * @method: generateOrderBy
238
+ * @param: {Object} pParameters SQL Query Parameters
239
+ * @return: {String} Returns the field list clause
240
+ */
241
241
  var generateOrderBy = function(pParameters)
242
242
  {
243
243
  var tmpOrderBy = pParameters.sort;
@@ -264,12 +264,12 @@ var FoxHoundDialectALASQL = function()
264
264
  };
265
265
 
266
266
  /**
267
- * Generate the limit clause
268
- *
269
- * @method: generateLimit
270
- * @param: {Object} pParameters SQL Query Parameters
271
- * @return: {String} Returns the table name clause
272
- */
267
+ * Generate the limit clause
268
+ *
269
+ * @method: generateLimit
270
+ * @param: {Object} pParameters SQL Query Parameters
271
+ * @return: {String} Returns the table name clause
272
+ */
273
273
  var generateLimit = function(pParameters)
274
274
  {
275
275
  if (!pParameters.cap)
@@ -291,12 +291,12 @@ var FoxHoundDialectALASQL = function()
291
291
  };
292
292
 
293
293
  /**
294
- * Generate the update SET clause
295
- *
296
- * @method: generateUpdateSetters
297
- * @param: {Object} pParameters SQL Query Parameters
298
- * @return: {String} Returns the table name clause
299
- */
294
+ * Generate the update SET clause
295
+ *
296
+ * @method: generateUpdateSetters
297
+ * @param: {Object} pParameters SQL Query Parameters
298
+ * @return: {String} Returns the table name clause
299
+ */
300
300
  var generateUpdateSetters = function(pParameters)
301
301
  {
302
302
  var tmpRecords = pParameters.query.records;
@@ -391,12 +391,12 @@ var FoxHoundDialectALASQL = function()
391
391
  };
392
392
 
393
393
  /**
394
- * Generate the update-delete SET clause
395
- *
396
- * @method: generateUpdateDeleteSetters
397
- * @param: {Object} pParameters SQL Query Parameters
398
- * @return: {String} Returns the table name clause
399
- */
394
+ * Generate the update-delete SET clause
395
+ *
396
+ * @method: generateUpdateDeleteSetters
397
+ * @param: {Object} pParameters SQL Query Parameters
398
+ * @return: {String} Returns the table name clause
399
+ */
400
400
  var generateUpdateDeleteSetters = function(pParameters)
401
401
  {
402
402
  if (pParameters.query.disableDeleteTracking)
@@ -468,12 +468,86 @@ var FoxHoundDialectALASQL = function()
468
468
  };
469
469
 
470
470
  /**
471
- * Generate the create SET clause
472
- *
473
- * @method: generateCreateSetList
474
- * @param: {Object} pParameters SQL Query Parameters
475
- * @return: {String} Returns the table name clause
476
- */
471
+ * Generate the update-delete SET clause
472
+ *
473
+ * @method: generateUpdateDeleteSetters
474
+ * @param: {Object} pParameters SQL Query Parameters
475
+ * @return: {String} Returns the table name clause
476
+ */
477
+ var generateUpdateUndeleteSetters = function(pParameters)
478
+ {
479
+ if (pParameters.query.disableDeleteTracking)
480
+ {
481
+ //Don't generate an UPDATE query if Delete tracking is disabled
482
+ return false;
483
+ }
484
+ // Check if there is a schema. If so, we will use it to decide if these are parameterized or not.
485
+ var tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];
486
+
487
+ var tmpCurrentColumn = 0;
488
+ var tmpHasDeletedField = false;
489
+ var tmpUpdate = '';
490
+ // No hash table yet, so, we will just linear search it for now.
491
+ // This uses the schema to decide if we want to treat a column differently on insert
492
+ var tmpSchemaEntry = {Type:'Default'};
493
+ for (var i = 0; i < tmpSchema.length; i++)
494
+ {
495
+ // There is a schema entry for it. Process it accordingly.
496
+ tmpSchemaEntry = tmpSchema[i];
497
+
498
+ var tmpUpdateSql = null;
499
+
500
+ switch (tmpSchemaEntry.Type)
501
+ {
502
+ case 'Deleted':
503
+ tmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = 0';
504
+ tmpHasDeletedField = true; //this field is required in order for query to be built
505
+ break;
506
+ case 'UpdateDate':
507
+ // Delete operation is an Update, so we should stamp the update time
508
+ tmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = NOW()';
509
+ break;
510
+ case 'UpdateIDUser':
511
+ // This is the user ID, which we hope is in the query.
512
+ // This is how to deal with a normal column
513
+ var tmpColumnParameter = tmpSchemaEntry.Column+'_'+tmpCurrentColumn;
514
+ tmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = :'+tmpColumnParameter;
515
+ // Set the query parameter
516
+ pParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;
517
+ break;
518
+ default:
519
+ //DON'T allow update of other fields in this query
520
+ continue;
521
+ }
522
+
523
+ if (tmpCurrentColumn > 0)
524
+ {
525
+ tmpUpdate += ',';
526
+ }
527
+
528
+ tmpUpdate += tmpUpdateSql;
529
+
530
+ // We use a number to make sure parameters are unique.
531
+ tmpCurrentColumn++;
532
+ }
533
+
534
+ // We need to tell the query not to generate improperly if there are no values set.
535
+ if (!tmpHasDeletedField ||
536
+ tmpUpdate === '')
537
+ {
538
+ return false;
539
+ }
540
+
541
+ return tmpUpdate;
542
+ };
543
+
544
+ /**
545
+ * Generate the create SET clause
546
+ *
547
+ * @method: generateCreateSetList
548
+ * @param: {Object} pParameters SQL Query Parameters
549
+ * @return: {String} Returns the table name clause
550
+ */
477
551
  var generateCreateSetValues = function(pParameters)
478
552
  {
479
553
  var tmpRecords = pParameters.query.records;
@@ -613,12 +687,12 @@ var FoxHoundDialectALASQL = function()
613
687
  };
614
688
 
615
689
  /**
616
- * Generate the create SET clause
617
- *
618
- * @method: generateCreateSetList
619
- * @param: {Object} pParameters SQL Query Parameters
620
- * @return: {String} Returns the table name clause
621
- */
690
+ * Generate the create SET clause
691
+ *
692
+ * @method: generateCreateSetList
693
+ * @param: {Object} pParameters SQL Query Parameters
694
+ * @return: {String} Returns the table name clause
695
+ */
622
696
  var generateCreateSetList = function(pParameters)
623
697
  {
624
698
  // The records were already validated by generateCreateSetValues
@@ -755,6 +829,23 @@ var FoxHoundDialectALASQL = function()
755
829
  }
756
830
  };
757
831
 
832
+ var Undelete = function(pParameters)
833
+ {
834
+ var tmpTableName = generateTableName(pParameters);
835
+ var tmpWhere = generateWhere(pParameters);
836
+ var tmpUpdateUndeleteSetters = generateUpdateUndeleteSetters(pParameters);
837
+
838
+ if (tmpUpdateUndeleteSetters)
839
+ {
840
+ //If it has a deleted bit, update it instead of actually deleting the record
841
+ return 'UPDATE'+tmpTableName+' SET'+tmpUpdateUndeleteSetters+tmpWhere+';';
842
+ }
843
+ else
844
+ {
845
+ return 'SELECT NULL;';
846
+ }
847
+ };
848
+
758
849
  var Count = function(pParameters)
759
850
  {
760
851
  var tmpTableName = generateTableName(pParameters);
@@ -790,15 +881,16 @@ var FoxHoundDialectALASQL = function()
790
881
  Read: Read,
791
882
  Update: Update,
792
883
  Delete: Delete,
884
+ Undelete: Undelete,
793
885
  Count: Count
794
886
  });
795
887
 
796
888
  /**
797
- * Dialect Name
798
- *
799
- * @property name
800
- * @type string
801
- */
889
+ * Dialect Name
890
+ *
891
+ * @property name
892
+ * @type string
893
+ */
802
894
  Object.defineProperty(tmpDialect, 'name',
803
895
  {
804
896
  get: function() { return 'ALASQL'; },
@@ -54,6 +54,13 @@ var FoxHoundDialectEnglish = function()
54
54
  return 'I am deleting your '+tmpScope+'.';
55
55
  };
56
56
 
57
+ var Undelete = function(pParameters)
58
+ {
59
+ var tmpScope = pParameters.scope;
60
+
61
+ return 'I am undeleting your '+tmpScope+'.';
62
+ };
63
+
57
64
  var Count = function(pParameters)
58
65
  {
59
66
  var tmpScope = pParameters.scope;
@@ -67,6 +74,7 @@ var FoxHoundDialectEnglish = function()
67
74
  Read: Read,
68
75
  Update: Update,
69
76
  Delete: Delete,
77
+ Undelete: Undelete,
70
78
  Count: Count
71
79
  });
72
80
 
@@ -23,12 +23,12 @@ var FoxHoundDialectMySQL = function()
23
23
  const SQL_NOW = "NOW(3)";
24
24
 
25
25
  /**
26
- * Generate a table name from the scope
27
- *
28
- * @method: generateTableName
29
- * @param: {Object} pParameters SQL Query Parameters
30
- * @return: {String} Returns the table name clause
31
- */
26
+ * Generate a table name from the scope
27
+ *
28
+ * @method: generateTableName
29
+ * @param: {Object} pParameters SQL Query Parameters
30
+ * @return: {String} Returns the table name clause
31
+ */
32
32
  var generateTableName = function(pParameters)
33
33
  {
34
34
  if (pParameters.scope && pParameters.scope.indexOf('`') >= 0)
@@ -38,16 +38,16 @@ var FoxHoundDialectMySQL = function()
38
38
  };
39
39
 
40
40
  /**
41
- * Generate a field list from the array of dataElements
42
- *
43
- * Each entry in the dataElements is a simple string
44
- *
45
- * @method: generateFieldList
46
- * @param: {Object} pParameters SQL Query Parameters
47
- * @param {Boolean} pIsForCountClause (optional) If true, generate fields for use within a count clause.
48
- * @return: {String} Returns the field list clause, or empty string if explicit fields are requested but cannot be fulfilled
49
- * due to missing schema.
50
- */
41
+ * Generate a field list from the array of dataElements
42
+ *
43
+ * Each entry in the dataElements is a simple string
44
+ *
45
+ * @method: generateFieldList
46
+ * @param: {Object} pParameters SQL Query Parameters
47
+ * @param {Boolean} pIsForCountClause (optional) If true, generate fields for use within a count clause.
48
+ * @return: {String} Returns the field list clause, or empty string if explicit fields are requested but cannot be fulfilled
49
+ * due to missing schema.
50
+ */
51
51
  var generateFieldList = function(pParameters, pIsForCountClause)
52
52
  {
53
53
  var tmpDataElements = pParameters.dataElements;
@@ -106,8 +106,8 @@ var FoxHoundDialectMySQL = function()
106
106
  };
107
107
 
108
108
  /**
109
- * Ensure a field name is properly escaped.
110
- */
109
+ * Ensure a field name is properly escaped.
110
+ */
111
111
  var generateSafeFieldName = function(pFieldName)
112
112
  {
113
113
  let pFieldNames = pFieldName.split('.');
@@ -122,9 +122,9 @@ var FoxHoundDialectMySQL = function()
122
122
  }
123
123
 
124
124
  /**
125
- * Generate a query from the array of where clauses
126
- *
127
- * Each clause is an object like:
125
+ * Generate a query from the array of where clauses
126
+ *
127
+ * Each clause is an object like:
128
128
  {
129
129
  Column:'Name',
130
130
  Operator:'EQ',
@@ -132,11 +132,11 @@ var FoxHoundDialectMySQL = function()
132
132
  Connector:'And',
133
133
  Parameter:'Name'
134
134
  }
135
- *
136
- * @method: generateWhere
137
- * @param: {Object} pParameters SQL Query Parameters
138
- * @return: {String} Returns the WHERE clause prefixed with WHERE, or an empty string if unnecessary
139
- */
135
+ *
136
+ * @method: generateWhere
137
+ * @param: {Object} pParameters SQL Query Parameters
138
+ * @return: {String} Returns the WHERE clause prefixed with WHERE, or an empty string if unnecessary
139
+ */
140
140
  var generateWhere = function(pParameters)
141
141
  {
142
142
  var tmpFilter = Array.isArray(pParameters.filter) ? pParameters.filter : [];
@@ -247,15 +247,15 @@ var FoxHoundDialectMySQL = function()
247
247
  };
248
248
 
249
249
  /**
250
- * Generate an ORDER BY clause from the sort array
251
- *
252
- * Each entry in the sort is an object like:
253
- * {Column:'Color',Direction:'Descending'}
254
- *
255
- * @method: generateOrderBy
256
- * @param: {Object} pParameters SQL Query Parameters
257
- * @return: {String} Returns the field list clause
258
- */
250
+ * Generate an ORDER BY clause from the sort array
251
+ *
252
+ * Each entry in the sort is an object like:
253
+ * {Column:'Color',Direction:'Descending'}
254
+ *
255
+ * @method: generateOrderBy
256
+ * @param: {Object} pParameters SQL Query Parameters
257
+ * @return: {String} Returns the field list clause
258
+ */
259
259
  var generateOrderBy = function(pParameters)
260
260
  {
261
261
  var tmpOrderBy = pParameters.sort;
@@ -282,12 +282,12 @@ var FoxHoundDialectMySQL = function()
282
282
  };
283
283
 
284
284
  /**
285
- * Generate the limit clause
286
- *
287
- * @method: generateLimit
288
- * @param: {Object} pParameters SQL Query Parameters
289
- * @return: {String} Returns the table name clause
290
- */
285
+ * Generate the limit clause
286
+ *
287
+ * @method: generateLimit
288
+ * @param: {Object} pParameters SQL Query Parameters
289
+ * @return: {String} Returns the table name clause
290
+ */
291
291
  var generateLimit = function(pParameters)
292
292
  {
293
293
  if (!pParameters.cap)
@@ -308,12 +308,12 @@ var FoxHoundDialectMySQL = function()
308
308
  };
309
309
 
310
310
  /**
311
- * Generate the join clause
312
- *
313
- * @method: generateJoins
314
- * @param: {Object} pParameters SQL Query Parameters
315
- * @return: {String} Returns the join clause
316
- */
311
+ * Generate the join clause
312
+ *
313
+ * @method: generateJoins
314
+ * @param: {Object} pParameters SQL Query Parameters
315
+ * @return: {String} Returns the join clause
316
+ */
317
317
  var generateJoins = function(pParameters)
318
318
  {
319
319
  var tmpJoins = pParameters.join;
@@ -337,12 +337,12 @@ var FoxHoundDialectMySQL = function()
337
337
  }
338
338
 
339
339
  /**
340
- * Generate the update SET clause
341
- *
342
- * @method: generateUpdateSetters
343
- * @param: {Object} pParameters SQL Query Parameters
344
- * @return: {String} Returns the table name clause
345
- */
340
+ * Generate the update SET clause
341
+ *
342
+ * @method: generateUpdateSetters
343
+ * @param: {Object} pParameters SQL Query Parameters
344
+ * @return: {String} Returns the table name clause
345
+ */
346
346
  var generateUpdateSetters = function(pParameters)
347
347
  {
348
348
  var tmpRecords = pParameters.query.records;
@@ -437,12 +437,12 @@ var FoxHoundDialectMySQL = function()
437
437
  };
438
438
 
439
439
  /**
440
- * Generate the update-delete SET clause
441
- *
442
- * @method: generateUpdateDeleteSetters
443
- * @param: {Object} pParameters SQL Query Parameters
444
- * @return: {String} Returns the table name clause
445
- */
440
+ * Generate the update-delete SET clause
441
+ *
442
+ * @method: generateUpdateDeleteSetters
443
+ * @param: {Object} pParameters SQL Query Parameters
444
+ * @return: {String} Returns the table name clause
445
+ */
446
446
  var generateUpdateDeleteSetters = function(pParameters)
447
447
  {
448
448
  if (pParameters.query.disableDeleteTracking)
@@ -452,7 +452,7 @@ var FoxHoundDialectMySQL = function()
452
452
  }
453
453
  // Check if there is a schema. If so, we will use it to decide if these are parameterized or not.
454
454
  var tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];
455
-
455
+
456
456
  var tmpCurrentColumn = 0;
457
457
  var tmpHasDeletedField = false;
458
458
  var tmpUpdate = '';
@@ -463,9 +463,9 @@ var FoxHoundDialectMySQL = function()
463
463
  {
464
464
  // There is a schema entry for it. Process it accordingly.
465
465
  tmpSchemaEntry = tmpSchema[i];
466
-
466
+
467
467
  var tmpUpdateSql = null;
468
-
468
+
469
469
  switch (tmpSchemaEntry.Type)
470
470
  {
471
471
  case 'Deleted':
@@ -491,6 +491,78 @@ var FoxHoundDialectMySQL = function()
491
491
  //DON'T allow update of other fields in this query
492
492
  continue;
493
493
  }
494
+
495
+ if (tmpCurrentColumn > 0)
496
+ {
497
+ tmpUpdate += ',';
498
+ }
499
+
500
+ tmpUpdate += tmpUpdateSql;
501
+
502
+ // We use a number to make sure parameters are unique.
503
+ tmpCurrentColumn++;
504
+ }
505
+
506
+ // We need to tell the query not to generate improperly if there are no values set.
507
+ if (!tmpHasDeletedField ||
508
+ tmpUpdate === '')
509
+ {
510
+ return false;
511
+ }
512
+
513
+ return tmpUpdate;
514
+ };
515
+
516
+ /**
517
+ * Generate the update-undelete SET clause
518
+ *
519
+ * @method: generateUpdateUndeleteSetters
520
+ * @param: {Object} pParameters SQL Query Parameters
521
+ * @return: {String} Returns the table name clause
522
+ */
523
+ var generateUpdateUndeleteSetters = function(pParameters)
524
+ {
525
+ // TODO: Eliminate this disableDeleteTracking stuff that was added
526
+ if (pParameters.query.disableDeleteTracking)
527
+ {
528
+ //Don't generate an UPDATE query if Delete tracking is disabled
529
+ return false;
530
+ }
531
+ // Check if there is a schema. If so, we will use it to decide if these are parameterized or not.
532
+ var tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];
533
+
534
+ var tmpCurrentColumn = 0;
535
+ var tmpHasDeletedField = false;
536
+ var tmpUpdate = '';
537
+ // No hash table yet, so, we will just linear search it for now.
538
+ // This uses the schema to decide if we want to treat a column differently on insert
539
+ var tmpSchemaEntry = {Type:'Default'};
540
+ for (var i = 0; i < tmpSchema.length; i++)
541
+ {
542
+ // There is a schema entry for it. Process it accordingly.
543
+ tmpSchemaEntry = tmpSchema[i];
544
+
545
+ var tmpUpdateSql = null;
546
+
547
+ switch (tmpSchemaEntry.Type)
548
+ {
549
+ case 'Deleted':
550
+ tmpUpdateSql = ' '+tmpSchemaEntry.Column+' = 0';
551
+ tmpHasDeletedField = true; //this field is required in order for query to be built
552
+ break;
553
+ case 'UpdateDate':
554
+ // The undelete operation is an Update, so we should stamp the update time
555
+ tmpUpdateSql = ' '+tmpSchemaEntry.Column+' = ' + SQL_NOW;
556
+ break;
557
+ case 'UpdateIDUser':
558
+ var tmpColumnParameter = tmpSchemaEntry.Column+'_'+tmpCurrentColumn;
559
+ tmpUpdateSql = ' '+tmpSchemaEntry.Column+' = :'+tmpColumnParameter;
560
+ pParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;
561
+ break;
562
+ default:
563
+ //DON'T allow update of other fields in this query
564
+ continue;
565
+ }
494
566
 
495
567
  if (tmpCurrentColumn > 0)
496
568
  {
@@ -514,12 +586,12 @@ var FoxHoundDialectMySQL = function()
514
586
  };
515
587
 
516
588
  /**
517
- * Generate the create SET clause
518
- *
519
- * @method: generateCreateSetList
520
- * @param: {Object} pParameters SQL Query Parameters
521
- * @return: {String} Returns the table name clause
522
- */
589
+ * Generate the create SET clause
590
+ *
591
+ * @method: generateCreateSetList
592
+ * @param: {Object} pParameters SQL Query Parameters
593
+ * @return: {String} Returns the table name clause
594
+ */
523
595
  var generateCreateSetValues = function(pParameters)
524
596
  {
525
597
  var tmpRecords = pParameters.query.records;
@@ -659,12 +731,12 @@ var FoxHoundDialectMySQL = function()
659
731
  };
660
732
 
661
733
  /**
662
- * Generate the create SET clause
663
- *
664
- * @method: generateCreateSetList
665
- * @param: {Object} pParameters SQL Query Parameters
666
- * @return: {String} Returns the table name clause
667
- */
734
+ * Generate the create SET clause
735
+ *
736
+ * @method: generateCreateSetList
737
+ * @param: {Object} pParameters SQL Query Parameters
738
+ * @return: {String} Returns the table name clause
739
+ */
668
740
  var generateCreateSetList = function(pParameters)
669
741
  {
670
742
  // The records were already validated by generateCreateSetValues
@@ -802,6 +874,25 @@ var FoxHoundDialectMySQL = function()
802
874
  }
803
875
  };
804
876
 
877
+ var Undelete = function(pParameters)
878
+ {
879
+ var tmpTableName = generateTableName(pParameters);
880
+ var tmpWhere = generateWhere(pParameters);
881
+ var tmpUpdateUndeleteSetters = generateUpdateUndeleteSetters(pParameters);
882
+
883
+ if (tmpUpdateUndeleteSetters)
884
+ {
885
+ //If the table has a deleted bit, go forward with the update to change things.
886
+ return 'UPDATE'+tmpTableName+' SET'+tmpUpdateUndeleteSetters+tmpWhere+';';
887
+ }
888
+ else
889
+ {
890
+ // This is a no-op because the record can't be undeleted.
891
+ // TODO: Should it throw instead?
892
+ return 'SELECT NULL;';
893
+ }
894
+ };
895
+
805
896
  var Count = function(pParameters)
806
897
  {
807
898
  var tmpFieldList = pParameters.distinct ? generateFieldList(pParameters, true) : '*';
@@ -838,15 +929,16 @@ var FoxHoundDialectMySQL = function()
838
929
  Read: Read,
839
930
  Update: Update,
840
931
  Delete: Delete,
932
+ Undelete: Undelete,
841
933
  Count: Count
842
934
  });
843
935
 
844
936
  /**
845
- * Dialect Name
846
- *
847
- * @property name
848
- * @type string
849
- */
937
+ * Dialect Name
938
+ *
939
+ * @property name
940
+ * @type string
941
+ */
850
942
  Object.defineProperty(tmpDialect, 'name',
851
943
  {
852
944
  get: function() { return 'MySQL'; },
@@ -659,6 +659,43 @@ suite
659
659
  }
660
660
  );
661
661
  test
662
+ (
663
+ 'Undelete Query with Deleted Bit',
664
+ function()
665
+ {
666
+ var tmpQuery = libFoxHound.new(libFable).setDialect('ALASQL')
667
+ .setScope('Animal')
668
+ .addFilter('IDAnimal', 10);
669
+
670
+ //Use a schema that already defines a deleted bit
671
+ tmpQuery.query.schema = _AnimalSchema;
672
+
673
+ // Build the query
674
+ tmpQuery.buildUndeleteQuery();
675
+ // This is the query generated by the ALASQL dialect
676
+ libFable.log.trace('Undelete Query', tmpQuery.query);
677
+ Expect(tmpQuery.query.body)
678
+ .to.equal('UPDATE Animal SET `UpdateDate` = NOW(), `UpdatingIDUser` = :UpdatingIDUser_1, `Deleted` = 0 WHERE `IDAnimal` = :IDAnimal_w0 AND `Deleted` = :Deleted_w1;');
679
+ }
680
+ );
681
+ test
682
+ (
683
+ 'Undelete Query without Deleted Bit',
684
+ function()
685
+ {
686
+ var tmpQuery = libFoxHound.new(libFable).setDialect('ALASQL')
687
+ .setScope('Animal')
688
+ .addFilter('IDAnimal', 10);
689
+
690
+ // Build the query
691
+ tmpQuery.buildUndeleteQuery();
692
+ // This is the query generated by the ALASQL dialect
693
+ libFable.log.trace('Undelete Query', tmpQuery.query);
694
+ Expect(tmpQuery.query.body)
695
+ .to.equal('SELECT NULL;');
696
+ }
697
+ );
698
+ test
662
699
  (
663
700
  'Update Query -- without Deleted',
664
701
  function()
@@ -205,6 +205,20 @@ suite
205
205
  }
206
206
  );
207
207
  test
208
+ (
209
+ 'Undelete Query',
210
+ function()
211
+ {
212
+ var tmpQuery = libFoxHound.new(libFable).setDialect('English').setScope('Animal');
213
+
214
+ // Build the query
215
+ tmpQuery.buildUndeleteQuery();
216
+ // This is the query generated by the English dialect
217
+ Expect(tmpQuery.query.body)
218
+ .to.equal('I am undeleting your Animal.');
219
+ }
220
+ );
221
+ test
208
222
  (
209
223
  'Count Query',
210
224
  function()
@@ -772,6 +772,43 @@ suite
772
772
  .to.equal('DELETE FROM `Animal` WHERE IDAnimal = :IDAnimal_w0;');
773
773
  }
774
774
  );
775
+ test
776
+ (
777
+ 'Undelete Query with Deleted Bit',
778
+ function()
779
+ {
780
+ var tmpQuery = libFoxHound.new(libFable).setDialect('MySQL')
781
+ .setScope('Animal')
782
+ .addFilter('IDAnimal', 10);
783
+
784
+ //Use a schema that already defines a deleted bit
785
+ tmpQuery.query.schema = _AnimalSchema;
786
+
787
+ // Build the query
788
+ tmpQuery.buildUndeleteQuery();
789
+ // This is the query generated by the MySQL dialect
790
+ libFable.log.trace('Undelete Query', tmpQuery.query);
791
+ Expect(tmpQuery.query.body)
792
+ .to.equal('UPDATE `Animal` SET UpdateDate = NOW(3), UpdatingIDUser = :UpdatingIDUser_1, Deleted = 0 WHERE IDAnimal = :IDAnimal_w0 AND `Animal`.Deleted = :Deleted_w1;');
793
+ }
794
+ );
795
+ test
796
+ (
797
+ 'Undelete Query without Deleted Bit',
798
+ function()
799
+ {
800
+ var tmpQuery = libFoxHound.new(libFable).setDialect('MySQL')
801
+ .setScope('Animal')
802
+ .addFilter('IDAnimal', 10);
803
+
804
+ // Build the query
805
+ tmpQuery.buildUndeleteQuery();
806
+ // This is the query generated by the MySQL dialect
807
+ libFable.log.trace('Undelete Query', tmpQuery.query);
808
+ Expect(tmpQuery.query.body)
809
+ .to.equal('SELECT NULL;');
810
+ }
811
+ );
775
812
  }
776
813
  );
777
814