foxhound 2.0.8 → 2.0.9
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 +1 -1
- package/source/FoxHound.js +13 -0
- package/source/Parameters.js +7 -2
- package/source/dialects/MicrosoftSQL/FoxHound-Dialect-MSSQL.js +24 -5
- package/source/dialects/MySQL/FoxHound-Dialect-MySQL.js +24 -5
- package/test/FoxHound-Dialect-MySQL_tests.js +22 -4
- package/test/Foxhound-Dialect-MSSQL_tests.js +38 -2
package/package.json
CHANGED
package/source/FoxHound.js
CHANGED
|
@@ -852,6 +852,19 @@ var FoxHound = function()
|
|
|
852
852
|
enumerable: true
|
|
853
853
|
});
|
|
854
854
|
|
|
855
|
+
/**
|
|
856
|
+
* Query
|
|
857
|
+
*
|
|
858
|
+
* @property query
|
|
859
|
+
* @type Object
|
|
860
|
+
*/
|
|
861
|
+
Object.defineProperty(tmpNewFoxHoundObject, 'indexHints',
|
|
862
|
+
{
|
|
863
|
+
get: function() { return _Parameters.indexHints; },
|
|
864
|
+
set: function(pHints) { _Parameters.indexHints = pHints; },
|
|
865
|
+
enumerable: true,
|
|
866
|
+
});
|
|
867
|
+
|
|
855
868
|
/**
|
|
856
869
|
* Result
|
|
857
870
|
*
|
package/source/Parameters.js
CHANGED
|
@@ -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;
|
|
@@ -355,7 +355,7 @@ var FoxHoundDialectMSSQL = function(pFable)
|
|
|
355
355
|
*
|
|
356
356
|
* @method: generateLimit
|
|
357
357
|
* @param: {Object} pParameters SQL Query Parameters
|
|
358
|
-
* @return: {String} Returns the table
|
|
358
|
+
* @return: {String} Returns the table limit clause
|
|
359
359
|
*/
|
|
360
360
|
var generateLimit = function(pParameters)
|
|
361
361
|
{
|
|
@@ -380,6 +380,23 @@ var FoxHoundDialectMSSQL = function(pFable)
|
|
|
380
380
|
return tmpLimit;
|
|
381
381
|
};
|
|
382
382
|
|
|
383
|
+
/**
|
|
384
|
+
* Generate the an index hinting clause
|
|
385
|
+
*
|
|
386
|
+
* @method: generateIndexHints
|
|
387
|
+
* @param: {Object} pParameters SQL Query Parameters
|
|
388
|
+
* @return: {String} Returns the table index hint clause
|
|
389
|
+
*/
|
|
390
|
+
var generateIndexHints = function(pParameters)
|
|
391
|
+
{
|
|
392
|
+
if (!Array.isArray(pParameters.indexHints) || pParameters.indexHints.length < 1)
|
|
393
|
+
{
|
|
394
|
+
return '';
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
return ` WITH(INDEX(${pParameters.indexHints.join(',')}))`
|
|
398
|
+
};
|
|
399
|
+
|
|
383
400
|
/**
|
|
384
401
|
* Generate the join clause
|
|
385
402
|
*
|
|
@@ -909,6 +926,7 @@ var FoxHoundDialectMSSQL = function(pFable)
|
|
|
909
926
|
var tmpJoin = generateJoins(pParameters);
|
|
910
927
|
var tmpOrderBy = generateOrderBy(pParameters);
|
|
911
928
|
var tmpLimit = generateLimit(pParameters);
|
|
929
|
+
var tmpIndexHints = generateIndexHints(pParameters);
|
|
912
930
|
const tmpOptDistinct = pParameters.distinct ? ' DISTINCT' : '';
|
|
913
931
|
|
|
914
932
|
if (pParameters.queryOverride)
|
|
@@ -916,7 +934,7 @@ var FoxHoundDialectMSSQL = function(pFable)
|
|
|
916
934
|
try
|
|
917
935
|
{
|
|
918
936
|
var tmpQueryTemplate = _Fable.Utility.template(pParameters.queryOverride);
|
|
919
|
-
return tmpQueryTemplate({FieldList:tmpFieldList, TableName:tmpTableName, Where:tmpWhere, Join:tmpJoin, OrderBy:tmpOrderBy, Limit:tmpLimit, Distinct: tmpOptDistinct, _Params: pParameters});
|
|
937
|
+
return tmpQueryTemplate({FieldList:tmpFieldList, TableName:tmpTableName, Where:tmpWhere, Join:tmpJoin, OrderBy:tmpOrderBy, Limit:tmpLimit, IndexHints: tmpIndexHints, Distinct: tmpOptDistinct, _Params: pParameters});
|
|
920
938
|
}
|
|
921
939
|
catch (pError)
|
|
922
940
|
{
|
|
@@ -926,7 +944,7 @@ var FoxHoundDialectMSSQL = function(pFable)
|
|
|
926
944
|
}
|
|
927
945
|
}
|
|
928
946
|
|
|
929
|
-
return `SELECT${tmpOptDistinct}${tmpFieldList} FROM${tmpTableName}${tmpJoin}${tmpWhere}${tmpOrderBy}${tmpLimit};`;
|
|
947
|
+
return `SELECT${tmpOptDistinct}${tmpFieldList} FROM${tmpTableName}${tmpIndexHints}${tmpJoin}${tmpWhere}${tmpOrderBy}${tmpLimit};`;
|
|
930
948
|
};
|
|
931
949
|
|
|
932
950
|
var Update = function(pParameters)
|
|
@@ -989,6 +1007,7 @@ var FoxHoundDialectMSSQL = function(pFable)
|
|
|
989
1007
|
var tmpTableName = generateTableName(pParameters);
|
|
990
1008
|
var tmpJoin = generateJoins(pParameters);
|
|
991
1009
|
var tmpWhere = generateWhere(pParameters);
|
|
1010
|
+
var tmpIndexHints = generateIndexHints(pParameters);
|
|
992
1011
|
// here, we ignore the distinct keyword if no fields have been specified and
|
|
993
1012
|
if (pParameters.distinct && tmpFieldList.length < 1)
|
|
994
1013
|
{
|
|
@@ -1001,7 +1020,7 @@ var FoxHoundDialectMSSQL = function(pFable)
|
|
|
1001
1020
|
try
|
|
1002
1021
|
{
|
|
1003
1022
|
var tmpQueryTemplate = _Fable.Utility.template(pParameters.queryOverride);
|
|
1004
|
-
return tmpQueryTemplate({FieldList:[], TableName:tmpTableName, Where:tmpWhere, OrderBy:'', Limit:'', Distinct: tmpOptDistinct, _Params: pParameters});
|
|
1023
|
+
return tmpQueryTemplate({FieldList:[], TableName:tmpTableName, Where:tmpWhere, OrderBy:'', IndexHints: tmpIndexHints, Limit:'', Distinct: tmpOptDistinct, _Params: pParameters});
|
|
1005
1024
|
}
|
|
1006
1025
|
catch (pError)
|
|
1007
1026
|
{
|
|
@@ -1011,7 +1030,7 @@ var FoxHoundDialectMSSQL = function(pFable)
|
|
|
1011
1030
|
}
|
|
1012
1031
|
}
|
|
1013
1032
|
|
|
1014
|
-
return `SELECT COUNT(${tmpOptDistinct}${tmpFieldList || '*'}) AS Row_Count FROM${tmpTableName}${tmpJoin}${tmpWhere};`;
|
|
1033
|
+
return `SELECT COUNT(${tmpOptDistinct}${tmpFieldList || '*'}) AS Row_Count FROM${tmpTableName}${tmpIndexHints}${tmpJoin}${tmpWhere};`;
|
|
1015
1034
|
};
|
|
1016
1035
|
|
|
1017
1036
|
var tmpDialect = ({
|
|
@@ -296,7 +296,7 @@ var FoxHoundDialectMySQL = function(pFable)
|
|
|
296
296
|
*
|
|
297
297
|
* @method: generateLimit
|
|
298
298
|
* @param: {Object} pParameters SQL Query Parameters
|
|
299
|
-
* @return: {String} Returns the table
|
|
299
|
+
* @return: {String} Returns the table limit clause
|
|
300
300
|
*/
|
|
301
301
|
var generateLimit = function(pParameters)
|
|
302
302
|
{
|
|
@@ -317,6 +317,23 @@ var FoxHoundDialectMySQL = function(pFable)
|
|
|
317
317
|
return tmpLimit;
|
|
318
318
|
};
|
|
319
319
|
|
|
320
|
+
/**
|
|
321
|
+
* Generate the use index clause
|
|
322
|
+
*
|
|
323
|
+
* @method: generateIndexHints
|
|
324
|
+
* @param: {Object} pParameters SQL Query Parameters
|
|
325
|
+
* @return: {String} Returns the table limit clause
|
|
326
|
+
*/
|
|
327
|
+
var generateIndexHints = function(pParameters)
|
|
328
|
+
{
|
|
329
|
+
if (!Array.isArray(pParameters.indexHints) || pParameters.indexHints.length < 1)
|
|
330
|
+
{
|
|
331
|
+
return '';
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
return ` USE INDEX (${pParameters.indexHints.join(',')})`;
|
|
335
|
+
};
|
|
336
|
+
|
|
320
337
|
/**
|
|
321
338
|
* Generate the join clause
|
|
322
339
|
*
|
|
@@ -827,6 +844,7 @@ var FoxHoundDialectMySQL = function(pFable)
|
|
|
827
844
|
var tmpJoin = generateJoins(pParameters);
|
|
828
845
|
var tmpOrderBy = generateOrderBy(pParameters);
|
|
829
846
|
var tmpLimit = generateLimit(pParameters);
|
|
847
|
+
var tmpIndexHints = generateIndexHints(pParameters);
|
|
830
848
|
const tmpOptDistinct = pParameters.distinct ? ' DISTINCT' : '';
|
|
831
849
|
|
|
832
850
|
if (pParameters.queryOverride)
|
|
@@ -834,7 +852,7 @@ var FoxHoundDialectMySQL = function(pFable)
|
|
|
834
852
|
try
|
|
835
853
|
{
|
|
836
854
|
var tmpQueryTemplate = _Fable.Utility.template(pParameters.queryOverride);
|
|
837
|
-
return tmpQueryTemplate({FieldList:tmpFieldList, TableName:tmpTableName, Where:tmpWhere, Join:tmpJoin, OrderBy:tmpOrderBy, Limit:tmpLimit, Distinct: tmpOptDistinct, _Params: pParameters});
|
|
855
|
+
return tmpQueryTemplate({FieldList:tmpFieldList, TableName:tmpTableName, Where:tmpWhere, Join:tmpJoin, OrderBy:tmpOrderBy, Limit:tmpLimit, IndexHints: tmpIndexHints, Distinct: tmpOptDistinct, _Params: pParameters});
|
|
838
856
|
}
|
|
839
857
|
catch (pError)
|
|
840
858
|
{
|
|
@@ -844,7 +862,7 @@ var FoxHoundDialectMySQL = function(pFable)
|
|
|
844
862
|
}
|
|
845
863
|
}
|
|
846
864
|
|
|
847
|
-
return `SELECT${tmpOptDistinct}${tmpFieldList} FROM${tmpTableName}${tmpJoin}${tmpWhere}${tmpOrderBy}${tmpLimit};`;
|
|
865
|
+
return `SELECT${tmpOptDistinct}${tmpFieldList} FROM${tmpTableName}${tmpIndexHints}${tmpJoin}${tmpWhere}${tmpOrderBy}${tmpLimit};`;
|
|
848
866
|
};
|
|
849
867
|
|
|
850
868
|
var Update = function(pParameters)
|
|
@@ -907,6 +925,7 @@ var FoxHoundDialectMySQL = function(pFable)
|
|
|
907
925
|
var tmpTableName = generateTableName(pParameters);
|
|
908
926
|
var tmpJoin = generateJoins(pParameters);
|
|
909
927
|
var tmpWhere = generateWhere(pParameters);
|
|
928
|
+
var tmpIndexHints = generateIndexHints(pParameters);
|
|
910
929
|
// here, we ignore the distinct keyword if no fields have been specified and
|
|
911
930
|
if (pParameters.distinct && tmpFieldList.length < 1)
|
|
912
931
|
{
|
|
@@ -919,7 +938,7 @@ var FoxHoundDialectMySQL = function(pFable)
|
|
|
919
938
|
try
|
|
920
939
|
{
|
|
921
940
|
var tmpQueryTemplate = _Fable.Utility.template(pParameters.queryOverride);
|
|
922
|
-
return tmpQueryTemplate({FieldList:[], TableName:tmpTableName, Where:tmpWhere, OrderBy:'', Limit:'', Distinct: tmpOptDistinct, _Params: pParameters});
|
|
941
|
+
return tmpQueryTemplate({FieldList:[], TableName:tmpTableName, Where:tmpWhere, OrderBy:'', Limit:'', IndexHints: tmpIndexHints, Distinct: tmpOptDistinct, _Params: pParameters});
|
|
923
942
|
}
|
|
924
943
|
catch (pError)
|
|
925
944
|
{
|
|
@@ -929,7 +948,7 @@ var FoxHoundDialectMySQL = function(pFable)
|
|
|
929
948
|
}
|
|
930
949
|
}
|
|
931
950
|
|
|
932
|
-
return `SELECT COUNT(${tmpOptDistinct}${tmpFieldList || '*'}) AS RowCount FROM${tmpTableName}${tmpJoin}${tmpWhere};`;
|
|
951
|
+
return `SELECT COUNT(${tmpOptDistinct}${tmpFieldList || '*'}) AS RowCount FROM${tmpTableName}${tmpIndexHints}${tmpJoin}${tmpWhere};`;
|
|
933
952
|
};
|
|
934
953
|
|
|
935
954
|
var tmpDialect = ({
|
|
@@ -124,6 +124,22 @@ suite
|
|
|
124
124
|
}
|
|
125
125
|
);
|
|
126
126
|
test
|
|
127
|
+
(
|
|
128
|
+
'Read Query with Index Hints',
|
|
129
|
+
function()
|
|
130
|
+
{
|
|
131
|
+
var tmpQuery = libFoxHound.new(_Fable).setDialect('MySQL').setScope('Animal');
|
|
132
|
+
tmpQuery.addSort({Column:'Cost',Direction:'Descending'});
|
|
133
|
+
tmpQuery.indexHints = ['AnimalIndex_1', 'AnimalIndex_2'];
|
|
134
|
+
// Build the query
|
|
135
|
+
tmpQuery.buildReadQuery();
|
|
136
|
+
// This is the query generated by the MySQL dialect
|
|
137
|
+
_Fable.log.trace('Simple Select Query', tmpQuery.query);
|
|
138
|
+
Expect(tmpQuery.query.body)
|
|
139
|
+
.to.equal('SELECT `Animal`.* FROM `Animal` USE INDEX (AnimalIndex_1,AnimalIndex_2) ORDER BY Cost DESC;');
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
test
|
|
127
143
|
(
|
|
128
144
|
'Read Query with Distinct',
|
|
129
145
|
function()
|
|
@@ -244,14 +260,15 @@ suite
|
|
|
244
260
|
.setDataElements(['Name', 'Age', 'Cost'])
|
|
245
261
|
.setSort([{Column:'Age',Direction:'Ascending'},{Column:'Cost',Direction:'Descending'}])
|
|
246
262
|
.setFilter({Column:'Age',Operator:'=',Value:'15',Connector:'AND',Parameter:'Age'});
|
|
263
|
+
tmpQuery.indexHints = ['AnimalIndex_1', 'AnimalIndex_2'];
|
|
247
264
|
tmpQuery.parameters.CustomFields = 'Name, Age * 5, Cost';
|
|
248
|
-
tmpQuery.parameters.queryOverride = 'SELECT <%= _Params.CustomFields %> FROM <%= TableName %> <%= Where %> <%= Limit %>;';
|
|
265
|
+
tmpQuery.parameters.queryOverride = 'SELECT <%= _Params.CustomFields %> FROM <%= TableName %><%= IndexHints %> <%= Where %> <%= Limit %>;';
|
|
249
266
|
// Build the query
|
|
250
267
|
tmpQuery.buildReadQuery();
|
|
251
268
|
// This is the query generated by the MySQL dialect
|
|
252
269
|
_Fable.log.trace('Custom Select Query', tmpQuery.query);
|
|
253
270
|
Expect(tmpQuery.query.body)
|
|
254
|
-
.to.equal('SELECT Name, Age * 5, Cost FROM `Animal` WHERE Age = :Age_w0 LIMIT 0, 10;');
|
|
271
|
+
.to.equal('SELECT Name, Age * 5, Cost FROM `Animal` USE INDEX (AnimalIndex_1,AnimalIndex_2) WHERE Age = :Age_w0 LIMIT 0, 10;');
|
|
255
272
|
}
|
|
256
273
|
);
|
|
257
274
|
test
|
|
@@ -303,13 +320,14 @@ suite
|
|
|
303
320
|
.setDialect('MySQL')
|
|
304
321
|
.setScope('Animal')
|
|
305
322
|
.setFilter({Column:'Age',Operator:'=',Value:'15',Connector:'AND',Parameter:'Age'});
|
|
306
|
-
tmpQuery.
|
|
323
|
+
tmpQuery.indexHints = ['AnimalIndex_1', 'AnimalIndex_2'];
|
|
324
|
+
tmpQuery.parameters.queryOverride = 'SELECT COUNT(*) AS RowCount FROM <%= TableName %><%= IndexHints %> <%= Where %>;';
|
|
307
325
|
// Build the query
|
|
308
326
|
tmpQuery.buildCountQuery();
|
|
309
327
|
// This is the query generated by the MySQL dialect
|
|
310
328
|
_Fable.log.trace('Custom Count Query', tmpQuery.query);
|
|
311
329
|
Expect(tmpQuery.query.body)
|
|
312
|
-
.to.equal('SELECT COUNT(*) AS RowCount FROM `Animal` WHERE Age = :Age_w0;');
|
|
330
|
+
.to.equal('SELECT COUNT(*) AS RowCount FROM `Animal` USE INDEX (AnimalIndex_1,AnimalIndex_2) WHERE Age = :Age_w0;');
|
|
313
331
|
}
|
|
314
332
|
);
|
|
315
333
|
test
|
|
@@ -126,6 +126,22 @@ suite
|
|
|
126
126
|
}
|
|
127
127
|
);
|
|
128
128
|
test
|
|
129
|
+
(
|
|
130
|
+
'Read Query with Index Hinting',
|
|
131
|
+
function()
|
|
132
|
+
{
|
|
133
|
+
var tmpQuery = libFoxHound.new(_Fable).setDialect('MSSQL').setScope('Animal');
|
|
134
|
+
tmpQuery.addSort({Column:'Cost',Direction:'Descending'});
|
|
135
|
+
tmpQuery.indexHints = ['AnimalIndex_1'];
|
|
136
|
+
// Build the query
|
|
137
|
+
tmpQuery.buildReadQuery();
|
|
138
|
+
// This is the query generated by the MSSQL dialect
|
|
139
|
+
_Fable.log.trace('Simple Select Query', tmpQuery.query);
|
|
140
|
+
Expect(tmpQuery.query.body)
|
|
141
|
+
.to.equal('SELECT Animal.* FROM Animal WITH(INDEX(AnimalIndex_1)) ORDER BY Cost DESC;');
|
|
142
|
+
}
|
|
143
|
+
);
|
|
144
|
+
test
|
|
129
145
|
(
|
|
130
146
|
'Read Query with Distinct',
|
|
131
147
|
function()
|
|
@@ -301,7 +317,7 @@ suite
|
|
|
301
317
|
.setDialect('MSSQL')
|
|
302
318
|
.setScope('Animal')
|
|
303
319
|
.setFilter({Column:'Age',Operator:'=',Value:'15',Connector:'AND',Parameter:'Age'});
|
|
304
|
-
tmpQuery.parameters.queryOverride = 'SELECT COUNT(*) AS RowCount FROM <%= TableName %> <%= Where %>;';
|
|
320
|
+
tmpQuery.parameters.queryOverride = 'SELECT COUNT(*) AS RowCount FROM <%= TableName %><%= IndexHints %> <%= Where %>;';
|
|
305
321
|
// Build the query
|
|
306
322
|
tmpQuery.buildCountQuery();
|
|
307
323
|
// This is the query generated by the MSSQL dialect
|
|
@@ -311,6 +327,25 @@ suite
|
|
|
311
327
|
}
|
|
312
328
|
);
|
|
313
329
|
test
|
|
330
|
+
(
|
|
331
|
+
'Custom Count Query with Index Hinting',
|
|
332
|
+
function()
|
|
333
|
+
{
|
|
334
|
+
var tmpQuery = libFoxHound.new(_Fable)
|
|
335
|
+
.setDialect('MSSQL')
|
|
336
|
+
.setScope('Animal')
|
|
337
|
+
.setFilter({Column:'Age',Operator:'=',Value:'15',Connector:'AND',Parameter:'Age'});
|
|
338
|
+
tmpQuery.indexHints = ['AnimalIndex_1'];
|
|
339
|
+
tmpQuery.parameters.queryOverride = 'SELECT COUNT(*) AS RowCount FROM <%= TableName %><%= IndexHints %> <%= Where %>;';
|
|
340
|
+
// Build the query
|
|
341
|
+
tmpQuery.buildCountQuery();
|
|
342
|
+
// This is the query generated by the MSSQL dialect
|
|
343
|
+
_Fable.log.trace('Custom Count Query', tmpQuery.query);
|
|
344
|
+
Expect(tmpQuery.query.body)
|
|
345
|
+
.to.equal('SELECT COUNT(*) AS RowCount FROM Animal WITH(INDEX(AnimalIndex_1)) WHERE Age = @Age_w0;');
|
|
346
|
+
}
|
|
347
|
+
);
|
|
348
|
+
test
|
|
314
349
|
(
|
|
315
350
|
'Custom Count Query with Custom Parameters',
|
|
316
351
|
function()
|
|
@@ -390,13 +425,14 @@ suite
|
|
|
390
425
|
var tmpQuery = libFoxHound.new(_Fable)
|
|
391
426
|
.setDialect('MSSQL')
|
|
392
427
|
.setScope('Animal');
|
|
428
|
+
tmpQuery.indexHints = ['AnimalIndex_1'];
|
|
393
429
|
|
|
394
430
|
// Build the query
|
|
395
431
|
tmpQuery.buildCountQuery();
|
|
396
432
|
// This is the query generated by the MSSQL dialect
|
|
397
433
|
_Fable.log.trace('Count Query', tmpQuery.query);
|
|
398
434
|
Expect(tmpQuery.query.body)
|
|
399
|
-
.to.equal('SELECT COUNT(*) AS Row_Count FROM Animal;');
|
|
435
|
+
.to.equal('SELECT COUNT(*) AS Row_Count FROM Animal WITH(INDEX(AnimalIndex_1));');
|
|
400
436
|
}
|
|
401
437
|
);
|
|
402
438
|
test
|