foxhound 1.0.41 → 1.0.43

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foxhound",
3
- "version": "1.0.41",
3
+ "version": "1.0.43",
4
4
  "description": "A Database Query generation library.",
5
5
  "main": "source/FoxHound.js",
6
6
  "scripts": {
@@ -863,6 +863,19 @@ var FoxHound = function()
863
863
  enumerable: true
864
864
  });
865
865
 
866
+ /**
867
+ * Query
868
+ *
869
+ * @property query
870
+ * @type Object
871
+ */
872
+ Object.defineProperty(tmpNewFoxHoundObject, 'indexHints',
873
+ {
874
+ get: function() { return _Parameters.indexHints; },
875
+ set: function(pHints) { _Parameters.indexHints = pHints; },
876
+ enumerable: true,
877
+ });
878
+
866
879
  /**
867
880
  * Result
868
881
  *
@@ -78,7 +78,12 @@ var FoxHoundQueryParameters = (
78
78
  parameters: {}
79
79
  }
80
80
  */
81
-
81
+
82
+ indexHints: false,
83
+ /*
84
+ ['IndexName1', 'IndexName2'] // A list of index names to hint to the underlying provider, if supported
85
+ */
86
+
82
87
  // Who is making the query
83
88
  userID: 0,
84
89
 
@@ -93,4 +98,4 @@ var FoxHoundQueryParameters = (
93
98
  */
94
99
  });
95
100
 
96
- module.exports = FoxHoundQueryParameters;
101
+ module.exports = FoxHoundQueryParameters;
@@ -113,12 +113,21 @@ var FoxHoundDialectMySQL = function()
113
113
  let pFieldNames = pFieldName.split('.');
114
114
  if (pFieldNames.length > 1)
115
115
  {
116
- return "`" + cleanseQuoting(pFieldNames[0]) + "`.`" + cleanseQuoting(pFieldNames[1]) + "`";
116
+ const cleansedFieldName = cleanseQuoting(pFieldNames[1]);
117
+ if (cleansedFieldName === '*')
118
+ {
119
+ // do not put * as `*`
120
+ return "`" + cleanseQuoting(pFieldNames[0]) + "`.*";
121
+ }
122
+ return "`" + cleanseQuoting(pFieldNames[0]) + "`.`" + cleansedFieldName + "`";
117
123
  }
118
- else
124
+ const cleansedFieldName = cleanseQuoting(pFieldNames[0]);
125
+ if (cleansedFieldName === '*')
119
126
  {
120
- return "`" + cleanseQuoting(pFieldNames[0]) + "`";
127
+ // do not put * as `*`
128
+ return '*';
121
129
  }
130
+ return "`" + cleanseQuoting(pFieldNames[0]) + "`";
122
131
  }
123
132
 
124
133
  /**
@@ -286,7 +295,7 @@ var FoxHoundDialectMySQL = function()
286
295
  *
287
296
  * @method: generateLimit
288
297
  * @param: {Object} pParameters SQL Query Parameters
289
- * @return: {String} Returns the table name clause
298
+ * @return: {String} Returns the table limit clause
290
299
  */
291
300
  var generateLimit = function(pParameters)
292
301
  {
@@ -307,6 +316,23 @@ var FoxHoundDialectMySQL = function()
307
316
  return tmpLimit;
308
317
  };
309
318
 
319
+ /**
320
+ * Generate the use index clause
321
+ *
322
+ * @method: generateIndexHints
323
+ * @param: {Object} pParameters SQL Query Parameters
324
+ * @return: {String} Returns the table limit clause
325
+ */
326
+ var generateIndexHints = function(pParameters)
327
+ {
328
+ if (!Array.isArray(pParameters.indexHints) || pParameters.indexHints.length < 1)
329
+ {
330
+ return '';
331
+ }
332
+
333
+ return ` USE INDEX (${pParameters.indexHints.join(',')})`;
334
+ };
335
+
310
336
  /**
311
337
  * Generate the join clause
312
338
  *
@@ -817,6 +843,7 @@ var FoxHoundDialectMySQL = function()
817
843
  var tmpJoin = generateJoins(pParameters);
818
844
  var tmpOrderBy = generateOrderBy(pParameters);
819
845
  var tmpLimit = generateLimit(pParameters);
846
+ var tmpIndexHints = generateIndexHints(pParameters);
820
847
  const tmpOptDistinct = pParameters.distinct ? ' DISTINCT' : '';
821
848
 
822
849
  if (pParameters.queryOverride)
@@ -824,7 +851,7 @@ var FoxHoundDialectMySQL = function()
824
851
  try
825
852
  {
826
853
  var tmpQueryTemplate = libUnderscore.template(pParameters.queryOverride);
827
- return tmpQueryTemplate({FieldList:tmpFieldList, TableName:tmpTableName, Where:tmpWhere, Join:tmpJoin, OrderBy:tmpOrderBy, Limit:tmpLimit, Distinct: tmpOptDistinct, _Params: pParameters});
854
+ return tmpQueryTemplate({FieldList:tmpFieldList, TableName:tmpTableName, Where:tmpWhere, Join:tmpJoin, OrderBy:tmpOrderBy, Limit:tmpLimit, IndexHints: tmpIndexHints, Distinct: tmpOptDistinct, _Params: pParameters});
828
855
  }
829
856
  catch (pError)
830
857
  {
@@ -834,7 +861,7 @@ var FoxHoundDialectMySQL = function()
834
861
  }
835
862
  }
836
863
 
837
- return `SELECT${tmpOptDistinct}${tmpFieldList} FROM${tmpTableName}${tmpJoin}${tmpWhere}${tmpOrderBy}${tmpLimit};`;
864
+ return `SELECT${tmpOptDistinct}${tmpFieldList} FROM${tmpTableName}${tmpIndexHints}${tmpJoin}${tmpWhere}${tmpOrderBy}${tmpLimit};`;
838
865
  };
839
866
 
840
867
  var Update = function(pParameters)
@@ -897,6 +924,7 @@ var FoxHoundDialectMySQL = function()
897
924
  var tmpTableName = generateTableName(pParameters);
898
925
  var tmpJoin = generateJoins(pParameters);
899
926
  var tmpWhere = generateWhere(pParameters);
927
+ var tmpIndexHints = generateIndexHints(pParameters);
900
928
  // here, we ignore the distinct keyword if no fields have been specified and
901
929
  if (pParameters.distinct && tmpFieldList.length < 1)
902
930
  {
@@ -909,7 +937,7 @@ var FoxHoundDialectMySQL = function()
909
937
  try
910
938
  {
911
939
  var tmpQueryTemplate = libUnderscore.template(pParameters.queryOverride);
912
- return tmpQueryTemplate({FieldList:[], TableName:tmpTableName, Where:tmpWhere, OrderBy:'', Limit:'', Distinct: tmpOptDistinct, _Params: pParameters});
940
+ return tmpQueryTemplate({FieldList:[], TableName:tmpTableName, Where:tmpWhere, OrderBy:'', Limit:'', IndexHints: tmpIndexHints, Distinct: tmpOptDistinct, _Params: pParameters});
913
941
  }
914
942
  catch (pError)
915
943
  {
@@ -919,7 +947,7 @@ var FoxHoundDialectMySQL = function()
919
947
  }
920
948
  }
921
949
 
922
- return `SELECT COUNT(${tmpOptDistinct}${tmpFieldList || '*'}) AS RowCount FROM${tmpTableName}${tmpJoin}${tmpWhere};`;
950
+ return `SELECT COUNT(${tmpOptDistinct}${tmpFieldList || '*'}) AS RowCount FROM${tmpTableName}${tmpIndexHints}${tmpJoin}${tmpWhere};`;
923
951
  };
924
952
 
925
953
  var tmpDialect = ({
@@ -123,6 +123,22 @@ suite
123
123
  }
124
124
  );
125
125
  test
126
+ (
127
+ 'Read Query with Index Hints',
128
+ function()
129
+ {
130
+ var tmpQuery = libFoxHound.new(libFable).setDialect('MySQL').setScope('Animal');
131
+ tmpQuery.addSort({Column:'Cost',Direction:'Descending'});
132
+ tmpQuery.indexHints = ['AnimalIndex_1', 'AnimalIndex_2'];
133
+ // Build the query
134
+ tmpQuery.buildReadQuery();
135
+ // This is the query generated by the MySQL dialect
136
+ libFable.log.trace('Simple Select Query', tmpQuery.query);
137
+ Expect(tmpQuery.query.body)
138
+ .to.equal('SELECT `Animal`.* FROM `Animal` USE INDEX (AnimalIndex_1,AnimalIndex_2) ORDER BY Cost DESC;');
139
+ }
140
+ );
141
+ test
126
142
  (
127
143
  'Read Query with Distinct',
128
144
  function()
@@ -161,6 +177,28 @@ suite
161
177
  }
162
178
  );
163
179
  test
180
+ (
181
+ 'Complex Read Query with qualified and unqualified "SELECT *" cases',
182
+ function()
183
+ {
184
+ var tmpQuery = libFoxHound.new(libFable)
185
+ .setDialect('MySQL')
186
+ .setScope('Animal')
187
+ .setCap(10)
188
+ .setBegin(0)
189
+ .setDataElements(['*', 'Name', 'Age', 'Cost', 'Animal.*'])
190
+ .setSort([{Column:'Age',Direction:'Ascending'}])
191
+ .setFilter({Column:'Age',Operator:'=',Value:'15',Connector:'AND',Parameter:'Age'});
192
+ tmpQuery.addSort('Cost');
193
+ // Build the query
194
+ tmpQuery.buildReadQuery();
195
+ // This is the query generated by the MySQL dialect
196
+ libFable.log.trace('Select Query', tmpQuery.query);
197
+ Expect(tmpQuery.query.body)
198
+ .to.equal('SELECT *, `Name`, `Age`, `Cost`, `Animal`.* FROM `Animal` WHERE Age = :Age_w0 ORDER BY Age, Cost LIMIT 0, 10;');
199
+ }
200
+ );
201
+ test
164
202
  (
165
203
  'Complex Read Query 2',
166
204
  function()
@@ -221,14 +259,15 @@ suite
221
259
  .setDataElements(['Name', 'Age', 'Cost'])
222
260
  .setSort([{Column:'Age',Direction:'Ascending'},{Column:'Cost',Direction:'Descending'}])
223
261
  .setFilter({Column:'Age',Operator:'=',Value:'15',Connector:'AND',Parameter:'Age'});
262
+ tmpQuery.indexHints = ['AnimalIndex_1', 'AnimalIndex_2'];
224
263
  tmpQuery.parameters.CustomFields = 'Name, Age * 5, Cost';
225
- tmpQuery.parameters.queryOverride = 'SELECT <%= _Params.CustomFields %> FROM <%= TableName %> <%= Where %> <%= Limit %>;';
264
+ tmpQuery.parameters.queryOverride = 'SELECT <%= _Params.CustomFields %> FROM <%= TableName %><%= IndexHints %> <%= Where %> <%= Limit %>;';
226
265
  // Build the query
227
266
  tmpQuery.buildReadQuery();
228
267
  // This is the query generated by the MySQL dialect
229
268
  libFable.log.trace('Custom Select Query', tmpQuery.query);
230
269
  Expect(tmpQuery.query.body)
231
- .to.equal('SELECT Name, Age * 5, Cost FROM `Animal` WHERE Age = :Age_w0 LIMIT 0, 10;');
270
+ .to.equal('SELECT Name, Age * 5, Cost FROM `Animal` USE INDEX (AnimalIndex_1,AnimalIndex_2) WHERE Age = :Age_w0 LIMIT 0, 10;');
232
271
  }
233
272
  );
234
273
  test
@@ -280,13 +319,14 @@ suite
280
319
  .setDialect('MySQL')
281
320
  .setScope('Animal')
282
321
  .setFilter({Column:'Age',Operator:'=',Value:'15',Connector:'AND',Parameter:'Age'});
283
- tmpQuery.parameters.queryOverride = 'SELECT COUNT(*) AS RowCount FROM <%= TableName %> <%= Where %>;';
322
+ tmpQuery.indexHints = ['AnimalIndex_1', 'AnimalIndex_2'];
323
+ tmpQuery.parameters.queryOverride = 'SELECT COUNT(*) AS RowCount FROM <%= TableName %><%= IndexHints %> <%= Where %>;';
284
324
  // Build the query
285
325
  tmpQuery.buildCountQuery();
286
326
  // This is the query generated by the MySQL dialect
287
327
  libFable.log.trace('Custom Count Query', tmpQuery.query);
288
328
  Expect(tmpQuery.query.body)
289
- .to.equal('SELECT COUNT(*) AS RowCount FROM `Animal` WHERE Age = :Age_w0;');
329
+ .to.equal('SELECT COUNT(*) AS RowCount FROM `Animal` USE INDEX (AnimalIndex_1,AnimalIndex_2) WHERE Age = :Age_w0;');
290
330
  }
291
331
  );
292
332
  test