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
package/source/FoxHound.js
CHANGED
|
@@ -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
|
*
|
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;
|
|
@@ -113,12 +113,21 @@ var FoxHoundDialectMySQL = function()
|
|
|
113
113
|
let pFieldNames = pFieldName.split('.');
|
|
114
114
|
if (pFieldNames.length > 1)
|
|
115
115
|
{
|
|
116
|
-
|
|
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
|
-
|
|
124
|
+
const cleansedFieldName = cleanseQuoting(pFieldNames[0]);
|
|
125
|
+
if (cleansedFieldName === '*')
|
|
119
126
|
{
|
|
120
|
-
|
|
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
|
|
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.
|
|
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
|