foxhound 1.0.31 → 1.0.34
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/.vscode/launch.json +18 -0
- package/debug/Harness.js +46 -0
- package/package.json +1 -1
- package/source/FoxHound.js +21 -0
- package/source/dialects/ALASQL/FoxHound-Dialect-ALASQL.js +40 -13
- package/source/dialects/English/FoxHound-Dialect-English.js +4 -2
- package/source/dialects/MeadowEndpoints/FoxHound-Dialect-MeadowEndpoints.js +445 -0
- package/source/dialects/MySQL/FoxHound-Dialect-MySQL.js +50 -14
- package/test/FoxHound-Dialect-ALASQL_tests.js +137 -0
- package/test/FoxHound-Dialect-English_tests.js +27 -0
- package/test/FoxHound-Dialect-MeadowEndpoints_tests.js +589 -0
- package/test/FoxHound-Dialect-MySQL_tests.js +118 -0
- package/0001-Fix-duck-typing-checks-to-not-fail-on-Fable-2.x.-Fix.patch +0 -482
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Use IntelliSense to learn about possible attributes.
|
|
3
|
+
// Hover to view descriptions of existing attributes.
|
|
4
|
+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
5
|
+
"version": "0.2.0",
|
|
6
|
+
"configurations": [
|
|
7
|
+
{
|
|
8
|
+
"type": "pwa-node",
|
|
9
|
+
"request": "launch",
|
|
10
|
+
"name": "Launch Program",
|
|
11
|
+
"outputCapture": "std",
|
|
12
|
+
"skipFiles": [
|
|
13
|
+
"<node_internals>/**"
|
|
14
|
+
],
|
|
15
|
+
"program": "${workspaceFolder}/debug/Harness.js"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
package/debug/Harness.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
var libFable = require('fable').new({});
|
|
2
|
+
var libFoxHound = require('../source/FoxHound.js');
|
|
3
|
+
|
|
4
|
+
var _AnimalSchema = (
|
|
5
|
+
[
|
|
6
|
+
{ Column: "IDAnimal", Type:"AutoIdentity" },
|
|
7
|
+
{ Column: "GUIDAnimal", Type:"AutoGUID" },
|
|
8
|
+
{ Column: "CreateDate", Type:"CreateDate" },
|
|
9
|
+
{ Column: "CreatingIDUser", Type:"CreateIDUser" },
|
|
10
|
+
{ Column: "UpdateDate", Type:"UpdateDate" },
|
|
11
|
+
{ Column: "UpdatingIDUser", Type:"UpdateIDUser" },
|
|
12
|
+
{ Column: "Deleted", Type:"Deleted" },
|
|
13
|
+
{ Column: "DeletingIDUser", Type:"DeleteIDUser" },
|
|
14
|
+
{ Column: "DeleteDate", Type:"DeleteDate" }
|
|
15
|
+
]);
|
|
16
|
+
|
|
17
|
+
var _AnimalSchemaWithoutDeleted = (
|
|
18
|
+
[
|
|
19
|
+
{ Column: "IDAnimal", Type:"AutoIdentity" },
|
|
20
|
+
{ Column: "GUIDAnimal", Type:"AutoGUID" },
|
|
21
|
+
{ Column: "CreateDate", Type:"CreateDate" },
|
|
22
|
+
{ Column: "CreatingIDUser", Type:"CreateIDUser" },
|
|
23
|
+
{ Column: "UpdateDate", Type:"UpdateDate" },
|
|
24
|
+
{ Column: "UpdatingIDUser", Type:"UpdateIDUser" }
|
|
25
|
+
]);
|
|
26
|
+
|
|
27
|
+
var tmpQuery = libFoxHound.new(libFable)
|
|
28
|
+
.setDialect('MeadowEndpoints')
|
|
29
|
+
.setScope('Animal')
|
|
30
|
+
.setDataElements(['Name', 'Age', 'Cost'])
|
|
31
|
+
.setCap(100)
|
|
32
|
+
.addFilter('Age', '25')
|
|
33
|
+
.addFilter('', '', '(')
|
|
34
|
+
.addFilter('Color', 'Red')
|
|
35
|
+
.addFilter('Color', 'Green', '=', 'OR')
|
|
36
|
+
.addFilter('', '', ')')
|
|
37
|
+
.addFilter('Description', '', 'IS NOT NULL')
|
|
38
|
+
.addFilter('IDOffice', [10, 11, 15, 18, 22], 'IN');
|
|
39
|
+
tmpQuery.setLogLevel(3).addSort('Age');
|
|
40
|
+
// Build the query
|
|
41
|
+
tmpQuery.buildReadQuery();
|
|
42
|
+
// This is the query generated by the MeadowEndpoints dialect
|
|
43
|
+
libFable.log.trace('Select Query', tmpQuery.query);
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
console.log(tmpQuery.query.body);
|
package/package.json
CHANGED
package/source/FoxHound.js
CHANGED
|
@@ -194,6 +194,26 @@ var FoxHound = function()
|
|
|
194
194
|
return this;
|
|
195
195
|
};
|
|
196
196
|
|
|
197
|
+
/**
|
|
198
|
+
* Set whether the query returns DISTINCT results.
|
|
199
|
+
* For count queries, returns the distinct for the selected fields, or all fields in the base table by default.
|
|
200
|
+
*
|
|
201
|
+
* @method setDistinct
|
|
202
|
+
* @param {Boolean} pDistinct True if the query should be distinct.
|
|
203
|
+
* @return {Object} Returns the current Query for chaining.
|
|
204
|
+
*/
|
|
205
|
+
var setDistinct = function(pDistinct)
|
|
206
|
+
{
|
|
207
|
+
_Parameters.distinct = !!pDistinct;
|
|
208
|
+
|
|
209
|
+
if (_LogLevel > 2)
|
|
210
|
+
{
|
|
211
|
+
_Fable.log.info('Distinct set: '+_Parameters.distinct, {queryUUID:_UUID, parameters:_Parameters});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return this;
|
|
215
|
+
};
|
|
216
|
+
|
|
197
217
|
|
|
198
218
|
/**
|
|
199
219
|
* Set the Data Elements for the Query. *Data Elements* are the fields
|
|
@@ -792,6 +812,7 @@ var FoxHound = function()
|
|
|
792
812
|
setLogLevel: setLogLevel,
|
|
793
813
|
|
|
794
814
|
setScope: setScope,
|
|
815
|
+
setDistinct: setDistinct,
|
|
795
816
|
setIDUser: setIDUser,
|
|
796
817
|
setDataElements: setDataElements,
|
|
797
818
|
setBegin: setBegin,
|
|
@@ -21,7 +21,7 @@ var FoxHoundDialectALASQL = function()
|
|
|
21
21
|
{
|
|
22
22
|
/**
|
|
23
23
|
* Generate a table name from the scope.
|
|
24
|
-
*
|
|
24
|
+
*
|
|
25
25
|
* Because ALASQL is all in-memory, and can be run in two modes (anonymous
|
|
26
26
|
* working on arrays or table-based) we are going to make this a programmable
|
|
27
27
|
* value. Then we can share the code across both providers.
|
|
@@ -34,7 +34,7 @@ var FoxHoundDialectALASQL = function()
|
|
|
34
34
|
{
|
|
35
35
|
return ' '+pParameters.scope;
|
|
36
36
|
};
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
/**
|
|
39
39
|
* Escape columns, because ALASQL has more reserved KWs than most SQL dialects
|
|
40
40
|
*/
|
|
@@ -67,14 +67,33 @@ var FoxHoundDialectALASQL = function()
|
|
|
67
67
|
*
|
|
68
68
|
* @method: generateFieldList
|
|
69
69
|
* @param: {Object} pParameters SQL Query Parameters
|
|
70
|
-
* @
|
|
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.
|
|
71
73
|
*/
|
|
72
|
-
var generateFieldList = function(pParameters)
|
|
74
|
+
var generateFieldList = function(pParameters, pIsForCountClause)
|
|
73
75
|
{
|
|
74
76
|
var tmpDataElements = pParameters.dataElements;
|
|
75
77
|
if (!Array.isArray(tmpDataElements) || tmpDataElements.length < 1)
|
|
76
78
|
{
|
|
77
|
-
|
|
79
|
+
if (!pIsForCountClause)
|
|
80
|
+
{
|
|
81
|
+
return ' *';
|
|
82
|
+
}
|
|
83
|
+
// we need to list all of the table fields explicitly; get them from the schema
|
|
84
|
+
const tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];
|
|
85
|
+
if (tmpSchema.length < 1)
|
|
86
|
+
{
|
|
87
|
+
// this means we have no schema; returning an empty string here signals the calling code to handle this case
|
|
88
|
+
return '';
|
|
89
|
+
}
|
|
90
|
+
const idColumn = tmpSchema.find((entry) => entry.Type === 'AutoIdentity');
|
|
91
|
+
if (!idColumn)
|
|
92
|
+
{
|
|
93
|
+
// this means there is no autoincrementing unique ID column; treat as above
|
|
94
|
+
return '';
|
|
95
|
+
}
|
|
96
|
+
return ` ${idColumn.Column}`;
|
|
78
97
|
}
|
|
79
98
|
|
|
80
99
|
var tmpFieldList = ' ';
|
|
@@ -94,10 +113,10 @@ var FoxHoundDialectALASQL = function()
|
|
|
94
113
|
*
|
|
95
114
|
* Each clause is an object like:
|
|
96
115
|
{
|
|
97
|
-
Column:'Name',
|
|
98
|
-
Operator:'EQ',
|
|
99
|
-
Value:'John',
|
|
100
|
-
Connector:'And',
|
|
116
|
+
Column:'Name',
|
|
117
|
+
Operator:'EQ',
|
|
118
|
+
Value:'John',
|
|
119
|
+
Connector:'And',
|
|
101
120
|
Parameter:'Name'
|
|
102
121
|
}
|
|
103
122
|
*
|
|
@@ -685,13 +704,14 @@ var FoxHoundDialectALASQL = function()
|
|
|
685
704
|
var tmpWhere = generateWhere(pParameters);
|
|
686
705
|
var tmpOrderBy = generateOrderBy(pParameters);
|
|
687
706
|
var tmpLimit = generateLimit(pParameters);
|
|
707
|
+
const tmpOptDistinct = pParameters.distinct ? ' DISTINCT' : '';
|
|
688
708
|
|
|
689
709
|
if (pParameters.queryOverride)
|
|
690
710
|
{
|
|
691
711
|
try
|
|
692
712
|
{
|
|
693
713
|
var tmpQueryTemplate = libUnderscore.template(pParameters.queryOverride);
|
|
694
|
-
return tmpQueryTemplate({FieldList:tmpFieldList, TableName:tmpTableName, Where:tmpWhere, OrderBy:tmpOrderBy, Limit:tmpLimit});
|
|
714
|
+
return tmpQueryTemplate({FieldList:tmpFieldList, TableName:tmpTableName, Where:tmpWhere, OrderBy:tmpOrderBy, Limit:tmpLimit, Distinct: tmpOptDistinct});
|
|
695
715
|
}
|
|
696
716
|
catch (pError)
|
|
697
717
|
{
|
|
@@ -701,7 +721,7 @@ var FoxHoundDialectALASQL = function()
|
|
|
701
721
|
}
|
|
702
722
|
}
|
|
703
723
|
|
|
704
|
-
return
|
|
724
|
+
return `SELECT${tmpOptDistinct}${tmpFieldList} FROM${tmpTableName}${tmpWhere}${tmpOrderBy}${tmpLimit};`;
|
|
705
725
|
};
|
|
706
726
|
|
|
707
727
|
var Update = function(pParameters)
|
|
@@ -739,13 +759,20 @@ var FoxHoundDialectALASQL = function()
|
|
|
739
759
|
{
|
|
740
760
|
var tmpTableName = generateTableName(pParameters);
|
|
741
761
|
var tmpWhere = generateWhere(pParameters);
|
|
762
|
+
const tmpFieldList = pParameters.distinct ? generateFieldList(pParameters, true) : '*';
|
|
742
763
|
|
|
764
|
+
// here, we ignore the distinct keyword if no fields have been specified and
|
|
765
|
+
if (pParameters.distinct && tmpFieldList.length < 1)
|
|
766
|
+
{
|
|
767
|
+
console.warn('Distinct requested but no field list or schema are available, so not honoring distinct for count query.');
|
|
768
|
+
}
|
|
769
|
+
const tmpOptDistinct = pParameters.distinct && tmpFieldList.length > 0 ? 'DISTINCT' : '';
|
|
743
770
|
if (pParameters.queryOverride)
|
|
744
771
|
{
|
|
745
772
|
try
|
|
746
773
|
{
|
|
747
774
|
var tmpQueryTemplate = libUnderscore.template(pParameters.queryOverride);
|
|
748
|
-
return tmpQueryTemplate({FieldList:[], TableName:tmpTableName, Where:tmpWhere, OrderBy:'', Limit:''});
|
|
775
|
+
return tmpQueryTemplate({FieldList:[], TableName:tmpTableName, Where:tmpWhere, OrderBy:'', Limit:'', Distinct: tmpOptDistinct});
|
|
749
776
|
}
|
|
750
777
|
catch (pError)
|
|
751
778
|
{
|
|
@@ -755,7 +782,7 @@ var FoxHoundDialectALASQL = function()
|
|
|
755
782
|
}
|
|
756
783
|
}
|
|
757
784
|
|
|
758
|
-
return
|
|
785
|
+
return `SELECT COUNT(${tmpOptDistinct}${tmpFieldList || '*'}) AS RowCount FROM${tmpTableName}${tmpWhere};`;
|
|
759
786
|
};
|
|
760
787
|
|
|
761
788
|
var tmpDialect = ({
|
|
@@ -35,8 +35,9 @@ var FoxHoundDialectEnglish = function()
|
|
|
35
35
|
var Read = function(pParameters)
|
|
36
36
|
{
|
|
37
37
|
var tmpScope = pParameters.scope;
|
|
38
|
+
const tmpDistinct = pParameters.distinct ? 'unique ' : '';
|
|
38
39
|
|
|
39
|
-
return
|
|
40
|
+
return `Please give me all your ${tmpDistinct}${tmpScope} records. Thanks.`;
|
|
40
41
|
};
|
|
41
42
|
|
|
42
43
|
var Update = function(pParameters)
|
|
@@ -56,8 +57,9 @@ var FoxHoundDialectEnglish = function()
|
|
|
56
57
|
var Count = function(pParameters)
|
|
57
58
|
{
|
|
58
59
|
var tmpScope = pParameters.scope;
|
|
60
|
+
const tmpDistinct = pParameters.distinct ? 'unique ' : '';
|
|
59
61
|
|
|
60
|
-
return
|
|
62
|
+
return `Count your ${tmpDistinct}${tmpScope}.`;
|
|
61
63
|
};
|
|
62
64
|
|
|
63
65
|
var tmpDialect = ({
|
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FoxHound Meadow Endpoints Dialect
|
|
3
|
+
*
|
|
4
|
+
* @license MIT
|
|
5
|
+
*
|
|
6
|
+
* @author Steven Velozo <steven@velozo.com>
|
|
7
|
+
* @class FoxHoundDialectMeadowEndpoints
|
|
8
|
+
*/
|
|
9
|
+
var libUnderscore = require('underscore');
|
|
10
|
+
|
|
11
|
+
var FoxHoundDialectMeadowEndpoints = function()
|
|
12
|
+
{
|
|
13
|
+
/**
|
|
14
|
+
* Generate a table name from the scope
|
|
15
|
+
*
|
|
16
|
+
* @method: generateTableName
|
|
17
|
+
* @param: {Object} pParameters SQL Query Parameters
|
|
18
|
+
* @return: {String} Returns the table name clause
|
|
19
|
+
*/
|
|
20
|
+
var generateTableName = function(pParameters)
|
|
21
|
+
{
|
|
22
|
+
return pParameters.scope;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Generate a field list from the array of dataElements
|
|
27
|
+
*
|
|
28
|
+
* Each entry in the dataElements is a simple string
|
|
29
|
+
*
|
|
30
|
+
* @method: generateFieldList
|
|
31
|
+
* @param: {Object} pParameters SQL Query Parameters
|
|
32
|
+
* @return: {String} Returns the field list clause
|
|
33
|
+
*/
|
|
34
|
+
var generateFieldList = function(pParameters)
|
|
35
|
+
{
|
|
36
|
+
var tmpDataElements = pParameters.dataElements;
|
|
37
|
+
if (!Array.isArray(tmpDataElements) || tmpDataElements.length < 1)
|
|
38
|
+
{
|
|
39
|
+
return '';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
var tmpFieldList = '';
|
|
43
|
+
for (var i = 0; i < tmpDataElements.length; i++)
|
|
44
|
+
{
|
|
45
|
+
if (i > 0)
|
|
46
|
+
{
|
|
47
|
+
tmpFieldList += ',';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
tmpFieldList += tmpDataElements[i];
|
|
51
|
+
}
|
|
52
|
+
return tmpFieldList;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Generate a query from the array of where clauses
|
|
57
|
+
*
|
|
58
|
+
* Each clause is an object like:
|
|
59
|
+
{
|
|
60
|
+
Column:'Name',
|
|
61
|
+
Operator:'EQ',
|
|
62
|
+
Value:'John',
|
|
63
|
+
Connector:'And',
|
|
64
|
+
Parameter:'Name'
|
|
65
|
+
}
|
|
66
|
+
*
|
|
67
|
+
* @method: generateWhere
|
|
68
|
+
* @param: {Object} pParameters SQL Query Parameters
|
|
69
|
+
* @return: {String} Returns the WHERE clause prefixed with WHERE, or an empty string if unnecessary
|
|
70
|
+
*/
|
|
71
|
+
var generateWhere = function(pParameters)
|
|
72
|
+
{
|
|
73
|
+
var tmpFilter = Array.isArray(pParameters.filter) ? pParameters.filter : [];
|
|
74
|
+
var tmpTableName = generateTableName(pParameters);
|
|
75
|
+
|
|
76
|
+
var tmpURL = '';
|
|
77
|
+
|
|
78
|
+
let tmpfAddFilter = (pFilterCommand, pFilterParameters) =>
|
|
79
|
+
{
|
|
80
|
+
if (tmpURL.length > 0)
|
|
81
|
+
{
|
|
82
|
+
tmpURL += '~';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
tmpURL += `${pFilterCommand}~${pFilterParameters[0]}~${pFilterParameters[1]}~${pFilterParameters[2]}`;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
let tmpfTranslateOperator = (pOperator) =>
|
|
89
|
+
{
|
|
90
|
+
tmpNewOperator = 'EQ';
|
|
91
|
+
switch(pOperator.toUpperCase())
|
|
92
|
+
{
|
|
93
|
+
case '!=':
|
|
94
|
+
tmpNewOperator = 'NE';
|
|
95
|
+
break;
|
|
96
|
+
case '>':
|
|
97
|
+
tmpNewOperator = 'GT';
|
|
98
|
+
break;
|
|
99
|
+
case '>=':
|
|
100
|
+
tmpNewOperator = 'GE';
|
|
101
|
+
break;
|
|
102
|
+
case '<=':
|
|
103
|
+
tmpNewOperator = 'LE';
|
|
104
|
+
break;
|
|
105
|
+
case '<':
|
|
106
|
+
tmpNewOperator = 'LT';
|
|
107
|
+
break;
|
|
108
|
+
case 'LIKE':
|
|
109
|
+
tmpNewOperator = 'LK';
|
|
110
|
+
break;
|
|
111
|
+
case 'IN':
|
|
112
|
+
tmpNewOperator = 'INN';
|
|
113
|
+
break;
|
|
114
|
+
case 'NOT IN':
|
|
115
|
+
tmpNewOperator = 'NI';
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
return tmpNewOperator;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Translating Delete Tracking bit on query to a query with automagic
|
|
122
|
+
// This will eventually deprecate this as part of the necessary query
|
|
123
|
+
if (pParameters.query.disableDeleteTracking)
|
|
124
|
+
{
|
|
125
|
+
tmpfAddFilter('FBV',['Deleted','GE','0'])
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
for (var i = 0; i < tmpFilter.length; i++)
|
|
129
|
+
{
|
|
130
|
+
if (tmpFilter[i].Operator === '(')
|
|
131
|
+
{
|
|
132
|
+
tmpfAddFilter('FOP',['0','(','0']);
|
|
133
|
+
}
|
|
134
|
+
else if (tmpFilter[i].Operator === ')')
|
|
135
|
+
{
|
|
136
|
+
// Close a logical grouping
|
|
137
|
+
tmpfAddFilter('FCP',['0',')','0']);
|
|
138
|
+
}
|
|
139
|
+
else if (tmpFilter[i].Operator === 'IN' || tmpFilter[i].Operator === "NOT IN")
|
|
140
|
+
{
|
|
141
|
+
let tmpFilterCommand = 'FBV';
|
|
142
|
+
if (tmpFilter[i].Connector == 'OR')
|
|
143
|
+
{
|
|
144
|
+
tmpFilterCommand = 'FBVOR';
|
|
145
|
+
}
|
|
146
|
+
// Add the column name, operator and parameter name to the list of where value parenthetical
|
|
147
|
+
tmpfAddFilter(tmpFilterCommand, [tmpFilter[i].Column, tmpfTranslateOperator(tmpFilter[i].Operator), tmpFilter[i].Value.map(encodeURIComponent).join(',')])
|
|
148
|
+
}
|
|
149
|
+
else if (tmpFilter[i].Operator === 'IS NULL')
|
|
150
|
+
{
|
|
151
|
+
// IS NULL is a special operator which doesn't require a value, or parameter
|
|
152
|
+
tmpfAddFilter('FBV', [tmpFilter[i].Column, 'IN', '0']);
|
|
153
|
+
}
|
|
154
|
+
else if (tmpFilter[i].Operator === 'IS NOT NULL')
|
|
155
|
+
{
|
|
156
|
+
// IS NOT NULL is a special operator which doesn't require a value, or parameter
|
|
157
|
+
tmpfAddFilter('FBV', [tmpFilter[i].Column, 'NN', '0']);
|
|
158
|
+
}
|
|
159
|
+
else
|
|
160
|
+
{
|
|
161
|
+
let tmpFilterCommand = 'FBV';
|
|
162
|
+
if (tmpFilter[i].Connector == 'OR')
|
|
163
|
+
{
|
|
164
|
+
tmpFilterCommand = 'FBVOR';
|
|
165
|
+
}
|
|
166
|
+
// Add the column name, operator and parameter name to the list of where value parenthetical
|
|
167
|
+
tmpfAddFilter(tmpFilterCommand, [tmpFilter[i].Column, tmpfTranslateOperator(tmpFilter[i].Operator), encodeURIComponent(tmpFilter[i].Value)]);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
let tmpOrderBy = generateOrderBy(pParameters);
|
|
172
|
+
if (tmpOrderBy)
|
|
173
|
+
{
|
|
174
|
+
if (tmpURL)
|
|
175
|
+
{
|
|
176
|
+
tmpURL += '~';
|
|
177
|
+
}
|
|
178
|
+
tmpURL += tmpOrderBy;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return tmpURL;
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Get the flags for the request
|
|
186
|
+
*
|
|
187
|
+
* These are usually passed in for Update and Create when extra tracking is disabled.
|
|
188
|
+
*
|
|
189
|
+
* @method: generateFlags
|
|
190
|
+
* @param: {Object} pParameters SQL Query Parameters
|
|
191
|
+
* @return: {String} Flags to be sent, if any.
|
|
192
|
+
*/
|
|
193
|
+
function generateFlags(pParameters)
|
|
194
|
+
{
|
|
195
|
+
let tmpDisableAutoDateStamp = pParameters.query.disableAutoDateStamp;
|
|
196
|
+
let tmpDisableDeleteTracking = pParameters.query.disableDeleteTracking;
|
|
197
|
+
let tmpDisableAutoIdentity = pParameters.query.disableAutoIdentity;
|
|
198
|
+
let tmpDisableAutoUserStamp = pParameters.query.disableAutoUserStamp;
|
|
199
|
+
|
|
200
|
+
let tmpFlags = '';
|
|
201
|
+
|
|
202
|
+
let fAddFlag = (pFlagSet, pFlag) =>
|
|
203
|
+
{
|
|
204
|
+
if (pFlagSet)
|
|
205
|
+
{
|
|
206
|
+
if (tmpFlags.length > 0)
|
|
207
|
+
{
|
|
208
|
+
tmpFlags += ',';
|
|
209
|
+
}
|
|
210
|
+
tmpFlags += pFlag;
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
fAddFlag(tmpDisableAutoDateStamp, 'DisableAutoDateStamp');
|
|
215
|
+
fAddFlag(tmpDisableDeleteTracking, 'DisableDeleteTracking');
|
|
216
|
+
fAddFlag(tmpDisableAutoIdentity, 'DisableAutoIdentity');
|
|
217
|
+
fAddFlag(tmpDisableAutoUserStamp, 'DisableAutoUserStamp');
|
|
218
|
+
|
|
219
|
+
return tmpFlags;
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Get the ID for the record, to be used in URIs
|
|
224
|
+
*
|
|
225
|
+
* @method: getIDRecord
|
|
226
|
+
* @param: {Object} pParameters SQL Query Parameters
|
|
227
|
+
* @return: {String} ID of the record in string form for the URI
|
|
228
|
+
*/
|
|
229
|
+
var getIDRecord = function(pParameters)
|
|
230
|
+
{
|
|
231
|
+
var tmpFilter = Array.isArray(pParameters.filter) ? pParameters.filter : [];
|
|
232
|
+
|
|
233
|
+
var tmpIDRecord = false;
|
|
234
|
+
|
|
235
|
+
if (tmpFilter.length < 1)
|
|
236
|
+
{
|
|
237
|
+
return tmpIDRecord;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
for (var i = 0; i < tmpFilter.length; i++)
|
|
241
|
+
{
|
|
242
|
+
// Check Schema Entry Type
|
|
243
|
+
var tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];
|
|
244
|
+
var tmpSchemaEntry = {Column:tmpFilter[i].Column, Type:'Default'};
|
|
245
|
+
for (var j = 0; j < tmpSchema.length; j++)
|
|
246
|
+
{
|
|
247
|
+
// If this column is the AutoIdentity, set it.
|
|
248
|
+
if ((tmpFilter[i].Column == tmpSchema[j].Column) &&
|
|
249
|
+
(tmpSchema[j].Type == 'AutoIdentity'))
|
|
250
|
+
{
|
|
251
|
+
tmpIDRecord = tmpFilter[i].Value;
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return tmpIDRecord;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Generate an ORDER BY clause from the sort array
|
|
262
|
+
*
|
|
263
|
+
* Each entry in the sort is an object like:
|
|
264
|
+
* {Column:'Color',Direction:'Descending'}
|
|
265
|
+
*
|
|
266
|
+
* @method: generateOrderBy
|
|
267
|
+
* @param: {Object} pParameters SQL Query Parameters
|
|
268
|
+
* @return: {String} Returns the field list clause
|
|
269
|
+
*/
|
|
270
|
+
var generateOrderBy = function(pParameters)
|
|
271
|
+
{
|
|
272
|
+
var tmpOrderBy = pParameters.sort;
|
|
273
|
+
var tmpOrderClause = false;
|
|
274
|
+
|
|
275
|
+
if (!Array.isArray(tmpOrderBy) || tmpOrderBy.length < 1)
|
|
276
|
+
{
|
|
277
|
+
return tmpOrderClause;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
tmpOrderClause = '';
|
|
281
|
+
|
|
282
|
+
for (var i = 0; i < tmpOrderBy.length; i++)
|
|
283
|
+
{
|
|
284
|
+
if (i > 0)
|
|
285
|
+
{
|
|
286
|
+
tmpOrderClause += '~';
|
|
287
|
+
}
|
|
288
|
+
tmpOrderClause += `FSF~${tmpOrderBy[i].Column}~`;
|
|
289
|
+
|
|
290
|
+
if (tmpOrderBy[i].Direction == 'Descending')
|
|
291
|
+
{
|
|
292
|
+
tmpOrderClause += 'DESC~0';
|
|
293
|
+
}
|
|
294
|
+
else
|
|
295
|
+
{
|
|
296
|
+
tmpOrderClause += 'ASC~0'
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return tmpOrderClause;
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Generate the limit clause
|
|
304
|
+
*
|
|
305
|
+
* @method: generateLimit
|
|
306
|
+
* @param: {Object} pParameters SQL Query Parameters
|
|
307
|
+
* @return: {String} Returns the table name clause
|
|
308
|
+
*/
|
|
309
|
+
var generateLimit = function(pParameters)
|
|
310
|
+
{
|
|
311
|
+
if (!pParameters.cap)
|
|
312
|
+
{
|
|
313
|
+
return '';
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
let tmpBegin = (pParameters.begin !== false) ? pParameters.begin : 0;
|
|
317
|
+
|
|
318
|
+
return `${tmpBegin}/${pParameters.cap}`;
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
var Create = function(pParameters)
|
|
322
|
+
{
|
|
323
|
+
var tmpTableName = generateTableName(pParameters);
|
|
324
|
+
var tmpFlags = generateFlags(pParameters);
|
|
325
|
+
|
|
326
|
+
if (tmpTableName)
|
|
327
|
+
{
|
|
328
|
+
let tmpURL = tmpTableName;
|
|
329
|
+
if (tmpFlags)
|
|
330
|
+
{
|
|
331
|
+
tmpURL = `${tmpURL}/WithFlags/${tmpFlags}`
|
|
332
|
+
}
|
|
333
|
+
return tmpURL;
|
|
334
|
+
}
|
|
335
|
+
else
|
|
336
|
+
{
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Read one or many records
|
|
344
|
+
*
|
|
345
|
+
* @method Read
|
|
346
|
+
* @param {Object} pParameters SQL Query parameters
|
|
347
|
+
* @return {String} Returns the current Query for chaining.
|
|
348
|
+
*/
|
|
349
|
+
var Read = function(pParameters)
|
|
350
|
+
{
|
|
351
|
+
var tmpTableName = generateTableName(pParameters);
|
|
352
|
+
var tmpFieldList = generateFieldList(pParameters);
|
|
353
|
+
var tmpWhere = generateWhere(pParameters);
|
|
354
|
+
var tmpLimit = generateLimit(pParameters);
|
|
355
|
+
|
|
356
|
+
var tmpURL = `${tmpTableName}s`;
|
|
357
|
+
if (tmpFieldList)
|
|
358
|
+
{
|
|
359
|
+
tmpURL = `${tmpURL}/LiteExtended/${tmpFieldList}`
|
|
360
|
+
}
|
|
361
|
+
if (tmpWhere)
|
|
362
|
+
{
|
|
363
|
+
tmpURL = `${tmpURL}/FilteredTo/${tmpWhere}`;
|
|
364
|
+
}
|
|
365
|
+
if (tmpLimit)
|
|
366
|
+
{
|
|
367
|
+
tmpURL = `${tmpURL}/${tmpLimit}`;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
return tmpURL;
|
|
371
|
+
///'SELECT'+tmpFieldList+' FROM'+tmpTableName+tmpJoin+tmpWhere+tmpOrderBy+tmpLimit+';';
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
var Update = function(pParameters)
|
|
375
|
+
{
|
|
376
|
+
var tmpTableName = generateTableName(pParameters);
|
|
377
|
+
var tmpFlags = generateFlags(pParameters);
|
|
378
|
+
|
|
379
|
+
if (tmpTableName)
|
|
380
|
+
{
|
|
381
|
+
let tmpURL = tmpTableName;
|
|
382
|
+
if (tmpFlags)
|
|
383
|
+
{
|
|
384
|
+
tmpURL = `${tmpURL}/WithFlags/${tmpFlags}`
|
|
385
|
+
}
|
|
386
|
+
return tmpURL;
|
|
387
|
+
}
|
|
388
|
+
else
|
|
389
|
+
{
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
var Delete = function(pParameters)
|
|
395
|
+
{
|
|
396
|
+
var tmpTableName = generateTableName(pParameters);
|
|
397
|
+
var tmpIDRecord = getIDRecord(pParameters);
|
|
398
|
+
|
|
399
|
+
if (!tmpIDRecord)
|
|
400
|
+
{
|
|
401
|
+
return false;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return `${tmpTableName}/${tmpIDRecord}`;
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
var Count = function(pParameters)
|
|
408
|
+
{
|
|
409
|
+
var tmpTableName = generateTableName(pParameters);
|
|
410
|
+
var tmpWhere = generateWhere(pParameters);
|
|
411
|
+
|
|
412
|
+
let tmpCountQuery = `${tmpTableName}s/Count`;
|
|
413
|
+
|
|
414
|
+
if (tmpWhere)
|
|
415
|
+
{
|
|
416
|
+
return `${tmpCountQuery}s/Count/FilteredTo/${tmpWhere}`;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
return tmpCountQuery;
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
var tmpDialect = ({
|
|
423
|
+
Create: Create,
|
|
424
|
+
Read: Read,
|
|
425
|
+
Update: Update,
|
|
426
|
+
Delete: Delete,
|
|
427
|
+
Count: Count
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Dialect Name
|
|
432
|
+
*
|
|
433
|
+
* @property name
|
|
434
|
+
* @type string
|
|
435
|
+
*/
|
|
436
|
+
Object.defineProperty(tmpDialect, 'name',
|
|
437
|
+
{
|
|
438
|
+
get: function() { return 'MeadowEndpoints'; },
|
|
439
|
+
enumerable: true
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
return tmpDialect;
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
module.exports = new FoxHoundDialectMeadowEndpoints();
|