foxhound 2.0.2 → 2.0.4
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/dist/foxhound.min.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["node_modules/browser-pack/_prelude.js","source/Foxhound-Browser-Shim.js","foxhound.min.js","source/Foxhound-Dialects.js","source/Foxhound.js","source/Parameters.js","source/dialects/ALASQL/FoxHound-Dialect-ALASQL.js","source/dialects/English/FoxHound-Dialect-English.js","source/dialects/MeadowEndpoints/FoxHound-Dialect-MeadowEndpoints.js","source/dialects/MySQL/FoxHound-Dialect-MySQL.js"],"names":["f","exports","module","define","amd","window","global","self","this","Foxhound","r","e","n","t","o","i","c","require","u","a","Error","code","p","call","length","libNPMModuleWrapper","hasOwnProperty","getDialects","tmpDialects","ALASQL","English","MeadowEndpoints","MySQL","default","baseParameters","createNew","pFable","pFromParameters","new","_Fable","_DefaultParameters","_Parameters","_Dialects","_UUID","getUUID","_LogLevel","_Dialect","resetParameters","Utility","extend","query","disableAutoIdentity","disableAutoDateStamp","disableAutoUserStamp","disableDeleteTracking","body","schema","IDUser","UUID","records","parameters","result","executed","value","error","addJoin","pTable","pFrom","pTo","pType","log","warn","queryUUID","indexOf","invalidField","tmpJoin","Type","Table","From","To","Array","isArray","join","push","info","setDialect","pDialectName","invalidDialect","checkDialect","tmpNewFoxHoundObject","mergeParameters","setLogLevel","pLogLevel","tmpLogLevel","setScope","pScope","tmpScope","invalidScope","scope","setDistinct","pDistinct","distinct","setIDUser","pIDUser","tmpUserID","invalidIDUser","userID","setDataElements","pDataElements","tmpDataElements","dataElements","setBegin","pBeginAmount","tmpBegin","invalidBeginAmount","begin","setCap","pCapAmount","tmpCapAmount","invalidCapAmount","cap","setFilter","pFilter","tmpFilter","filter","addFilter","pColumn","pValue","pOperator","pConnector","pParameter","invalidColumn","tmpParameter","Column","Operator","Value","Connector","Parameter","replace","newFilter","setSort","pSort","tmpSort","Direction","sort","addSort","setJoin","pJoin","forEach","addRecord","pRecord","newRecord","setDisableAutoIdentity","pFlag","setDisableAutoDateStamp","setDisableAutoUserStamp","setDisableDeleteTracking","buildCreateQuery","Create","buildReadQuery","Read","buildUpdateQuery","Update","buildDeleteQuery","Delete","buildUndeleteQuery","Undelete","buildCountQuery","Count","clone","tmpFoxHound","slice","Object","defineProperty","get","set","pQuery","enumerable","pResult","pParameters","queryOverride","generateTableName","escapeColumn","tmpTableName","generateFieldList","pIsForCountClause","tmpSchema","idColumn","find","entry","tmpFieldList","generateWhere","trim","tmpSchemaEntry","tmpHasDeletedParameter","x","tmpWhere","tmpLastOperatorNoConnector","tmpColumnParameter","tmpDialect","tmpCreateSetList","tmpRecords","tmpCreateSet","tmpColumn","generateCreateSetList","tmpCreateSetValues","tmpCurrentColumn","buildDefaultDefinition","generateCreateSetValues","tmpOrderBy","tmpOrderClause","generateOrderBy","tmpLimit","generateLimit","tmpOptDistinct","template","tmpQueryTemplate","FieldList","TableName","Where","OrderBy","Limit","Distinct","_Params","pError","console","tmpUpdateSetters","tmpUpdate","tmpColumnDefaultParameter","generateUpdateSetters","tmpUpdateDeleteSetters","tmpHasDeletedField","tmpUpdateSql","generateUpdateDeleteSetters","tmpDeleteTrackingState","tmpUpdateUndeleteSetters","generateUpdateUndeleteSetters","tmpURL","tmpfAddFilter","pFilterCommand","pFilterParameters","tmpfTranslateOperator","tmpNewOperator","toUpperCase","tmpFilterCommand","map","encodeURIComponent","generateFlags","tmpDisableAutoDateStamp","tmpDisableDeleteTracking","tmpDisableAutoIdentity","tmpDisableAutoUserStamp","tmpFlags","fAddFlag","pFlagSet","generateIdentityColumnName","tmpIDRecord","j","getIDRecord","SQL_NOW","qualifiedIDColumn","generateSafeFieldName","SURROUNDING_QUOTES_AND_WHITESPACE_REGEX","cleanseQuoting","str","pFieldName","pFieldNames","split","cleansedFieldName","generateJoins","tmpJoins","tmpJoinClause","Join"],"mappings":"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","file":"foxhound.min.js","sourcesContent":["(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()","/**\n* Simple browser shim loader - assign the npm module to a window global automatically\n*\n* @license MIT\n* @author <steven@velozo.com>\n*/\nvar libNPMModuleWrapper = require('./Foxhound.js');\n\nif ((typeof(window) === 'object') && !window.hasOwnProperty('Foxhound'))\n{\n\twindow.Foxhound = libNPMModuleWrapper;\n}\n\nmodule.exports = libNPMModuleWrapper;","(function(f){if(typeof exports===\"object\"&&typeof module!==\"undefined\"){module.exports=f()}else if(typeof define===\"function\"&&define.amd){define([],f)}else{var g;if(typeof window!==\"undefined\"){g=window}else if(typeof global!==\"undefined\"){g=global}else if(typeof self!==\"undefined\"){g=self}else{g=this}g.Foxhound = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){\n/**\n* Simple browser shim loader - assign the npm module to a window global automatically\n*\n* @license MIT\n* @author <steven@velozo.com>\n*/\nvar libNPMModuleWrapper = require('./Foxhound.js');\n\nif ((typeof(window) === 'object') && !window.hasOwnProperty('Foxhound'))\n{\n\twindow.Foxhound = libNPMModuleWrapper;\n}\n\nmodule.exports = libNPMModuleWrapper;\n},{\"./Foxhound.js\":3}],2:[function(require,module,exports){\ngetDialects = () =>\n{\n\tlet tmpDialects = {};\n\n\ttmpDialects.ALASQL = require('./dialects/ALASQL/FoxHound-Dialect-ALASQL.js');\n\ttmpDialects.English = require('./dialects/English/FoxHound-Dialect-English.js');\n\ttmpDialects.MeadowEndpoints = require('./dialects/MeadowEndpoints/FoxHound-Dialect-MeadowEndpoints.js');\n\ttmpDialects.MySQL = require('./dialects/MySQL/FoxHound-Dialect-MySQL.js');\n\n\ttmpDialects.default = tmpDialects.English;\n\n\treturn tmpDialects;\n}\n\nmodule.exports = getDialects();\n},{\"./dialects/ALASQL/FoxHound-Dialect-ALASQL.js\":5,\"./dialects/English/FoxHound-Dialect-English.js\":6,\"./dialects/MeadowEndpoints/FoxHound-Dialect-MeadowEndpoints.js\":7,\"./dialects/MySQL/FoxHound-Dialect-MySQL.js\":8}],3:[function(require,module,exports){\n/**\n* FoxHound Query Generation Library\n* @license MIT\n* @author Steven Velozo <steven@velozo.com>\n*/\n\n// Load our base parameters skeleton object\nconst baseParameters = require('./Parameters.js');\n\nvar FoxHound = function()\n{\n\tfunction createNew(pFable, pFromParameters)\n\t{\n\t\t// If a valid Fable object isn't passed in, return a constructor\n\t\tif ((typeof(pFable) !== 'object') || !('fable' in pFable))\n\t\t{\n\t\t\treturn {new: createNew};\n\t\t}\n\n\t\tvar _Fable = pFable;\n\n\t\t// The default parameters config object, used as a template for all new\n\t\t// queries created from this query.\n\t\tvar _DefaultParameters = (typeof(pFromParameters) === 'undefined') ? {} : pFromParameters;\n\n\t\t// The parameters config object for the current query. This is the only\n\t\t// piece of internal state that is important to operation.\n\t\tvar _Parameters = false;\n\n\t\tvar _Dialects = require('./Foxhound-Dialects.js');\n\n\t\t// The unique identifier for a query\n\t\tvar _UUID = _Fable.getUUID();\n\n\t\t// The log level, for debugging chattiness.\n\t\tvar _LogLevel = 0;\n\n\t\t// The dialect to use when generating queries\n\t\tvar _Dialect = false;\n\n\t\t/**\n\t\t* Clone the current FoxHound Query into a new Query object, copying all\n\t\t* parameters as the new default. Clone also copies the log level.\n\t\t*\n\t\t* @method clone\n\t\t* @return {Object} Returns a cloned Query. This is still chainable.\n\t\t*/\n\t\tvar clone = function()\n\t\t{\n\t\t\tvar tmpFoxHound = createNew(_Fable, baseParameters)\n\t\t\t\t.setScope(_Parameters.scope)\n\t\t\t\t.setBegin(_Parameters.begin)\n\t\t\t\t.setCap(_Parameters.cap);\n\n\t\t\t// Schema is the only part of a query that carries forward.\n\t\t\ttmpFoxHound.query.schema = _Parameters.query.schema;\n\n\t\t\tif (_Parameters.dataElements)\n\t\t\t{\n\t\t\t\ttmpFoxHound.parameters.dataElements = _Parameters.dataElements.slice(); // Copy the array of dataElements\n\t\t\t}\n\t\t\tif (_Parameters.sort)\n\t\t\t{\n\t\t\t\ttmpFoxHound.parameters.sort = _Parameters.sort.slice(); // Copy the sort array.\n\t\t\t\t// TODO: Fix the side affect nature of these being objects in the array .. they are technically clones of the previous.\n\t\t\t}\n\t\t\tif (_Parameters.filter)\n\t\t\t{\n\t\t\t\ttmpFoxHound.parameters.filter = _Parameters.filter.slice(); // Copy the filter array.\n\t\t\t\t// TODO: Fix the side affect nature of these being objects in the array .. they are technically clones of the previous.\n\t\t\t}\n\n\t\t\treturn tmpFoxHound;\n\t\t};\n\n\n\t\t/**\n\t\t* Reset the parameters of the FoxHound Query to the Default. Default\n\t\t* parameters were set during object construction.\n\t\t*\n\t\t* @method resetParameters\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar resetParameters = function()\n\t\t{\n\t\t\t_Parameters = _Fable.Utility.extend({}, baseParameters, _DefaultParameters);\n\t\t\t_Parameters.query = ({\n\t\t\t\tdisableAutoIdentity: false,\n\t\t\t\tdisableAutoDateStamp: false,\n\t\t\t\tdisableAutoUserStamp: false,\n\t\t\t\tdisableDeleteTracking: false,\n\t\t\t\tbody: false,\n\t\t\t\tschema: false, // The schema to intersect with our records\n\t\t\t\tIDUser: 0, // The user to stamp into records\n\t\t\t\tUUID: _Fable.getUUID(), // A UUID for this record\n\t\t\t\trecords: false, // The records to be created or changed\n\t\t\t\tparameters: {}\n\t\t\t});\n\n\t\t\t_Parameters.result = ({\n\t\t\t\texecuted: false, // True once we've run a query.\n\t\t\t\tvalue: false, // The return value of the last query run\n\t\t\t\terror: false // The error message of the last run query\n\t\t\t});\n\n\t\t\treturn this;\n\t\t};\n\t\tresetParameters();\n\n\t\t/**\n\t\t* Reset the parameters of the FoxHound Query to the Default. Default\n\t\t* parameters were set during object construction.\n\t\t*\n\t\t* @method mergeParameters\n\t\t* @param {Object} pFromParameters A Parameters Object to merge from\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar mergeParameters = function(pFromParameters)\n\t\t{\n\t\t\t_Parameters = _Fable.Utility.extend({}, _Parameters, pFromParameters);\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the the Logging level.\n\t\t*\n\t\t* The log levels are:\n\t\t* 0 - Don't log anything\n\t\t* 1 - Log queries\n\t\t* 2 - Log queries and non-parameterized queries\n\t\t* 3 - Log everything\n\t\t*\n\t\t* @method setLogLevel\n\t\t* @param {Number} pLogLevel The log level for our object\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setLogLevel = function(pLogLevel)\n\t\t{\n\t\t\tvar tmpLogLevel = 0;\n\n\t\t\tif (typeof(pLogLevel) === 'number' && (pLogLevel % 1) === 0)\n\t\t\t{\n\t\t\t\ttmpLogLevel = pLogLevel;\n\t\t\t}\n\n\t\t\t_LogLevel = tmpLogLevel;\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the Scope for the Query. *Scope* is the source for the data being\n\t\t* pulled. In TSQL this would be the _table_, whereas in MongoDB this\n\t\t* would be the _collection_.\n\t\t*\n\t\t* A scope can be either a string, or an array (for JOINs and such).\n\t\t*\n\t\t* @method setScope\n\t\t* @param {String} pScope A Scope for the Query.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setScope = function(pScope)\n\t\t{\n\t\t\tvar tmpScope = false;\n\n\t\t\tif (typeof(pScope) === 'string')\n\t\t\t{\n\t\t\t\ttmpScope = pScope;\n\t\t\t}\n\t\t\telse if (pScope !== false)\n\t\t\t{\n\t\t\t\t_Fable.log.error('Scope set failed. You must pass in a string or array.', {queryUUID:_UUID, parameters:_Parameters, invalidScope:pScope});\n\t\t\t}\n\n\t\t\t_Parameters.scope = tmpScope;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Scope set: '+tmpScope, {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\t\t/**\n\t\t* Set whether the query returns DISTINCT results.\n\t\t* For count queries, returns the distinct for the selected fields, or all fields in the base table by default.\n\t\t*\n\t\t* @method setDistinct\n\t\t* @param {Boolean} pDistinct True if the query should be distinct.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setDistinct = function(pDistinct)\n\t\t{\n\t\t\t_Parameters.distinct = !!pDistinct;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Distinct set: '+_Parameters.distinct, {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the Data Elements for the Query. *Data Elements* are the fields\n\t\t* being pulled by the query. In TSQL this would be the _columns_,\n\t\t* whereas in MongoDB this would be the _fields_.\n\t\t*\n\t\t* The passed values can be either a string, or an array.\n\t\t*\n\t\t* @method setDataElements\n\t\t* @param {String} pDataElements The Data Element(s) for the Query.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setDataElements = function(pDataElements)\n\t\t{\n\t\t\tvar tmpDataElements = false;\n\n\t\t\tif (Array.isArray(pDataElements))\n\t\t\t{\n\t\t\t\t// TODO: Check each entry of the array are all strings\n\t\t\t\ttmpDataElements = pDataElements;\n\t\t\t}\n\t\t\tif (typeof(pDataElements) === 'string')\n\t\t\t{\n\t\t\t\ttmpDataElements = [pDataElements];\n\t\t\t}\n\n\t\t\t_Parameters.dataElements = tmpDataElements;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Data Elements set', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the sort data element\n\t\t*\n\t\t* The passed values can be either a string, an object or an array of objects.\n\t\t*\n\t\t* The Sort object has two values:\n\t\t* {Column:'Birthday', Direction:'Ascending'}\n\t\t*\n\t\t* @method setSort\n\t\t* @param {String} pSort The sort criteria(s) for the Query.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setSort = function(pSort)\n\t\t{\n\t\t\tvar tmpSort = false;\n\n\t\t\tif (Array.isArray(pSort))\n\t\t\t{\n\t\t\t\t// TODO: Check each entry of the array are all conformant sort objects\n\t\t\t\ttmpSort = pSort;\n\t\t\t}\n\t\t\telse if (typeof(pSort) === 'string')\n\t\t\t{\n\t\t\t\t// Default to ascending\n\t\t\t\ttmpSort = [{Column:pSort, Direction:'Ascending'}];\n\t\t\t}\n\t\t\telse if (typeof(pSort) === 'object')\n\t\t\t{\n\t\t\t\t// TODO: Check that this sort entry conforms to a sort entry\n\t\t\t\ttmpSort = [pSort];\n\t\t\t}\n\n\t\t\t_Parameters.sort = tmpSort;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Sort set', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\t\t/**\n\t\t* Set the join data element\n\t\t*\n\t\t* The passed values can be either an object or an array of objects.\n\t\t*\n\t\t* The join object has four values:\n\t\t* {Type:'INNER JOIN', Table:'Test', From:'Test.ID', To:'Scope.IDItem'}\n\t\t*\n\t\t* @method setJoin\n\t\t* @param {Object} pJoin The join criteria(s) for the Query.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setJoin = function(pJoin)\n\t\t{\n\t\t\t_Parameters.join = [];\n\n\t\t\tif (Array.isArray(pJoin))\n\t\t\t{\n\t\t\t\tpJoin.forEach(function(join)\n\t\t\t\t{\n\t\t\t\t\taddJoin(join.Table, join.From, join.To, join.Type);\n\t\t\t\t});\n\t\t\t}\n\t\t\telse if (typeof(pJoin) === 'object')\n\t\t\t{\n\t\t\t\taddJoin(pJoin.Table, pJoin.From, pJoin.To, pJoin.Type);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Add a sort data element\n\t\t*\n\t\t* The passed values can be either a string, an object or an array of objects.\n\t\t*\n\t\t* The Sort object has two values:\n\t\t* {Column:'Birthday', Direction:'Ascending'}\n\t\t*\n\t\t* @method setSort\n\t\t* @param {String} pSort The sort criteria to add to the Query.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar addSort = function(pSort)\n\t\t{\n\t\t\tvar tmpSort = false;\n\n\t\t\tif (typeof(pSort) === 'string')\n\t\t\t{\n\t\t\t\t// Default to ascending\n\t\t\t\ttmpSort = {Column:pSort, Direction:'Ascending'};\n\t\t\t}\n\t\t\tif (typeof(pSort) === 'object')\n\t\t\t{\n\t\t\t\t// TODO: Check that this sort entry conforms to a sort entry\n\t\t\t\ttmpSort = pSort;\n\t\t\t}\n\n\t\t\tif (!_Parameters.sort)\n\t\t\t{\n\t\t\t\t_Parameters.sort = [];\n\t\t\t}\n\n\t\t\t_Parameters.sort.push(tmpSort);\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Sort set', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the the Begin index for the Query. *Begin* is the index at which\n\t\t* a query should start returning rows. In TSQL this would be the n\n\t\t* parameter of ```LIMIT 1,n```, whereas in MongoDB this would be the\n\t\t* n in ```skip(n)```.\n\t\t*\n\t\t* The passed value must be an Integer >= 0.\n\t\t*\n\t\t* @method setBegin\n\t\t* @param {Number} pBeginAmount The index to begin returning Query data.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setBegin = function(pBeginAmount)\n\t\t{\n\t\t\tvar tmpBegin = false;\n\n\t\t\t// Test if it is an integer > -1\n\t\t\t// http://jsperf.com/numbers-and-integers\n\t\t\tif (typeof(pBeginAmount) === 'number' && (pBeginAmount % 1) === 0 && pBeginAmount >= 0)\n\t\t\t{\n\t\t\t\ttmpBegin = pBeginAmount;\n\t\t\t}\n\t\t\telse if (pBeginAmount !== false)\n\t\t\t{\n\t\t\t\t_Fable.log.error('Begin set failed; non-positive or non-numeric argument.', {queryUUID:_UUID, parameters:_Parameters, invalidBeginAmount:pBeginAmount});\n\t\t\t}\n\n\t\t\t_Parameters.begin = tmpBegin;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Begin set: '+pBeginAmount, {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the the Cap for the Query. *Cap* is the maximum number of records\n\t\t* a Query should return in a set. In TSQL this would be the n\n\t\t* parameter of ```LIMIT n```, whereas in MongoDB this would be the\n\t\t* n in ```limit(n)```.\n\t\t*\n\t\t* The passed value must be an Integer >= 0.\n\t\t*\n\t\t* @method setCap\n\t\t* @param {Number} pCapAmount The maximum records for the Query set.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setCap = function(pCapAmount)\n\t\t{\n\t\t\tvar tmpCapAmount = false;\n\n\t\t\tif (typeof(pCapAmount) === 'number' && (pCapAmount % 1) === 0 && pCapAmount >= 0)\n\t\t\t{\n\t\t\t\ttmpCapAmount = pCapAmount;\n\t\t\t}\n\t\t\telse if (pCapAmount !== false)\n\t\t\t{\n\t\t\t\t_Fable.log.error('Cap set failed; non-positive or non-numeric argument.', {queryUUID:_UUID, parameters:_Parameters, invalidCapAmount:pCapAmount});\n\t\t\t}\n\n\n\t\t\t_Parameters.cap = tmpCapAmount;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Cap set to: '+tmpCapAmount, {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the filter expression\n\t\t*\n\t\t* The passed values can be either an object or an array of objects.\n\t\t*\n\t\t* The Filter object has a minimum of two values (which expands to the following):\n\t\t* {Column:'Name', Value:'John'}\n\t\t* {Column:'Name', Operator:'EQ', Value:'John', Connector:'And', Parameter:'Name'}\n\t\t*\n\t\t* @method setFilter\n\t\t* @param {String} pFilter The filter(s) for the Query.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setFilter = function(pFilter)\n\t\t{\n\t\t\tvar tmpFilter = false;\n\n\t\t\tif (Array.isArray(pFilter))\n\t\t\t{\n\t\t\t\t// TODO: Check each entry of the array are all conformant Filter objects\n\t\t\t\ttmpFilter = pFilter;\n\t\t\t}\n\t\t\telse if (typeof(pFilter) === 'object')\n\t\t\t{\n\t\t\t\t// TODO: Check that this Filter entry conforms to a Filter entry\n\t\t\t\ttmpFilter = [pFilter];\n\t\t\t}\n\n\t\t\t_Parameters.filter = tmpFilter;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Filter set', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\n\t\t/**\n\t\t* Add a filter expression\n\t\t*\n\t\t* {Column:'Name', Operator:'EQ', Value:'John', Connector:'And', Parameter:'Name'}\n\t\t*\n\t\t* @method addFilter\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar addFilter = function(pColumn, pValue, pOperator, pConnector, pParameter)\n\t\t{\n\t\t\tif (typeof(pColumn) !== 'string')\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid query filter column', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tif (typeof(pValue) === 'undefined')\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid query filter value', {queryUUID:_UUID, parameters:_Parameters, invalidColumn:pColumn});\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tvar tmpOperator = (typeof(pOperator) === 'undefined') ? '=' : pOperator;\n\t\t\tvar tmpConnector = (typeof(pConnector) === 'undefined') ? 'AND' : pConnector;\n\t\t\tvar tmpParameter = (typeof(pParameter) === 'undefined') ? pColumn : pParameter;\n\n\t\t\t//support table.field notation (mysql2 requires this)\n\t\t\ttmpParameter = tmpParameter.replace('.', '_');\n\n\t\t\tvar tmpFilter = (\n\t\t\t\t{\n\t\t\t\t\tColumn: pColumn,\n\t\t\t\t\tOperator: tmpOperator,\n\t\t\t\t\tValue: pValue,\n\t\t\t\t\tConnector: tmpConnector,\n\t\t\t\t\tParameter: tmpParameter\n\t\t\t\t});\n\n\t\t\tif (!Array.isArray(_Parameters.filter))\n\t\t\t{\n\t\t\t\t_Parameters.filter = [tmpFilter];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_Parameters.filter.push(tmpFilter);\n\t\t\t}\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Added a filter', {queryUUID:_UUID, parameters:_Parameters, newFilter:tmpFilter});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\t\t/**\n\t\t* Add a join expression\n\t\t*\n\t\t* {Type:'INNER JOIN', Table:'Test', From:'Test.ID', To:'Scope.IDItem'}\n\t\t*\n\t\t* @method addJoin\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar addJoin = function(pTable, pFrom, pTo, pType)\n\t\t{\n\t\t\tif (typeof(pTable) !== 'string')\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid query join table', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tif (typeof(pFrom) === 'undefined' || typeof(pTo) === 'undefined')\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid query join field', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\t//sanity check the join fields\n\t\t\tif (pFrom.indexOf(pTable)!=0)\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid query join field, join must come FROM the join table!', {queryUUID:_UUID, parameters:_Parameters, invalidField:pFrom});\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tif (pTo.indexOf('.')<=0)\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid query join field, join must go TO a field on another table ([table].[field])!', {queryUUID:_UUID, parameters:_Parameters, invalidField:pTo});\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tvar tmpType = (typeof(pType) === 'undefined') ? 'INNER JOIN' : pType;\n\n\t\t\tvar tmpJoin = (\n\t\t\t\t{\n\t\t\t\t\tType: tmpType,\n\t\t\t\t\tTable: pTable,\n\t\t\t\t\tFrom: pFrom,\n\t\t\t\t\tTo: pTo\n\t\t\t\t});\n\n\t\t\tif (!Array.isArray(_Parameters.join))\n\t\t\t{\n\t\t\t\t_Parameters.join = [tmpJoin];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_Parameters.join.push(tmpJoin);\n\t\t\t}\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Added a join', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\n\t\t/**\n\t\t* Add a record (for UPDATE and INSERT)\n\t\t*\n\t\t*\n\t\t* @method addRecord\n\t\t* @param {Object} pRecord The record to add.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar addRecord = function(pRecord)\n\t\t{\n\t\t\tif (typeof(pRecord) !== 'object')\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid record to the query -- records must be an object', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tif (!Array.isArray(_Parameters.query.records))\n\t\t\t{\n\t\t\t\t_Parameters.query.records = [pRecord];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_Parameters.query.records.push(pRecord);\n\t\t\t}\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Added a record to the query', {queryUUID:_UUID, parameters:_Parameters, newRecord:pRecord});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\n\t\t/**\n\t\t* Set the Dialect for Query generation.\n\t\t*\n\t\t* This function expects a string, case sensitive, which matches both the\n\t\t* folder and filename\n\t\t*\n\t\t* @method setDialect\n\t\t* @param {String} pDialectName The dialect for query generation.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setDialect = function(pDialectName)\n\t\t{\n\n\t\t\tif (typeof(pDialectName) !== 'string')\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Dialect set to English - invalid name', {queryUUID:_UUID, parameters:_Parameters, invalidDialect:pDialectName});\n\t\t\t\treturn setDialect('English');\n\t\t\t}\n\n\t\t\tif (_Dialects.hasOwnProperty(pDialectName))\n\t\t\t{\n\t\t\t\t_Dialect = _Dialects[pDialectName](_Fable);\n\t\t\t\tif (_LogLevel > 2)\n\t\t\t\t{\n\t\t\t\t\t_Fable.log.info('Dialog set to: '+pDialectName, {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_Fable.log.error('Dialect not set - unknown dialect \"'+pDialectName+\"'\", {queryUUID:_UUID, parameters:_Parameters, invalidDialect:pDialectName});\n\t\t\t\tsetDialect('English');\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\t\t/**\n\t\t* User to use for this query\n\t\t*\n\t\t* @method setIDUser\n\t\t*/\n\t\tvar setIDUser = function(pIDUser)\n\t\t{\n\n\t\t\tvar tmpUserID = 0;\n\n\t\t\tif (typeof(pIDUser) === 'number' && (pIDUser % 1) === 0 && pIDUser >= 0)\n\t\t\t{\n\t\t\t\ttmpUserID = pIDUser;\n\t\t\t}\n\t\t\telse if (pIDUser !== false)\n\t\t\t{\n\t\t\t\t_Fable.log.error('User set failed; non-positive or non-numeric argument.', {queryUUID:_UUID, parameters:_Parameters, invalidIDUser:pIDUser});\n\t\t\t}\n\n\n\t\t\t_Parameters.userID = tmpUserID;\n\t\t\t_Parameters.query.IDUser = tmpUserID;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('IDUser set to: '+tmpUserID, {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\t\t/**\n\t\t* Flag to disable auto identity\n\t\t*\n\t\t* @method setDisableAutoIdentity\n\t\t*/\n\t\tvar setDisableAutoIdentity = function(pFlag)\n\t\t{\n\t\t\t_Parameters.query.disableAutoIdentity = pFlag;\n\n\t\t\treturn this; //chainable\n\t\t};\n\n\t\t/**\n\t\t* Flag to disable auto datestamp\n\t\t*\n\t\t* @method setDisableAutoDateStamp\n\t\t*/\n\t\tvar setDisableAutoDateStamp = function(pFlag)\n\t\t{\n\t\t\t_Parameters.query.disableAutoDateStamp = pFlag;\n\n\t\t\treturn this; //chainable\n\t\t};\n\n\t\t/**\n\t\t* Flag to disable auto userstamp\n\t\t*\n\t\t* @method setDisableAutoUserStamp\n\t\t*/\n\t\tvar setDisableAutoUserStamp = function(pFlag)\n\t\t{\n\t\t\t_Parameters.query.disableAutoUserStamp = pFlag;\n\n\t\t\treturn this; //chainable\n\t\t};\n\n\t\t/**\n\t\t* Flag to disable delete tracking\n\t\t*\n\t\t* @method setDisableDeleteTracking\n\t\t*/\n\t\tvar setDisableDeleteTracking = function(pFlag)\n\t\t{\n\t\t\t_Parameters.query.disableDeleteTracking = pFlag;\n\n\t\t\treturn this; //chainable\n\t\t};\n\n\t\t/**\n\t\t* Check that a valid Dialect has been set\n\t\t*\n\t\t* If there has not been a dialect set, it defaults to English.\n\t\t* TODO: Have the json configuration define a \"default\" dialect.\n\t\t*\n\t\t* @method checkDialect\n\t\t*/\n\t\tvar checkDialect = function()\n\t\t{\n\t\t\tif (_Dialect === false)\n\t\t\t{\n\t\t\t\tsetDialect('English');\n\t\t\t}\n\t\t};\n\n\n\t\tvar buildCreateQuery = function()\n\t\t{\n\t\t\tcheckDialect();\n\t\t\t_Parameters.query.body = _Dialect.Create(_Parameters);\n\t\t\treturn this;\n\t\t};\n\n\t\tvar buildReadQuery = function()\n\t\t{\n\t\t\tcheckDialect();\n\t\t\t_Parameters.query.body = _Dialect.Read(_Parameters);\n\t\t\treturn this;\n\t\t};\n\n\t\tvar buildUpdateQuery = function()\n\t\t{\n\t\t\tcheckDialect();\n\t\t\t_Parameters.query.body = _Dialect.Update(_Parameters);\n\t\t\treturn this;\n\t\t};\n\n\t\tvar buildDeleteQuery = function()\n\t\t{\n\t\t\tcheckDialect();\n\t\t\t_Parameters.query.body = _Dialect.Delete(_Parameters);\n\t\t\treturn this;\n\t\t};\n\n\t\tvar buildUndeleteQuery = function()\n\t\t{\n\t\t\tcheckDialect();\n\t\t\t_Parameters.query.body = _Dialect.Undelete(_Parameters);\n\t\t\treturn this;\n\t\t};\n\n\t\tvar buildCountQuery = function()\n\t\t{\n\t\t\tcheckDialect();\n\t\t\t_Parameters.query.body = _Dialect.Count(_Parameters);\n\t\t\treturn this;\n\t\t};\n\n\t\t/**\n\t\t* Container Object for our Factory Pattern\n\t\t*/\n\t\tvar tmpNewFoxHoundObject = (\n\t\t{\n\t\t\tresetParameters: resetParameters,\n\t\t\tmergeParameters: mergeParameters,\n\n\t\t\tsetLogLevel: setLogLevel,\n\n\t\t\tsetScope: setScope,\n\t\t\tsetDistinct: setDistinct,\n\t\t\tsetIDUser: setIDUser,\n\t\t\tsetDataElements: setDataElements,\n\t\t\tsetBegin: setBegin,\n\t\t\tsetCap: setCap,\n\t\t\tsetFilter: setFilter,\n\t\t\taddFilter: addFilter,\n\t\t\tsetSort: setSort,\n\t\t\taddSort: addSort,\n\t\t\tsetJoin: setJoin,\n\t\t\taddJoin: addJoin,\n\n\t\t\taddRecord: addRecord,\n\t\t\tsetDisableAutoIdentity: setDisableAutoIdentity,\n\t\t\tsetDisableAutoDateStamp: setDisableAutoDateStamp,\n\t\t\tsetDisableAutoUserStamp: setDisableAutoUserStamp,\n\t\t\tsetDisableDeleteTracking: setDisableDeleteTracking,\n\n\t\t\tsetDialect: setDialect,\n\n\t\t\tbuildCreateQuery: buildCreateQuery,\n\t\t\tbuildReadQuery: buildReadQuery,\n\t\t\tbuildUpdateQuery: buildUpdateQuery,\n\t\t\tbuildDeleteQuery: buildDeleteQuery,\n\t\t\tbuildUndeleteQuery: buildUndeleteQuery,\n\t\t\tbuildCountQuery: buildCountQuery,\n\n\t\t\tclone: clone,\n\t\t\tnew: createNew\n\t\t});\n\n\t\t/**\n\t\t * Query\n\t\t *\n\t\t * @property query\n\t\t * @type Object\n\t\t */\n\t\tObject.defineProperty(tmpNewFoxHoundObject, 'query',\n\t\t\t{\n\t\t\t\tget: function() { return _Parameters.query; },\n\t\t\t\tset: function(pQuery) { _Parameters.query = pQuery; },\n\t\t\t\tenumerable: true\n\t\t\t});\n\n\t\t/**\n\t\t * Result\n\t\t *\n\t\t * @property result\n\t\t * @type Object\n\t\t */\n\t\tObject.defineProperty(tmpNewFoxHoundObject, 'result',\n\t\t\t{\n\t\t\t\tget: function() { return _Parameters.result; },\n\t\t\t\tset: function(pResult) { _Parameters.result = pResult; },\n\t\t\t\tenumerable: true\n\t\t\t});\n\n\t\t/**\n\t\t * Query Parameters\n\t\t *\n\t\t * @property parameters\n\t\t * @type Object\n\t\t */\n\t\tObject.defineProperty(tmpNewFoxHoundObject, 'parameters',\n\t\t\t{\n\t\t\t\tget: function() { return _Parameters; },\n\t\t\t\tset: function(pParameters) { _Parameters = pParameters; },\n\t\t\t\tenumerable: true\n\t\t\t});\n\n\t\t/**\n\t\t * Dialect\n\t\t *\n\t\t * @property dialect\n\t\t * @type Object\n\t\t */\n\t\tObject.defineProperty(tmpNewFoxHoundObject, 'dialect',\n\t\t\t{\n\t\t\t\tget: function() { return _Dialect; },\n\t\t\t\tenumerable: true\n\t\t\t});\n\n\t\t/**\n\t\t * Universally Unique Identifier\n\t\t *\n\t\t * @property uuid\n\t\t * @type String\n\t\t */\n\t\tObject.defineProperty(tmpNewFoxHoundObject, 'uuid',\n\t\t\t{\n\t\t\t\tget: function() { return _UUID; },\n\t\t\t\tenumerable: true\n\t\t\t});\n\n\t\t/**\n\t\t * Log Level\n\t\t *\n\t\t * @property logLevel\n\t\t * @type Integer\n\t\t */\n\t\tObject.defineProperty(tmpNewFoxHoundObject, 'logLevel',\n\t\t\t{\n\t\t\t\tget: function() { return _LogLevel; },\n\t\t\t\tenumerable: true\n\t\t\t});\n\n\t\treturn tmpNewFoxHoundObject;\n\t}\n\n\treturn createNew();\n};\n\nmodule.exports = FoxHound();\n\n},{\"./Foxhound-Dialects.js\":2,\"./Parameters.js\":4}],4:[function(require,module,exports){\n/**\n* Query Parameters Object\n*\n* @class FoxHoundQueryParameters\n* @constructor\n*/\nvar FoxHoundQueryParameters = (\n{\n\t\tscope: false, // STR: The scope of the data\n\t\t\t\t\t\t\t\t// TSQL: the \"Table\" or \"View\"\n\t\t\t\t\t\t\t\t// MongoDB: the \"Collection\"\n\n\t\tdataElements: false, // ARR of STR: The data elements to return\n\t\t\t\t\t\t\t\t// TSQL: the \"Columns\"\n\t\t\t\t\t\t\t\t// MongoDB: the \"Fields\"\n\n\t\tbegin: false, // INT: Record index to start at\n\t\t\t\t\t\t\t\t// TSQL: n in LIMIT 1,n\n\t\t\t\t\t\t\t\t// MongoDB: n in Skip(n)\n\n\t\tcap: false, // INT: Maximum number of records to return\n\t\t\t\t\t\t\t\t// TSQL: n in LIMIT n\n\t\t\t\t\t\t\t\t// MongoDB: n in limit(n)\n\n\t\t// Serialization example for a query:\n\t\t// Take the filter and return an array of filter instructions\n\t\t// Basic instruction anatomy:\n\t\t// INSTRUCTION~FIELD~OPERATOR~VALUE\n\t\t// FOP - Filter Open Paren\n\t\t// FOP~~(~\n\t\t// FCP - Filter Close Paren\n\t\t// FCP~~)~\n\t\t// FBV - Filter By Value\n\t\t// FBV~Category~EQ~Books\n\t\t// Possible comparisons:\n\t\t// * EQ - Equals To (=)\n\t\t// * NE - Not Equals To (!=)\n\t\t// * GT - Greater Than (>)\n\t\t// * GE - Greater Than or Equals To (>=)\n\t\t// * LT - Less Than (<)\n\t\t// * LE - Less Than or Equals To (<=)\n\t\t// * LK - Like (Like)\n\t\t// FBL - Filter By List (value list, separated by commas)\n\t\t// FBL~Category~EQ~Books,Movies\n\t\t// FSF - Filter Sort Field\n\t\t// FSF~Category~ASC~0\n\t\t// FSF~Category~DESC~0\n\t\t// FCC - Filter Constraint Cap (the limit of what is returned)\n\t\t// FCC~~10~\n\t\t// FCB - Filter Constraint Begin (the zero-based start index of what is returned)\n\t\t// FCB~~10~\n\t\t//\n\t\t// This means: FBV~Category~EQ~Books~FBV~PublishedYear~GT~2000~FSF~PublishedYear~DESC~0\n\t\t// Filters down to ALL BOOKS PUBLISHED AFTER 2000 IN DESCENDING ORDER\n\t\tfilter: false, // ARR of OBJ: Data filter expression list {Column:'Name', Operator:'EQ', Value:'John', Connector:'And', Parameter:'Name'}\n\t\t\t\t\t\t\t\t// TSQL: the WHERE clause\n\t\t\t\t\t\t\t\t// MongoDB: a find() expression\n\n\t\tsort: false, // ARR of OBJ: The sort order {Column:'Birthday', Direction:'Ascending'}\n\t\t\t\t\t\t\t\t// TSQL: ORDER BY\n\t\t\t\t\t\t\t\t// MongoDB: sort()\n\n\t\tjoin: false, // ARR of OBJ: The join tables {Type:'INNER JOIN', Table:'test', From: 'Test.ID', To: 'Scope.IDItem' }\n\t\t\t\t\t\t\t\t// TSQL: JOIN\n\n\t\t// Force a specific query to run regardless of above ... this is used to override the query generator.\n\t\tqueryOverride: false,\n\n\t\t// Where the generated query goes\n\t\tquery: false,\n\t\t/*\n\t\t\t{\n\t\t\t\tbody: false,\n\t\t\t\tschema: false, // The schema to intersect with our records\n\t\t\t\tIDUser: 0, // The User ID to stamp into records\n\t\t\t\tUUID: A_UUID, // Some globally unique record id, different per cloned query.\n\t\t\t\trecords: false, // The records to be created or changed\n\t\t\t\tparameters: {}\n\t\t\t}\n\t\t*/\n\t\t\n\t\t// Who is making the query\n\t\tuserID: 0,\n\n\t\t// Where the query results are stuck\n\t\tresult: false\n\t\t/*\n\t\t\t{\n\t\t\t\texecuted: false, // True once we've run a query.\n\t\t\t\tvalue: false, // The return value of the last query run\n\t\t\t\terror: false // The error message of the last run query\n\t\t\t}\n\t\t*/\n});\n\nmodule.exports = FoxHoundQueryParameters;\n},{}],5:[function(require,module,exports){\n/**\n* FoxHound ALASQL Dialect\n*\n* @license MIT\n*\n* For an ALASQL query override:\n// An underscore template with the following values:\n// <%= DataElements %> = Field1, Field2, Field3, Field4\n// <%= Begin %> = 0\n// <%= Cap %> = 10\n// <%= Filter %> = WHERE StartDate > :MyStartDate\n// <%= Sort %> = ORDER BY Field1\n// The values are empty strings if they aren't set.\n*\n* @author Steven Velozo <steven@velozo.com>\n* @class FoxHoundDialectALASQL\n*/\n\nvar FoxHoundDialectALASQL = function(pFable)\n{\n\t//Request time from SQL server with microseconds resolution\n\tconst SQL_NOW = \"NOW(3)\";\n\n\t_Fable = pFable;\n\n\t/**\n\t* Generate a table name from the scope.\n\t*\n\t* Because ALASQL is all in-memory, and can be run in two modes (anonymous\n\t* working on arrays or table-based) we are going to make this a programmable\n\t* value. Then we can share the code across both providers.\n\t*\n\t* @method: generateTableName\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateTableName = function(pParameters)\n\t{\n\t\treturn ' '+pParameters.scope;\n\t};\n\n\t/**\n\t* Escape columns, because ALASQL has more reserved KWs than most SQL dialects\n\t*/\n\tvar escapeColumn = (pColumn, pParameters) =>\n\t{\n\t\tif (pColumn.indexOf('.') < 0)\n\t\t{\n\t\t\treturn '`'+pColumn+'`';\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// This could suck if the scope is not the same\n\t\t\tvar tmpTableName = pParameters.scope;\n\t\t\tif (pColumn.indexOf(tmpTableName+'.') > -1)\n\t\t\t{\n\t\t\t\treturn '`'+pColumn.replace(tmpTableName+'.', '')+'`';\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// This doesn't work well but we'll try it.\n\t\t\t\treturn '`'+pColumn+'`';\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t* Generate a field list from the array of dataElements\n\t*\n\t* Each entry in the dataElements is a simple string\n\t*\n\t* @method: generateFieldList\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @param {Boolean} pIsForCountClause (optional) If true, generate fields for use within a count clause.\n\t* @return: {String} Returns the field list clause, or empty string if explicit fields are requested but cannot be fulfilled\n\t* due to missing schema.\n\t*/\n\tvar generateFieldList = function(pParameters, pIsForCountClause)\n\t{\n\t\tvar tmpDataElements = pParameters.dataElements;\n\t\tif (!Array.isArray(tmpDataElements) || tmpDataElements.length < 1)\n\t\t{\n\t\t\tif (!pIsForCountClause)\n\t\t\t{\n\t\t\t\treturn ' *';\n\t\t\t}\n\t\t\t// we need to list all of the table fields explicitly; get them from the schema\n\t\t\tconst tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\t\t\tif (tmpSchema.length < 1)\n\t\t\t{\n\t\t\t\t// this means we have no schema; returning an empty string here signals the calling code to handle this case\n\t\t\t\treturn '';\n\t\t\t}\n\t\t\tconst idColumn = tmpSchema.find((entry) => entry.Type === 'AutoIdentity');\n\t\t\tif (!idColumn)\n\t\t\t{\n\t\t\t\t// this means there is no autoincrementing unique ID column; treat as above\n\t\t\t\treturn '';\n\t\t\t}\n\t\t\treturn ` ${idColumn.Column}`;\n\t\t}\n\n\t\tvar tmpFieldList = ' ';\n\t\tfor (var i = 0; i < tmpDataElements.length; i++)\n\t\t{\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\ttmpFieldList += ', ';\n\t\t\t}\n\t\t\ttmpFieldList += escapeColumn(tmpDataElements[i], pParameters);\n\t\t}\n\t\treturn tmpFieldList;\n\t};\n\n\t/**\n\t* Generate a query from the array of where clauses\n\t*\n\t* Each clause is an object like:\n\t\t{\n\t\t\tColumn:'Name',\n\t\t\tOperator:'EQ',\n\t\t\tValue:'John',\n\t\t\tConnector:'And',\n\t\t\tParameter:'Name'\n\t\t}\n\t*\n\t* @method: generateWhere\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the WHERE clause prefixed with WHERE, or an empty string if unnecessary\n\t*/\n\tvar generateWhere = function(pParameters)\n\t{\n\t\tvar tmpFilter = Array.isArray(pParameters.filter) ? pParameters.filter : [];\n\t\tvar tmpTableName = generateTableName(pParameters).trim();\n\n\t\tif (!pParameters.query.disableDeleteTracking)\n\t\t{\n\t\t\t// Check if there is a Deleted column on the Schema. If so, we add this to the filters automatically (if not already present)\n\t\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\tvar tmpSchemaEntry = tmpSchema[i];\n\n\t\t\t\tif (tmpSchemaEntry.Type === 'Deleted')\n\t\t\t\t{\n\t\t\t\t\tvar tmpHasDeletedParameter = false;\n\n\t\t\t\t\t//first, check to see if filters are already looking for Deleted column\n\t\t\t\t\tif (tmpFilter.length > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (var x = 0; x < tmpFilter.length; x++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (tmpFilter[x].Column === tmpSchemaEntry.Column)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttmpHasDeletedParameter = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (!tmpHasDeletedParameter)\n\t\t\t\t\t{\n\t\t\t\t\t\t//if not, we need to add it\n\t\t\t\t\t\ttmpFilter.push(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tColumn: tmpTableName + '.' + tmpSchemaEntry.Column,\n\t\t\t\t\t\t\tOperator: '=',\n\t\t\t\t\t\t\tValue: 0,\n\t\t\t\t\t\t\tConnector: 'AND',\n\t\t\t\t\t\t\tParameter: 'Deleted'\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (tmpFilter.length < 1)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpWhere = ' WHERE';\n\n\t\t// This is used to disable the connectors for subsequent queries.\n\t\t// Only the open parenthesis operator uses this, currently.\n\t\tvar tmpLastOperatorNoConnector = false;\n\n\t\tfor (var i = 0; i < tmpFilter.length; i++)\n\t\t{\n\t\t\tif ((tmpFilter[i].Connector != 'NONE') && (tmpFilter[i].Operator != ')') && (tmpWhere != ' WHERE') && (tmpLastOperatorNoConnector == false))\n\t\t\t{\n\t\t\t\ttmpWhere += ' '+tmpFilter[i].Connector;\n\t\t\t}\n\n\t\t\ttmpLastOperatorNoConnector = false;\n\n\t\t\tvar tmpColumnParameter;\n\n\t\t\tif (tmpFilter[i].Operator === '(')\n\t\t\t{\n\t\t\t\t// Open a logical grouping\n\t\t\t\ttmpWhere += ' (';\n\t\t\t\ttmpLastOperatorNoConnector = true;\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === ')')\n\t\t\t{\n\t\t\t\t// Close a logical grouping\n\t\t\t\ttmpWhere += ' )';\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IN')\n\t\t\t{\n\t\t\t\ttmpColumnParameter = tmpFilter[i].Parameter+'_w'+i;\n\t\t\t\t// Add the column name, operator and parameter name to the list of where value parenthetical\n\t\t\t\ttmpWhere += ' '+escapeColumn(tmpFilter[i].Column, pParameters)+' '+tmpFilter[i].Operator+' ( :'+tmpColumnParameter+' )';\n\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = tmpFilter[i].Value;\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IS NOT NULL')\n\t\t\t{\n\t\t\t\t// IS NOT NULL is a special operator which doesn't require a value, or parameter\n\t\t\t\ttmpWhere += ' '+escapeColumn(tmpFilter[i].Column, pParameters)+' '+tmpFilter[i].Operator;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpColumnParameter = tmpFilter[i].Parameter+'_w'+i;\n\t\t\t\t// Add the column name, operator and parameter name to the list of where value parenthetical\n\t\t\t\ttmpWhere += ' '+escapeColumn(tmpFilter[i].Column, pParameters)+' '+tmpFilter[i].Operator+' :'+tmpColumnParameter;\n\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = tmpFilter[i].Value;\n\t\t\t}\n\t\t}\n\n\t\treturn tmpWhere;\n\t};\n\n\t/**\n\t* Generate an ORDER BY clause from the sort array\n\t*\n\t* Each entry in the sort is an object like:\n\t* {Column:'Color',Direction:'Descending'}\n\t*\n\t* @method: generateOrderBy\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the field list clause\n\t*/\n\tvar generateOrderBy = function(pParameters)\n\t{\n\t\tvar tmpOrderBy = pParameters.sort;\n\t\tif (!Array.isArray(tmpOrderBy) || tmpOrderBy.length < 1)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpOrderClause = ' ORDER BY';\n\t\tfor (var i = 0; i < tmpOrderBy.length; i++)\n\t\t{\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\ttmpOrderClause += ',';\n\t\t\t}\n\t\t\ttmpOrderClause += ' '+escapeColumn(tmpOrderBy[i].Column, pParameters);\n\n\t\t\tif (tmpOrderBy[i].Direction == 'Descending')\n\t\t\t{\n\t\t\t\ttmpOrderClause += ' DESC';\n\t\t\t}\n\t\t}\n\t\treturn tmpOrderClause;\n\t};\n\n\t/**\n\t* Generate the limit clause\n\t*\n\t* @method: generateLimit\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateLimit = function(pParameters)\n\t{\n\t\tif (!pParameters.cap)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpLimit = ' LIMIT';\n\t\t// Cap is required for a limit clause.\n\t\ttmpLimit += ' ' + pParameters.cap;\n\n\t\t// If there is a begin record, we'll pass that in as well.\n\t\tif (pParameters.begin !== false)\n\t\t{\n\t\t\ttmpLimit += ' FETCH ' + pParameters.begin;\n\t\t}\n\n\t\treturn tmpLimit;\n\t};\n\n\t/**\n\t* Generate the update SET clause\n\t*\n\t* @method: generateUpdateSetters\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateUpdateSetters = function(pParameters)\n\t{\n\t\tvar tmpRecords = pParameters.query.records;\n\t\t// We need to tell the query not to generate improperly if there are no values to set.\n\t\tif (!Array.isArray(tmpRecords) || tmpRecords.length < 1)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpUpdate = '';\n\t\t// If there is more than one record in records, we are going to ignore them for now.\n\t\tvar tmpCurrentColumn = 0;\n\t\tfor(var tmpColumn in tmpRecords[0])\n\t\t{\n\t\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\t\tvar tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\tif (tmpColumn == tmpSchema[i].Column)\n\t\t\t\t{\n\t\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\t\ttmpSchemaEntry = tmpSchema[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (pParameters.query.disableAutoDateStamp &&\n\t\t\t\ttmpSchemaEntry.Type === 'UpdateDate')\n\t\t\t{\n\t\t\t\t// This is ignored if flag is set\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (pParameters.query.disableAutoUserStamp &&\n\t\t\t\ttmpSchemaEntry.Type === 'UpdateIDUser')\n\t\t\t{\n\t\t\t\t// This is ignored if flag is set\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'AutoIdentity':\n\t\t\t\tcase 'CreateDate':\n\t\t\t\tcase 'CreateIDUser':\n\t\t\t\tcase 'DeleteDate':\n\t\t\t\tcase 'DeleteIDUser':\n\t\t\t\t\t// These are all ignored on update\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpUpdate += ',';\n\t\t\t}\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\ttmpUpdate += ' '+escapeColumn(tmpColumn, pParameters)+' = NOW()';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateIDUser':\n\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\tvar tmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdate += ' '+escapeColumn(tmpColumn, pParameters)+' = :'+tmpColumnParameter;\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tvar tmpColumnDefaultParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdate += ' '+escapeColumn(tmpColumn, pParameters)+' = :'+tmpColumnDefaultParameter;\n\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnDefaultParameter] = tmpRecords[0][tmpColumn];\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// We use a number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (tmpUpdate === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpUpdate;\n\t};\n\n\t/**\n\t* Generate the update-delete SET clause\n\t*\n\t* @method: generateUpdateDeleteSetters\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateUpdateDeleteSetters = function(pParameters)\n\t{\n\t\tif (pParameters.query.disableDeleteTracking)\n\t\t{\n\t\t\t//Don't generate an UPDATE query if Delete tracking is disabled\n\t\t\treturn false;\n\t\t}\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpCurrentColumn = 0;\n\t\tvar tmpHasDeletedField = false;\n\t\tvar tmpUpdate = '';\n\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\tvar tmpSchemaEntry = {Type:'Default'};\n\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t{\n\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\ttmpSchemaEntry = tmpSchema[i];\n\n\t\t\tvar tmpUpdateSql = null;\n\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'Deleted':\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = 1';\n\t\t\t\t\ttmpHasDeletedField = true; //this field is required in order for query to be built\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'DeleteDate':\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = NOW()';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\t\t// Delete operation is an Update, so we should stamp the update time\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = NOW()';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'DeleteIDUser':\n\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\tvar tmpColumnParameter = tmpSchemaEntry.Column+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = :'+tmpColumnParameter;\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t//DON'T allow update of other fields in this query\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpUpdate += ',';\n\t\t\t}\n\n\t\t\ttmpUpdate += tmpUpdateSql;\n\n\t\t\t// We use a number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (!tmpHasDeletedField ||\n\t\t\ttmpUpdate === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpUpdate;\n\t};\n\n\t/**\n\t* Generate the update-delete SET clause\n\t*\n\t* @method: generateUpdateDeleteSetters\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateUpdateUndeleteSetters = function(pParameters)\n\t{\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpCurrentColumn = 0;\n\t\tvar tmpHasDeletedField = false;\n\t\tvar tmpUpdate = '';\n\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\tvar tmpSchemaEntry = {Type:'Default'};\n\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t{\n\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\ttmpSchemaEntry = tmpSchema[i];\n\n\t\t\tvar tmpUpdateSql = null;\n\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'Deleted':\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = 0';\n\t\t\t\t\ttmpHasDeletedField = true; //this field is required in order for query to be built\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\t\t// Delete operation is an Update, so we should stamp the update time\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = NOW()';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateIDUser':\n\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\tvar tmpColumnParameter = tmpSchemaEntry.Column+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = :'+tmpColumnParameter;\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t//DON'T allow update of other fields in this query\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpUpdate += ',';\n\t\t\t}\n\n\t\t\ttmpUpdate += tmpUpdateSql;\n\n\t\t\t// We use a number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (!tmpHasDeletedField ||\n\t\t\ttmpUpdate === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpUpdate;\n\t};\n\n\t/**\n\t* Generate the create SET clause\n\t*\n\t* @method: generateCreateSetList\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateCreateSetValues = function(pParameters)\n\t{\n\t\tvar tmpRecords = pParameters.query.records;\n\t\t// We need to tell the query not to generate improperly if there are no values to set.\n\t\tif (!Array.isArray(tmpRecords) || tmpRecords.length < 1)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\n\t\tvar tmpCreateSet = '';\n\t\t// If there is more than one record in records, we are going to ignore them for now.\n\t\tvar tmpCurrentColumn = 0;\n\t\tfor(var tmpColumn in tmpRecords[0])\n\t\t{\n\t\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\t\tvar tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\tif (tmpColumn == tmpSchema[i].Column)\n\t\t\t\t{\n\t\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\t\ttmpSchemaEntry = tmpSchema[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!pParameters.query.disableDeleteTracking)\n\t\t\t{\n\t\t\t\tif (tmpSchemaEntry.Type === 'DeleteDate' ||\n\t\t\t\t\ttmpSchemaEntry.Type === 'DeleteIDUser')\n\t\t\t\t{\n\t\t\t\t\t// These are all ignored on insert (if delete tracking is enabled as normal)\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpCreateSet += ',';\n\t\t\t}\n\n\t\t\t//define a re-usable method for setting up field definitions in a default pattern\n\t\t\tvar buildDefaultDefinition = function()\n\t\t\t{\n\t\t\t\tvar tmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\ttmpCreateSet += ' :'+tmpColumnParameter;\n\t\t\t\t// Set the query parameter\n\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = tmpRecords[0][tmpColumn];\n\t\t\t};\n\n\t\t\tvar tmpColumnParameter;\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'AutoIdentity':\n\t\t\t\t\tif (pParameters.query.disableAutoIdentity)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\t\ttmpCreateSet += ' NULL';\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'AutoGUID':\n\t\t\t\t\tif (pParameters.query.disableAutoIdentity)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse if (tmpRecords[0][tmpColumn] &&\n\t\t\t\t\t\t\ttmpRecords[0][tmpColumn].length >= 5 &&\n\t\t\t\t\t\t\ttmpRecords[0][tmpColumn] !== '0x0000000000000000') //stricture default\n\t\t\t\t\t{\n\t\t\t\t\t\t// Allow consumer to override AutoGUID\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\t\ttmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\t\ttmpCreateSet += ' :'+tmpColumnParameter;\n\t\t\t\t\t\t// Set the query parameter\n\t\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.UUID;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\tcase 'CreateDate':\n\t\t\t\tcase 'DeleteDate':\n\t\t\t\t\tif (pParameters.query.disableAutoDateStamp)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\t\ttmpCreateSet += ' NOW()';\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateIDUser':\n\t\t\t\tcase 'CreateIDUser':\n\t\t\t\tcase 'DeleteIDUser':\n\t\t\t\t\tif (pParameters.query.disableAutoUserStamp)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\t\ttmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\t\ttmpCreateSet += ' :'+tmpColumnParameter;\n\t\t\t\t\t\t// Set the query parameter\n\t\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// We use an appended number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (tmpCreateSet === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpCreateSet;\n\t};\n\n\t/**\n\t* Generate the create SET clause\n\t*\n\t* @method: generateCreateSetList\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateCreateSetList = function(pParameters)\n\t{\n\t\t// The records were already validated by generateCreateSetValues\n\t\tvar tmpRecords = pParameters.query.records;\n\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpCreateSet = '';\n\t\t// If there is more than one record in records, we are going to ignore them for now.\n\t\tfor(var tmpColumn in tmpRecords[0])\n\t\t{\n\t\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\t\tvar tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\tif (tmpColumn == tmpSchema[i].Column)\n\t\t\t\t{\n\t\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\t\ttmpSchemaEntry = tmpSchema[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!pParameters.query.disableDeleteTracking)\n\t\t\t{\n\t\t\t\tif (tmpSchemaEntry.Type === 'DeleteDate' ||\n\t\t\t\t\ttmpSchemaEntry.Type === 'DeleteIDUser')\n\t\t\t\t{\n\t\t\t\t\t// These are all ignored on insert (if delete tracking is enabled as normal)\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tdefault:\n\t\t\t\t\tif (tmpCreateSet != '')\n\t\t\t\t\t{\n\t\t\t\t\t\ttmpCreateSet += ',';\n\t\t\t\t\t}\n\t\t\t\t\ttmpCreateSet += ' '+escapeColumn(tmpColumn, pParameters);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn tmpCreateSet;\n\t};\n\n\n\tvar Create = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpCreateSetList = generateCreateSetList(pParameters);\n\t\tvar tmpCreateSetValues = generateCreateSetValues(pParameters);\n\n\t\tif (!tmpCreateSetValues)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn 'INSERT INTO'+tmpTableName+' ('+tmpCreateSetList+') VALUES ('+tmpCreateSetValues+');';\n\t};\n\n\n\t/**\n\t* Read one or many records\n\t*\n\t* Some examples:\n\t* SELECT * FROM WIDGETS;\n\t* SELECT * FROM WIDGETS LIMIT 0, 20;\n\t* SELECT * FROM WIDGETS LIMIT 5, 20;\n\t* SELECT ID, Name, Cost FROM WIDGETS LIMIT 5, 20;\n\t* SELECT ID, Name, Cost FROM WIDGETS LIMIT 5, 20 WHERE LastName = 'Smith';\n\t*\n\t* @method Read\n\t* @param {Object} pParameters SQL Query parameters\n\t* @return {String} Returns the current Query for chaining.\n\t*/\n\tvar Read = function(pParameters)\n\t{\n\t\tvar tmpFieldList = generateFieldList(pParameters);\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpOrderBy = generateOrderBy(pParameters);\n\t\tvar tmpLimit = generateLimit(pParameters);\n\t\tconst tmpOptDistinct = pParameters.distinct ? ' DISTINCT' : '';\n\n\t\tif (pParameters.queryOverride)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tvar tmpQueryTemplate = _Fable.Utility.template(pParameters.queryOverride);\n\t\t\t\treturn tmpQueryTemplate({FieldList:tmpFieldList, TableName:tmpTableName, Where:tmpWhere, OrderBy:tmpOrderBy, Limit:tmpLimit, Distinct: tmpOptDistinct, _Params: pParameters});\n\t\t\t}\n\t\t\tcatch (pError)\n\t\t\t{\n\t\t\t\t// This pokemon is here to give us a convenient way of not throwing up totally if the query fails.\n\t\t\t\tconsole.log('Error with custom Read Query ['+pParameters.queryOverride+']: '+pError);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn `SELECT${tmpOptDistinct}${tmpFieldList} FROM${tmpTableName}${tmpWhere}${tmpOrderBy}${tmpLimit};`;\n\t};\n\n\tvar Update = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpUpdateSetters = generateUpdateSetters(pParameters);\n\n\t\tif (!tmpUpdateSetters)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn 'UPDATE'+tmpTableName+' SET'+tmpUpdateSetters+tmpWhere+';';\n\t};\n\n\tvar Delete = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpUpdateDeleteSetters = generateUpdateDeleteSetters(pParameters);\n\n\t\tif (tmpUpdateDeleteSetters)\n\t\t{\n\t\t\t//If it has a deleted bit, update it instead of actually deleting the record\n\t\t\treturn 'UPDATE'+tmpTableName+' SET'+tmpUpdateDeleteSetters+tmpWhere+';';\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn 'DELETE FROM'+tmpTableName+tmpWhere+';';\n\t\t}\n\t};\n\n\tvar Undelete = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tlet tmpDeleteTrackingState = pParameters.query.disableDeleteTracking;\n\t\tpParameters.query.disableDeleteTracking = true;\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpUpdateUndeleteSetters = generateUpdateUndeleteSetters(pParameters);\n\t\tpParameters.query.disableDeleteTracking = tmpDeleteTrackingState;\n\n\t\tif (tmpUpdateUndeleteSetters)\n\t\t{\n\t\t\t//If it has a deleted bit, update it instead of actually deleting the record\n\t\t\treturn 'UPDATE'+tmpTableName+' SET'+tmpUpdateUndeleteSetters+tmpWhere+';';\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn 'SELECT NULL;';\n\t\t}\n\t};\n\n\tvar Count = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tconst tmpFieldList = pParameters.distinct ? generateFieldList(pParameters, true) : '*';\n\n\t\t// here, we ignore the distinct keyword if no fields have been specified and\n\t\tif (pParameters.distinct && tmpFieldList.length < 1)\n\t\t{\n\t\t\tconsole.warn('Distinct requested but no field list or schema are available, so not honoring distinct for count query.');\n\t\t}\n\t\tconst tmpOptDistinct = pParameters.distinct && tmpFieldList.length > 0 ? 'DISTINCT' : '';\n\t\tif (pParameters.queryOverride)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tvar tmpQueryTemplate = _Fable.Utility.template(pParameters.queryOverride);\n\t\t\t\treturn tmpQueryTemplate({FieldList:[], TableName:tmpTableName, Where:tmpWhere, OrderBy:'', Limit:'', Distinct: tmpOptDistinct, _Params: pParameters});\n\t\t\t}\n\t\t\tcatch (pError)\n\t\t\t{\n\t\t\t\t// This pokemon is here to give us a convenient way of not throwing up totally if the query fails.\n\t\t\t\tconsole.log('Error with custom Count Query ['+pParameters.queryOverride+']: '+pError);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn `SELECT COUNT(${tmpOptDistinct}${tmpFieldList || '*'}) AS RowCount FROM${tmpTableName}${tmpWhere};`;\n\t};\n\n\tvar tmpDialect = ({\n\t\tCreate: Create,\n\t\tRead: Read,\n\t\tUpdate: Update,\n\t\tDelete: Delete,\n\t\tUndelete: Undelete,\n\t\tCount: Count\n\t});\n\n\t/**\n\t* Dialect Name\n\t*\n\t* @property name\n\t* @type string\n\t*/\n\tObject.defineProperty(tmpDialect, 'name',\n\t\t{\n\t\t\tget: function() { return 'ALASQL'; },\n\t\t\tenumerable: true\n\t\t});\n\n\treturn tmpDialect;\n};\n\nmodule.exports = FoxHoundDialectALASQL;\n\n},{}],6:[function(require,module,exports){\n/**\n* FoxHound English Dialect\n*\n* Because if I can't ask for it in my native tongue, how am I going to ask a\n* complicated server for it?\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n* @class FoxHoundDialectEnglish\n*/\nvar FoxHoundDialectEnglish = function()\n{\n\tvar Create = function(pParameters)\n\t{\n\t\tvar tmpScope = pParameters.scope;\n\n\t\treturn 'Here is a '+tmpScope+'.';\n\t};\n\n\t/**\n\t* Read one or many records\n\t*\n\t* Some examples:\n\t* Please give me all your Widget records. Thanks.\n\t* Please give me 20 Widget records. Thanks.\n\t* Please give me 20 Widget records starting with record 5. Thanks.\n\t* Please give me the ID, Name and Cost of 20 Widget records starting with record 5. Thanks.\n\t* Please give me the ID and Name of 20 Widget records starting with record 5, when LastName equals \"Smith\". Thanks.\n\t*\n\t* @method Read\n\t* @param {Number} pLogLevel The log level for our object\n\t* @return {String} Returns the current Query for chaining.\n\t*/\n\tvar Read = function(pParameters)\n\t{\n\t\tvar tmpScope = pParameters.scope;\n\t\tconst tmpDistinct = pParameters.distinct ? 'unique ' : '';\n\n\t\treturn `Please give me all your ${tmpDistinct}${tmpScope} records. Thanks.`;\n\t};\n\n\tvar Update = function(pParameters)\n\t{\n\t\tvar tmpScope = pParameters.scope;\n\n\t\treturn 'I am changing your '+tmpScope+'.';\n\t};\n\n\tvar Delete = function(pParameters)\n\t{\n\t\tvar tmpScope = pParameters.scope;\n\n\t\treturn 'I am deleting your '+tmpScope+'.';\n\t};\n\n\tvar Undelete = function(pParameters)\n\t{\n\t\tvar tmpScope = pParameters.scope;\n\n\t\treturn 'I am undeleting your '+tmpScope+'.';\n\t};\n\n\tvar Count = function(pParameters)\n\t{\n\t\tvar tmpScope = pParameters.scope;\n\t\tconst tmpDistinct = pParameters.distinct ? 'unique ' : '';\n\n\t\treturn `Count your ${tmpDistinct}${tmpScope}.`;\n\t};\n\n\tvar tmpDialect = ({\n\t\tCreate: Create,\n\t\tRead: Read,\n\t\tUpdate: Update,\n\t\tDelete: Delete,\n\t\tUndelete: Undelete,\n\t\tCount: Count\n\t});\n\n\t/**\n\t * Dialect Name\n\t *\n\t * @property name\n\t * @type string\n\t */\n\tObject.defineProperty(tmpDialect, 'name',\n\t\t{\n\t\t\tget: function() { return 'English'; },\n\t\t\tenumerable: true\n\t\t});\n\n\treturn tmpDialect;\n};\n\nmodule.exports = FoxHoundDialectEnglish;\n\n},{}],7:[function(require,module,exports){\n/**\n* FoxHound Meadow Endpoints Dialect\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n* @class FoxHoundDialectMeadowEndpoints\n*/\n\nvar FoxHoundDialectMeadowEndpoints = function()\n{\n\t/**\n\t * Generate a table name from the scope\n\t *\n\t * @method: generateTableName\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Returns the table name clause\n\t */\n\tvar generateTableName = function(pParameters)\n\t{\n\t\treturn pParameters.scope;\n\t};\n\n\t/**\n\t * Generate the Identity column from the schema or scope\n\t * \n\t * @method: generateIdentityColumnName\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Returns the table name clause\n\t */\n\tvar generateIdentityColumnName = function(pParameters)\n\t{\n\t\t// TODO: See about using the Schema or the Schemata for this\n\t\treturn `ID${pParameters.scope}`;\n\t};\n\n\t/**\n\t * Generate a field list from the array of dataElements\n\t *\n\t * Each entry in the dataElements is a simple string\n\t *\n\t * @method: generateFieldList\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Returns the field list clause\n\t */\n\tvar generateFieldList = function(pParameters)\n\t{\n\t\tvar tmpDataElements = pParameters.dataElements;\n\t\tif (!Array.isArray(tmpDataElements) || tmpDataElements.length < 1)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpFieldList = '';\n\t\tfor (var i = 0; i < tmpDataElements.length; i++)\n\t\t{\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\ttmpFieldList += ',';\n\t\t\t}\n\n tmpFieldList += tmpDataElements[i];\n\t\t}\n\t\treturn tmpFieldList;\n\t};\n\n\t/**\n\t * Generate a query from the array of where clauses\n\t *\n\t * Each clause is an object like:\n\t\t{\n\t\t\tColumn:'Name', \n\t\t\tOperator:'EQ', \n\t\t\tValue:'John', \n\t\t\tConnector:'And', \n\t\t\tParameter:'Name'\n\t\t}\n\t *\n\t * @method: generateWhere\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Returns the WHERE clause prefixed with WHERE, or an empty string if unnecessary\n\t */\n\tvar generateWhere = function(pParameters)\n\t{\n\t\tvar tmpFilter = Array.isArray(pParameters.filter) ? pParameters.filter : [];\n\t\tvar tmpTableName = generateTableName(pParameters);\n \n var tmpURL = '';\n\n let tmpfAddFilter = (pFilterCommand, pFilterParameters) =>\n {\n if (tmpURL.length > 0)\n {\n tmpURL += '~';\n }\n \n tmpURL += `${pFilterCommand}~${pFilterParameters[0]}~${pFilterParameters[1]}~${pFilterParameters[2]}`;\n };\n\n let tmpfTranslateOperator = (pOperator) =>\n {\n tmpNewOperator = 'EQ';\n switch(pOperator.toUpperCase())\n {\n case '!=':\n tmpNewOperator = 'NE';\n break;\n case '>':\n tmpNewOperator = 'GT';\n break;\n case '>=':\n tmpNewOperator = 'GE';\n break;\n case '<=':\n tmpNewOperator = 'LE';\n break;\n case '<':\n tmpNewOperator = 'LT';\n break;\n case 'LIKE':\n tmpNewOperator = 'LK';\n break;\n case 'IN':\n tmpNewOperator = 'INN';\n break;\n case 'NOT IN':\n tmpNewOperator = 'NI';\n break;\n }\n return tmpNewOperator;\n }\n\n // Translating Delete Tracking bit on query to a query with automagic\n // This will eventually deprecate this as part of the necessary query\n if (pParameters.query.disableDeleteTracking)\n {\n tmpfAddFilter('FBV',['Deleted','GE','0'])\n }\n\n\t\tfor (var i = 0; i < tmpFilter.length; i++)\n\t\t{\n\t\t\tif (tmpFilter[i].Operator === '(')\n\t\t\t{\n tmpfAddFilter('FOP',['0','(','0']);\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === ')')\n\t\t\t{\n\t\t\t\t// Close a logical grouping\n tmpfAddFilter('FCP',['0',')','0']);\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IN' || tmpFilter[i].Operator === \"NOT IN\")\n\t\t\t{\n let tmpFilterCommand = 'FBV';\n if (tmpFilter[i].Connector == 'OR')\n {\n tmpFilterCommand = 'FBVOR';\n }\n\t\t\t\t// Add the column name, operator and parameter name to the list of where value parenthetical\n tmpfAddFilter(tmpFilterCommand, [tmpFilter[i].Column, tmpfTranslateOperator(tmpFilter[i].Operator), tmpFilter[i].Value.map(encodeURIComponent).join(',')])\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IS NULL')\n\t\t\t{\n\t\t\t\t// IS NULL is a special operator which doesn't require a value, or parameter\n tmpfAddFilter('FBV', [tmpFilter[i].Column, 'IN', '0']);\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IS NOT NULL')\n\t\t\t{\n\t\t\t\t// IS NOT NULL is a special operator which doesn't require a value, or parameter\n tmpfAddFilter('FBV', [tmpFilter[i].Column, 'NN', '0']);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n let tmpFilterCommand = 'FBV';\n if (tmpFilter[i].Connector == 'OR')\n {\n tmpFilterCommand = 'FBVOR';\n }\n\t\t\t\t// Add the column name, operator and parameter name to the list of where value parenthetical\n tmpfAddFilter(tmpFilterCommand, [tmpFilter[i].Column, tmpfTranslateOperator(tmpFilter[i].Operator), encodeURIComponent(tmpFilter[i].Value)]);\n\t\t\t}\n\t\t}\n\n let tmpOrderBy = generateOrderBy(pParameters);\n if (tmpOrderBy)\n {\n if (tmpURL)\n {\n tmpURL += '~';\n }\n tmpURL += tmpOrderBy;\n }\n\n\t\treturn tmpURL;\n\t};\n\n /**\n\t * Get the flags for the request\n * \n * These are usually passed in for Update and Create when extra tracking is disabled.\n\t *\n\t * @method: generateFlags\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Flags to be sent, if any.\n\t */\n function generateFlags(pParameters)\n {\n let tmpDisableAutoDateStamp = pParameters.query.disableAutoDateStamp;\n let tmpDisableDeleteTracking = pParameters.query.disableDeleteTracking;\n let tmpDisableAutoIdentity = pParameters.query.disableAutoIdentity;\n let tmpDisableAutoUserStamp = pParameters.query.disableAutoUserStamp;\n\n let tmpFlags = '';\n\n let fAddFlag = (pFlagSet, pFlag) =>\n {\n if (pFlagSet)\n {\n if (tmpFlags.length > 0)\n {\n tmpFlags += ',';\n }\n tmpFlags += pFlag;\n }\n };\n\n fAddFlag(tmpDisableAutoDateStamp, 'DisableAutoDateStamp');\n fAddFlag(tmpDisableDeleteTracking, 'DisableDeleteTracking');\n fAddFlag(tmpDisableAutoIdentity, 'DisableAutoIdentity');\n fAddFlag(tmpDisableAutoUserStamp, 'DisableAutoUserStamp');\n\n return tmpFlags;\n };\n\n /**\n\t * Get the ID for the record, to be used in URIs\n\t *\n\t * @method: getIDRecord\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} ID of the record in string form for the URI\n\t */\n\tvar getIDRecord = function(pParameters)\n\t{\n var tmpFilter = Array.isArray(pParameters.filter) ? pParameters.filter : [];\n\n\t\tvar tmpIDRecord = false;\n\n if (tmpFilter.length < 1)\n\t\t{\n\t\t\treturn tmpIDRecord;\n\t\t}\n\n\t\tfor (var i = 0; i < tmpFilter.length; i++)\n\t\t{\n // Check Schema Entry Type\n var tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\t\t\tvar tmpSchemaEntry = {Column:tmpFilter[i].Column, Type:'Default'};\n\t\t\tfor (var j = 0; j < tmpSchema.length; j++)\n\t\t\t{\n // If this column is the AutoIdentity, set it.\n\t\t\t\tif ((tmpFilter[i].Column == tmpSchema[j].Column) &&\n (tmpSchema[j].Type == 'AutoIdentity'))\n\t\t\t\t{\n tmpIDRecord = tmpFilter[i].Value;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn tmpIDRecord;\n }\n\t\n /**\n\t * Generate an ORDER BY clause from the sort array\n\t *\n\t * Each entry in the sort is an object like:\n\t * {Column:'Color',Direction:'Descending'}\n\t *\n\t * @method: generateOrderBy\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Returns the field list clause\n\t */\n\tvar generateOrderBy = function(pParameters)\n\t{\n\t\tvar tmpOrderBy = pParameters.sort;\n\t\tvar tmpOrderClause = false;\n\n if (!Array.isArray(tmpOrderBy) || tmpOrderBy.length < 1)\n\t\t{\n\t\t\treturn tmpOrderClause;\n\t\t}\n\n tmpOrderClause = '';\n\n for (var i = 0; i < tmpOrderBy.length; i++)\n\t\t{\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\ttmpOrderClause += '~';\n\t\t\t}\n\t\t\ttmpOrderClause += `FSF~${tmpOrderBy[i].Column}~`;\n\n\t\t\tif (tmpOrderBy[i].Direction == 'Descending')\n\t\t\t{\n\t\t\t\ttmpOrderClause += 'DESC~0';\n\t\t\t}\n else\n {\n tmpOrderClause += 'ASC~0'\n }\n\t\t}\n\t\treturn tmpOrderClause;\n\t};\n\n\t/**\n\t * Generate the limit clause\n\t *\n\t * @method: generateLimit\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Returns the table name clause\n\t */\n\tvar generateLimit = function(pParameters)\n\t{\n\t\tif (!pParameters.cap)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n let tmpBegin = (pParameters.begin !== false) ? pParameters.begin : 0;\n\n return `${tmpBegin}/${pParameters.cap}`;\n\t};\n\n\tvar Create = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n var tmpFlags = generateFlags(pParameters);\n\n if (tmpTableName)\n {\n let tmpURL = tmpTableName;\n if (tmpFlags)\n {\n tmpURL = `${tmpURL}/WithFlags/${tmpFlags}`\n }\n return tmpURL;\n }\n else\n {\n return false;\n }\n\t};\n\n\n\t/**\n\t* Read one or many records\n\t*\n\t* @method Read\n\t* @param {Object} pParameters SQL Query parameters\n\t* @return {String} Returns the current Query for chaining.\n\t*/\n\tvar Read = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpFieldList = generateFieldList(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpLimit = generateLimit(pParameters);\n\n\t\tvar tmpURL = `${tmpTableName}`;\n\t\t// In the case that there is only a single query parameter, and the parameter is a single identity, \n\t\t// we will cast it to the READ endpoint rather than READS.\n\t\tif ((pParameters.filter)\n\t\t\t && (pParameters.filter.length == 1)\n // If there is exactly one query filter parameter\n\t\t\t && (pParameters.filter[0].Column === generateIdentityColumnName(pParameters))\n\t\t\t // AND It is the Identity column\n\t\t\t && (pParameters.filter[0].Operator === '=')\n\t\t\t // AND The comparators is a simple equals \n\t\t\t && (tmpLimit == '') && (tmpFieldList == '')\n\t\t\t // AND There is no limit or field list set\n\t\t\t && (!pParameters.sort))\n\t\t\t // AND There is no sort clause\n\t\t{\n\t\t\t// THEN This is a SINGLE READ by presumption.\n\t\t\t// There are some bad side affects this could cause with chaining and overridden behaviors, if \n\t\t\t// we are requesting a filtered list of 1 record.\n\t\t\ttmpURL = `${tmpURL}/${pParameters.filter[0].Value}`;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpURL = `${tmpURL}s`;\n\t\t\tif (tmpFieldList)\n\t\t\t{\n\t\t\t\ttmpURL = `${tmpURL}/LiteExtended/${tmpFieldList}`\n\t\t\t}\n\t\t\tif (tmpWhere)\n\t\t\t{\n\t\t\t\ttmpURL = `${tmpURL}/FilteredTo/${tmpWhere}`;\n\t\t\t}\n\t\t\tif (tmpLimit)\n\t\t\t{\n\t\t\t\ttmpURL = `${tmpURL}/${tmpLimit}`;\n\t\t\t}\n\t\t}\n\n\t\treturn tmpURL;\n\t};\n\n\tvar Update = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n var tmpFlags = generateFlags(pParameters);\n\n if (tmpTableName)\n {\n let tmpURL = tmpTableName;\n if (tmpFlags)\n {\n tmpURL = `${tmpURL}/WithFlags/${tmpFlags}`\n }\n return tmpURL;\n }\n else\n {\n return false;\n }\n\t};\n\n\tvar Delete = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpIDRecord = getIDRecord(pParameters);\n\n if (!tmpIDRecord)\n {\n return false;\n }\n\n\t\treturn `${tmpTableName}/${tmpIDRecord}`;\n\t};\n\n\tvar Count = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\n let tmpCountQuery = `${tmpTableName}s/Count`;\n\n if (tmpWhere)\n {\n return `${tmpTableName}s/Count/FilteredTo/${tmpWhere}`;\n }\n\n return tmpCountQuery;\n\t};\n\n\tvar tmpDialect = ({\n\t\tCreate: Create,\n\t\tRead: Read,\n\t\tUpdate: Update,\n\t\tDelete: Delete,\n\t\tCount: Count\n\t});\n\n\t/**\n\t * Dialect Name\n\t *\n\t * @property name\n\t * @type string\n\t */\n\tObject.defineProperty(tmpDialect, 'name',\n\t\t{\n\t\t\tget: function() { return 'MeadowEndpoints'; },\n\t\t\tenumerable: true\n\t\t});\n\n\treturn tmpDialect;\n};\n\nmodule.exports = FoxHoundDialectMeadowEndpoints;\n\n},{}],8:[function(require,module,exports){\n/**\n* FoxHound MySQL Dialect\n*\n* @license MIT\n*\n* For a MySQL query override:\n// An underscore template with the following values:\n// <%= DataElements %> = Field1, Field2, Field3, Field4\n// <%= Begin %> = 0\n// <%= Cap %> = 10\n// <%= Filter %> = WHERE StartDate > :MyStartDate\n// <%= Sort %> = ORDER BY Field1\n// The values are empty strings if they aren't set.\n*\n* @author Steven Velozo <steven@velozo.com>\n* @class FoxHoundDialectMySQL\n*/\n\nvar FoxHoundDialectMySQL = function(pFable)\n{\n\t//Request time from SQL server with microseconds resolution\n\tconst SQL_NOW = \"NOW(3)\";\n\n\t_Fable = pFable;\n\n\t/**\n\t* Generate a table name from the scope\n\t*\n\t* @method: generateTableName\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateTableName = function(pParameters)\n\t{\n\t\tif (pParameters.scope && pParameters.scope.indexOf('`') >= 0)\n\t\t\treturn ' '+pParameters.scope+'';\n\t\telse\n\t\t\treturn ' `'+pParameters.scope+'`';\n\t};\n\n\t/**\n\t* Generate a field list from the array of dataElements\n\t*\n\t* Each entry in the dataElements is a simple string\n\t*\n\t* @method: generateFieldList\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @param {Boolean} pIsForCountClause (optional) If true, generate fields for use within a count clause.\n\t* @return: {String} Returns the field list clause, or empty string if explicit fields are requested but cannot be fulfilled\n\t* due to missing schema.\n\t*/\n\tvar generateFieldList = function(pParameters, pIsForCountClause)\n\t{\n\t\tvar tmpDataElements = pParameters.dataElements;\n\t\tif (!Array.isArray(tmpDataElements) || tmpDataElements.length < 1)\n\t\t{\n\t\t\tconst tmpTableName = generateTableName(pParameters);\n\t\t\tif (!pIsForCountClause)\n\t\t\t{\n\t\t\t\treturn tmpTableName + '.*';\n\t\t\t}\n\t\t\t// we need to list all of the table fields explicitly; get them from the schema\n\t\t\tconst tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\t\t\tif (tmpSchema.length < 1)\n\t\t\t{\n\t\t\t\t// this means we have no schema; returning an empty string here signals the calling code to handle this case\n\t\t\t\treturn '';\n\t\t\t}\n\t\t\tconst idColumn = tmpSchema.find((entry) => entry.Type === 'AutoIdentity');\n\t\t\tif (!idColumn)\n\t\t\t{\n\t\t\t\t// this means there is no autoincrementing unique ID column; treat as above\n\t\t\t\treturn '';\n\t\t\t}\n\t\t\tconst qualifiedIDColumn = `${tmpTableName}.${idColumn.Column}`;\n\t\t\treturn ` ${generateSafeFieldName(qualifiedIDColumn)}`;\n\t\t}\n\n\t\tvar tmpFieldList = ' ';\n\t\tfor (var i = 0; i < tmpDataElements.length; i++)\n\t\t{\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\ttmpFieldList += ', ';\n\t\t\t}\n\t\t\tif (Array.isArray(tmpDataElements[i]))\n\t\t\t{\n\t\t\t\ttmpFieldList += generateSafeFieldName(tmpDataElements[i][0]);\n\t\t\t\tif (tmpDataElements[i].length > 1 && tmpDataElements[i][1])\n\t\t\t\t{\n\t\t\t\t\ttmpFieldList += \" AS \" + generateSafeFieldName(tmpDataElements[i][1]);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpFieldList += generateSafeFieldName(tmpDataElements[i]);\n\t\t\t}\n\t\t}\n\t\treturn tmpFieldList;\n\t};\n\n\tconst SURROUNDING_QUOTES_AND_WHITESPACE_REGEX = /^[` ]+|[` ]+$/g;\n\n\tconst cleanseQuoting = (str) =>\n\t{\n\t\treturn str.replace(SURROUNDING_QUOTES_AND_WHITESPACE_REGEX, '');\n\t};\n\n\t/**\n\t* Ensure a field name is properly escaped.\n\t*/\n\tvar generateSafeFieldName = function(pFieldName)\n\t{\n\t\tlet pFieldNames = pFieldName.split('.');\n\t\tif (pFieldNames.length > 1)\n\t\t{\n\t\t\tconst cleansedFieldName = cleanseQuoting(pFieldNames[1]);\n\t\t\tif (cleansedFieldName === '*')\n\t\t\t{\n\t\t\t\t// do not put * as `*`\n\t\t\t\treturn \"`\" + cleanseQuoting(pFieldNames[0]) + \"`.*\";\n\t\t\t}\n\t\t\treturn \"`\" + cleanseQuoting(pFieldNames[0]) + \"`.`\" + cleansedFieldName + \"`\";\n\t\t}\n\t\tconst cleansedFieldName = cleanseQuoting(pFieldNames[0]);\n\t\tif (cleansedFieldName === '*')\n\t\t{\n\t\t\t// do not put * as `*`\n\t\t\treturn '*';\n\t\t}\n\t\treturn \"`\" + cleanseQuoting(pFieldNames[0]) + \"`\";\n\t}\n\n\t/**\n\t* Generate a query from the array of where clauses\n\t*\n\t* Each clause is an object like:\n\t\t{\n\t\t\tColumn:'Name',\n\t\t\tOperator:'EQ',\n\t\t\tValue:'John',\n\t\t\tConnector:'And',\n\t\t\tParameter:'Name'\n\t\t}\n\t*\n\t* @method: generateWhere\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the WHERE clause prefixed with WHERE, or an empty string if unnecessary\n\t*/\n\tvar generateWhere = function(pParameters)\n\t{\n\t\tvar tmpFilter = Array.isArray(pParameters.filter) ? pParameters.filter : [];\n\t\tvar tmpTableName = generateTableName(pParameters);\n\n\t\tif (!pParameters.query.disableDeleteTracking)\n\t\t{\n\t\t\t// Check if there is a Deleted column on the Schema. If so, we add this to the filters automatically (if not already present)\n\t\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\tvar tmpSchemaEntry = tmpSchema[i];\n\n\t\t\t\tif (tmpSchemaEntry.Type === 'Deleted')\n\t\t\t\t{\n\t\t\t\t\tvar tmpHasDeletedParameter = false;\n\n\t\t\t\t\t//first, check to see if filters are already looking for Deleted column\n\t\t\t\t\tif (tmpFilter.length > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (var x = 0; x < tmpFilter.length; x++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (tmpFilter[x].Column === tmpSchemaEntry.Column)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttmpHasDeletedParameter = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (!tmpHasDeletedParameter)\n\t\t\t\t\t{\n\t\t\t\t\t\t//if not, we need to add it\n\t\t\t\t\t\ttmpFilter.push(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tColumn: tmpTableName + '.' + tmpSchemaEntry.Column,\n\t\t\t\t\t\t\tOperator: '=',\n\t\t\t\t\t\t\tValue: 0,\n\t\t\t\t\t\t\tConnector: 'AND',\n\t\t\t\t\t\t\tParameter: 'Deleted'\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (tmpFilter.length < 1)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpWhere = ' WHERE';\n\n\t\t// This is used to disable the connectors for subsequent queries.\n\t\t// Only the open parenthesis operator uses this, currently.\n\t\tvar tmpLastOperatorNoConnector = false;\n\n\t\tfor (var i = 0; i < tmpFilter.length; i++)\n\t\t{\n\t\t\tif ((tmpFilter[i].Connector != 'NONE') && (tmpFilter[i].Operator != ')') && (tmpWhere != ' WHERE') && (tmpLastOperatorNoConnector == false))\n\t\t\t{\n\t\t\t\ttmpWhere += ' '+tmpFilter[i].Connector;\n\t\t\t}\n\n\t\t\ttmpLastOperatorNoConnector = false;\n\n\t\t\tvar tmpColumnParameter;\n\n\t\t\tif (tmpFilter[i].Operator === '(')\n\t\t\t{\n\t\t\t\t// Open a logical grouping\n\t\t\t\ttmpWhere += ' (';\n\t\t\t\ttmpLastOperatorNoConnector = true;\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === ')')\n\t\t\t{\n\t\t\t\t// Close a logical grouping\n\t\t\t\ttmpWhere += ' )';\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IN' || tmpFilter[i].Operator === \"NOT IN\")\n\t\t\t{\n\t\t\t\ttmpColumnParameter = tmpFilter[i].Parameter+'_w'+i;\n\t\t\t\t// Add the column name, operator and parameter name to the list of where value parenthetical\n\t\t\t\ttmpWhere += ' '+tmpFilter[i].Column+' '+tmpFilter[i].Operator+' ( :'+tmpColumnParameter+' )';\n\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = tmpFilter[i].Value;\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IS NULL')\n\t\t\t{\n\t\t\t\t// IS NULL is a special operator which doesn't require a value, or parameter\n\t\t\t\ttmpWhere += ' '+tmpFilter[i].Column+' '+tmpFilter[i].Operator;\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IS NOT NULL')\n\t\t\t{\n\t\t\t\t// IS NOT NULL is a special operator which doesn't require a value, or parameter\n\t\t\t\ttmpWhere += ' '+tmpFilter[i].Column+' '+tmpFilter[i].Operator;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpColumnParameter = tmpFilter[i].Parameter+'_w'+i;\n\t\t\t\t// Add the column name, operator and parameter name to the list of where value parenthetical\n\t\t\t\ttmpWhere += ' '+tmpFilter[i].Column+' '+tmpFilter[i].Operator+' :'+tmpColumnParameter;\n\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = tmpFilter[i].Value;\n\t\t\t}\n\t\t}\n\n\t\treturn tmpWhere;\n\t};\n\n\t/**\n\t* Generate an ORDER BY clause from the sort array\n\t*\n\t* Each entry in the sort is an object like:\n\t* {Column:'Color',Direction:'Descending'}\n\t*\n\t* @method: generateOrderBy\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the field list clause\n\t*/\n\tvar generateOrderBy = function(pParameters)\n\t{\n\t\tvar tmpOrderBy = pParameters.sort;\n\t\tif (!Array.isArray(tmpOrderBy) || tmpOrderBy.length < 1)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpOrderClause = ' ORDER BY';\n\t\tfor (var i = 0; i < tmpOrderBy.length; i++)\n\t\t{\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\ttmpOrderClause += ',';\n\t\t\t}\n\t\t\ttmpOrderClause += ' '+tmpOrderBy[i].Column;\n\n\t\t\tif (tmpOrderBy[i].Direction == 'Descending')\n\t\t\t{\n\t\t\t\ttmpOrderClause += ' DESC';\n\t\t\t}\n\t\t}\n\t\treturn tmpOrderClause;\n\t};\n\n\t/**\n\t* Generate the limit clause\n\t*\n\t* @method: generateLimit\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateLimit = function(pParameters)\n\t{\n\t\tif (!pParameters.cap)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpLimit = ' LIMIT';\n\t\t// If there is a begin record, we'll pass that in as well.\n\t\tif (pParameters.begin !== false)\n\t\t{\n\t\t\ttmpLimit += ' ' + pParameters.begin + ',';\n\t\t}\n\t\t// Cap is required for a limit clause.\n\t\ttmpLimit += ' ' + pParameters.cap;\n\n\t\treturn tmpLimit;\n\t};\n\n\t/**\n\t* Generate the join clause\n\t*\n\t* @method: generateJoins\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the join clause\n\t*/\n\tvar generateJoins = function(pParameters)\n\t{\n\t\tvar tmpJoins = pParameters.join;\n\t\tif (!Array.isArray(tmpJoins) || tmpJoins.length < 1)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpJoinClause = ''; //ex. ' INNER JOIN';\n\t\tfor (var i = 0; i < tmpJoins.length; i++)\n\t\t{\n\t\t\tvar join = tmpJoins[i];\n\t\t\t//verify that all required fields are valid\n\t\t\tif (join.Type && join.Table && join.From && join.To)\n\t\t\t{\n\t\t\t\ttmpJoinClause += ` ${join.Type} ${join.Table} ON ${join.From} = ${join.To}`;\n\t\t\t}\n\t\t}\n\n\t\treturn tmpJoinClause;\n\t}\n\n\t/**\n\t* Generate the update SET clause\n\t*\n\t* @method: generateUpdateSetters\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateUpdateSetters = function(pParameters)\n\t{\n\t\tvar tmpRecords = pParameters.query.records;\n\t\t// We need to tell the query not to generate improperly if there are no values to set.\n\t\tif (!Array.isArray(tmpRecords) || tmpRecords.length < 1)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpUpdate = '';\n\t\t// If there is more than one record in records, we are going to ignore them for now.\n\t\tvar tmpCurrentColumn = 0;\n\t\tfor(var tmpColumn in tmpRecords[0])\n\t\t{\n\t\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\t\tvar tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\tif (tmpColumn == tmpSchema[i].Column)\n\t\t\t\t{\n\t\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\t\ttmpSchemaEntry = tmpSchema[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (pParameters.query.disableAutoDateStamp &&\n\t\t\t\ttmpSchemaEntry.Type === 'UpdateDate')\n\t\t\t{\n\t\t\t\t// This is ignored if flag is set\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (pParameters.query.disableAutoUserStamp &&\n\t\t\t\ttmpSchemaEntry.Type === 'UpdateIDUser')\n\t\t\t{\n\t\t\t\t// This is ignored if flag is set\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'AutoIdentity':\n\t\t\t\tcase 'CreateDate':\n\t\t\t\tcase 'CreateIDUser':\n\t\t\t\tcase 'DeleteDate':\n\t\t\t\tcase 'DeleteIDUser':\n\t\t\t\t\t// These are all ignored on update\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpUpdate += ',';\n\t\t\t}\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\ttmpUpdate += ' '+tmpColumn+' = ' + SQL_NOW;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateIDUser':\n\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\tvar tmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdate += ' '+tmpColumn+' = :'+tmpColumnParameter;\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tvar tmpColumnDefaultParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdate += ' '+tmpColumn+' = :'+tmpColumnDefaultParameter;\n\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnDefaultParameter] = tmpRecords[0][tmpColumn];\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// We use a number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (tmpUpdate === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpUpdate;\n\t};\n\n\t/**\n\t* Generate the update-delete SET clause\n\t*\n\t* @method: generateUpdateDeleteSetters\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateUpdateDeleteSetters = function(pParameters)\n\t{\n\t\tif (pParameters.query.disableDeleteTracking)\n\t\t{\n\t\t\t//Don't generate an UPDATE query if Delete tracking is disabled\n\t\t\treturn false;\n\t\t}\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpCurrentColumn = 0;\n\t\tvar tmpHasDeletedField = false;\n\t\tvar tmpUpdate = '';\n\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\tvar tmpSchemaEntry = {Type:'Default'};\n\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t{\n\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\ttmpSchemaEntry = tmpSchema[i];\n\n\t\t\tvar tmpUpdateSql = null;\n\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'Deleted':\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = 1';\n\t\t\t\t\ttmpHasDeletedField = true; //this field is required in order for query to be built\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'DeleteDate':\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = ' + SQL_NOW;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\t\t// Delete operation is an Update, so we should stamp the update time\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = ' + SQL_NOW;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'DeleteIDUser':\n\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\tvar tmpColumnParameter = tmpSchemaEntry.Column+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = :'+tmpColumnParameter;\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t//DON'T allow update of other fields in this query\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpUpdate += ',';\n\t\t\t}\n\n\t\t\ttmpUpdate += tmpUpdateSql;\n\n\t\t\t// We use a number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (!tmpHasDeletedField ||\n\t\t\ttmpUpdate === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpUpdate;\n\t};\n\n\t/**\n\t* Generate the update-undelete SET clause\n\t*\n\t* @method: generateUpdateUndeleteSetters\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateUpdateUndeleteSetters = function(pParameters)\n\t{\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpCurrentColumn = 0;\n\t\tvar tmpHasDeletedField = false;\n\t\tvar tmpUpdate = '';\n\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\tvar tmpSchemaEntry = {Type:'Default'};\n\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t{\n\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\ttmpSchemaEntry = tmpSchema[i];\n\n\t\t\tvar tmpUpdateSql = null;\n\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'Deleted':\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = 0';\n\t\t\t\t\ttmpHasDeletedField = true; //this field is required in order for query to be built\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\t\t// The undelete operation is an Update, so we should stamp the update time\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = ' + SQL_NOW;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateIDUser':\n\t\t\t\t\tvar tmpColumnParameter = tmpSchemaEntry.Column+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = :'+tmpColumnParameter;\n\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t//DON'T allow update of other fields in this query\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpUpdate += ',';\n\t\t\t}\n\n\t\t\ttmpUpdate += tmpUpdateSql;\n\n\t\t\t// We use a number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (!tmpHasDeletedField ||\n\t\t\ttmpUpdate === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpUpdate;\n\t};\n\n\t/**\n\t* Generate the create SET clause\n\t*\n\t* @method: generateCreateSetList\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateCreateSetValues = function(pParameters)\n\t{\n\t\tvar tmpRecords = pParameters.query.records;\n\t\t// We need to tell the query not to generate improperly if there are no values to set.\n\t\tif (!Array.isArray(tmpRecords) || tmpRecords.length < 1)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\n\t\tvar tmpCreateSet = '';\n\t\t// If there is more than one record in records, we are going to ignore them for now.\n\t\tvar tmpCurrentColumn = 0;\n\t\tfor(var tmpColumn in tmpRecords[0])\n\t\t{\n\t\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\t\tvar tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\tif (tmpColumn == tmpSchema[i].Column)\n\t\t\t\t{\n\t\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\t\ttmpSchemaEntry = tmpSchema[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!pParameters.query.disableDeleteTracking)\n\t\t\t{\n\t\t\t\tif (tmpSchemaEntry.Type === 'DeleteDate' ||\n\t\t\t\t\ttmpSchemaEntry.Type === 'DeleteIDUser')\n\t\t\t\t{\n\t\t\t\t\t// These are all ignored on insert (if delete tracking is enabled as normal)\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpCreateSet += ',';\n\t\t\t}\n\n\t\t\t//define a re-usable method for setting up field definitions in a default pattern\n\t\t\tvar buildDefaultDefinition = function()\n\t\t\t{\n\t\t\t\tvar tmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\ttmpCreateSet += ' :'+tmpColumnParameter;\n\t\t\t\t// Set the query parameter\n\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = tmpRecords[0][tmpColumn];\n\t\t\t};\n\n\t\t\tvar tmpColumnParameter;\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'AutoIdentity':\n\t\t\t\t\tif (pParameters.query.disableAutoIdentity)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\t\ttmpCreateSet += ' NULL';\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'AutoGUID':\n\t\t\t\t\tif (pParameters.query.disableAutoIdentity)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse if (tmpRecords[0][tmpColumn] &&\n\t\t\t\t\t\t\ttmpRecords[0][tmpColumn].length >= 5 &&\n\t\t\t\t\t\t\ttmpRecords[0][tmpColumn] !== '0x0000000000000000') //stricture default\n\t\t\t\t\t{\n\t\t\t\t\t\t// Allow consumer to override AutoGUID\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\t\ttmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\t\ttmpCreateSet += ' :'+tmpColumnParameter;\n\t\t\t\t\t\t// Set the query parameter\n\t\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.UUID;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\tcase 'CreateDate':\n\t\t\t\tcase 'DeleteDate':\n\t\t\t\t\tif (pParameters.query.disableAutoDateStamp)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\t\ttmpCreateSet += ' ' + SQL_NOW;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'DeleteIDUser':\n\t\t\t\tcase 'UpdateIDUser':\n\t\t\t\tcase 'CreateIDUser':\n\t\t\t\t\tif (pParameters.query.disableAutoUserStamp)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\t\ttmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\t\ttmpCreateSet += ' :'+tmpColumnParameter;\n\t\t\t\t\t\t// Set the query parameter\n\t\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// We use an appended number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (tmpCreateSet === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpCreateSet;\n\t};\n\n\t/**\n\t* Generate the create SET clause\n\t*\n\t* @method: generateCreateSetList\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateCreateSetList = function(pParameters)\n\t{\n\t\t// The records were already validated by generateCreateSetValues\n\t\tvar tmpRecords = pParameters.query.records;\n\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpCreateSet = '';\n\t\t// If there is more than one record in records, we are going to ignore them for now.\n\t\tfor(var tmpColumn in tmpRecords[0])\n\t\t{\n\t\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\t\tvar tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\tif (tmpColumn == tmpSchema[i].Column)\n\t\t\t\t{\n\t\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\t\ttmpSchemaEntry = tmpSchema[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!pParameters.query.disableDeleteTracking)\n\t\t\t{\n\t\t\t\tif (tmpSchemaEntry.Type === 'DeleteDate' ||\n\t\t\t\t\ttmpSchemaEntry.Type === 'DeleteIDUser')\n\t\t\t\t{\n\t\t\t\t\t// These are all ignored on insert (if delete tracking is enabled as normal)\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tdefault:\n\t\t\t\t\tif (tmpCreateSet != '')\n\t\t\t\t\t{\n\t\t\t\t\t\ttmpCreateSet += ',';\n\t\t\t\t\t}\n\t\t\t\t\ttmpCreateSet += ' '+tmpColumn;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn tmpCreateSet;\n\t};\n\n\n\tvar Create = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpCreateSetList = generateCreateSetList(pParameters);\n\t\tvar tmpCreateSetValues = generateCreateSetValues(pParameters);\n\n\t\tif (!tmpCreateSetValues)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn 'INSERT INTO'+tmpTableName+' ('+tmpCreateSetList+') VALUES ('+tmpCreateSetValues+');';\n\t};\n\n\n\t/**\n\t* Read one or many records\n\t*\n\t* Some examples:\n\t* SELECT * FROM WIDGETS;\n\t* SELECT * FROM WIDGETS LIMIT 0, 20;\n\t* SELECT * FROM WIDGETS LIMIT 5, 20;\n\t* SELECT ID, Name, Cost FROM WIDGETS LIMIT 5, 20;\n\t* SELECT ID, Name, Cost FROM WIDGETS LIMIT 5, 20 WHERE LastName = 'Smith';\n\t*\n\t* @method Read\n\t* @param {Object} pParameters SQL Query parameters\n\t* @return {String} Returns the current Query for chaining.\n\t*/\n\tvar Read = function(pParameters)\n\t{\n\t\tvar tmpFieldList = generateFieldList(pParameters);\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpJoin = generateJoins(pParameters);\n\t\tvar tmpOrderBy = generateOrderBy(pParameters);\n\t\tvar tmpLimit = generateLimit(pParameters);\n\t\tconst tmpOptDistinct = pParameters.distinct ? ' DISTINCT' : '';\n\n\t\tif (pParameters.queryOverride)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tvar tmpQueryTemplate = _Fable.Utility.template(pParameters.queryOverride);\n\t\t\t\treturn tmpQueryTemplate({FieldList:tmpFieldList, TableName:tmpTableName, Where:tmpWhere, Join:tmpJoin, OrderBy:tmpOrderBy, Limit:tmpLimit, Distinct: tmpOptDistinct, _Params: pParameters});\n\t\t\t}\n\t\t\tcatch (pError)\n\t\t\t{\n\t\t\t\t// This pokemon is here to give us a convenient way of not throwing up totally if the query fails.\n\t\t\t\tconsole.log('Error with custom Read Query ['+pParameters.queryOverride+']: '+pError);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn `SELECT${tmpOptDistinct}${tmpFieldList} FROM${tmpTableName}${tmpJoin}${tmpWhere}${tmpOrderBy}${tmpLimit};`;\n\t};\n\n\tvar Update = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpUpdateSetters = generateUpdateSetters(pParameters);\n\n\t\tif (!tmpUpdateSetters)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn 'UPDATE'+tmpTableName+' SET'+tmpUpdateSetters+tmpWhere+';';\n\t};\n\n\tvar Delete = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpUpdateDeleteSetters = generateUpdateDeleteSetters(pParameters);\n\n\t\tif (tmpUpdateDeleteSetters)\n\t\t{\n\t\t\t//If it has a deleted bit, update it instead of actually deleting the record\n\t\t\treturn 'UPDATE'+tmpTableName+' SET'+tmpUpdateDeleteSetters+tmpWhere+';';\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn 'DELETE FROM'+tmpTableName+tmpWhere+';';\n\t\t}\n\t};\n\n\tvar Undelete = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\t// TODO: Fix these\n\t\tlet tmpDeleteTrackingState = pParameters.query.disableDeleteTracking;\n\t\tpParameters.query.disableDeleteTracking = true;\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpUpdateUndeleteSetters = generateUpdateUndeleteSetters(pParameters);\n\t\tpParameters.query.disableDeleteTracking = tmpDeleteTrackingState;\n\n\t\tif (tmpUpdateUndeleteSetters)\n\t\t{\n\t\t\t//If the table has a deleted bit, go forward with the update to change things.\n\t\t\treturn 'UPDATE'+tmpTableName+' SET'+tmpUpdateUndeleteSetters+tmpWhere+';';\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// This is a no-op because the record can't be undeleted.\n\t\t\t// TODO: Should it throw instead?\n\t\t\treturn 'SELECT NULL;';\n\t\t}\n\t};\n\n\tvar Count = function(pParameters)\n\t{\n\t\tvar tmpFieldList = pParameters.distinct ? generateFieldList(pParameters, true) : '*';\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpJoin = generateJoins(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\t// here, we ignore the distinct keyword if no fields have been specified and\n\t\tif (pParameters.distinct && tmpFieldList.length < 1)\n\t\t{\n\t\t\tconsole.warn('Distinct requested but no field list or schema are available, so not honoring distinct for count query.');\n\t\t}\n\t\tconst tmpOptDistinct = pParameters.distinct && tmpFieldList.length > 0 ? 'DISTINCT' : '';\n\n\t\tif (pParameters.queryOverride)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tvar tmpQueryTemplate = _Fable.Utility.template(pParameters.queryOverride);\n\t\t\t\treturn tmpQueryTemplate({FieldList:[], TableName:tmpTableName, Where:tmpWhere, OrderBy:'', Limit:'', Distinct: tmpOptDistinct, _Params: pParameters});\n\t\t\t}\n\t\t\tcatch (pError)\n\t\t\t{\n\t\t\t\t// This pokemon is here to give us a convenient way of not throwing up totally if the query fails.\n\t\t\t\tconsole.log('Error with custom Count Query ['+pParameters.queryOverride+']: '+pError);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn `SELECT COUNT(${tmpOptDistinct}${tmpFieldList || '*'}) AS RowCount FROM${tmpTableName}${tmpJoin}${tmpWhere};`;\n\t};\n\n\tvar tmpDialect = ({\n\t\tCreate: Create,\n\t\tRead: Read,\n\t\tUpdate: Update,\n\t\tDelete: Delete,\n\t\tUndelete: Undelete,\n\t\tCount: Count\n\t});\n\n\t/**\n\t* Dialect Name\n\t*\n\t* @property name\n\t* @type string\n\t*/\n\tObject.defineProperty(tmpDialect, 'name',\n\t\t{\n\t\t\tget: function() { return 'MySQL'; },\n\t\t\tenumerable: true\n\t\t});\n\n\treturn tmpDialect;\n};\n\nmodule.exports = FoxHoundDialectMySQL;\n\n},{}]},{},[1])(1)\n});\n\n","getDialects = () =>\n{\n\tlet tmpDialects = {};\n\n\ttmpDialects.ALASQL = require('./dialects/ALASQL/FoxHound-Dialect-ALASQL.js');\n\ttmpDialects.English = require('./dialects/English/FoxHound-Dialect-English.js');\n\ttmpDialects.MeadowEndpoints = require('./dialects/MeadowEndpoints/FoxHound-Dialect-MeadowEndpoints.js');\n\ttmpDialects.MySQL = require('./dialects/MySQL/FoxHound-Dialect-MySQL.js');\n\n\ttmpDialects.default = tmpDialects.English;\n\n\treturn tmpDialects;\n}\n\nmodule.exports = getDialects();","/**\n* FoxHound Query Generation Library\n* @license MIT\n* @author Steven Velozo <steven@velozo.com>\n*/\n\n// Load our base parameters skeleton object\nconst baseParameters = require('./Parameters.js');\n\nvar FoxHound = function()\n{\n\tfunction createNew(pFable, pFromParameters)\n\t{\n\t\t// If a valid Fable object isn't passed in, return a constructor\n\t\tif ((typeof(pFable) !== 'object') || !('fable' in pFable))\n\t\t{\n\t\t\treturn {new: createNew};\n\t\t}\n\n\t\tvar _Fable = pFable;\n\n\t\t// The default parameters config object, used as a template for all new\n\t\t// queries created from this query.\n\t\tvar _DefaultParameters = (typeof(pFromParameters) === 'undefined') ? {} : pFromParameters;\n\n\t\t// The parameters config object for the current query. This is the only\n\t\t// piece of internal state that is important to operation.\n\t\tvar _Parameters = false;\n\n\t\tvar _Dialects = require('./Foxhound-Dialects.js');\n\n\t\t// The unique identifier for a query\n\t\tvar _UUID = _Fable.getUUID();\n\n\t\t// The log level, for debugging chattiness.\n\t\tvar _LogLevel = 0;\n\n\t\t// The dialect to use when generating queries\n\t\tvar _Dialect = false;\n\n\t\t/**\n\t\t* Clone the current FoxHound Query into a new Query object, copying all\n\t\t* parameters as the new default. Clone also copies the log level.\n\t\t*\n\t\t* @method clone\n\t\t* @return {Object} Returns a cloned Query. This is still chainable.\n\t\t*/\n\t\tvar clone = function()\n\t\t{\n\t\t\tvar tmpFoxHound = createNew(_Fable, baseParameters)\n\t\t\t\t.setScope(_Parameters.scope)\n\t\t\t\t.setBegin(_Parameters.begin)\n\t\t\t\t.setCap(_Parameters.cap);\n\n\t\t\t// Schema is the only part of a query that carries forward.\n\t\t\ttmpFoxHound.query.schema = _Parameters.query.schema;\n\n\t\t\tif (_Parameters.dataElements)\n\t\t\t{\n\t\t\t\ttmpFoxHound.parameters.dataElements = _Parameters.dataElements.slice(); // Copy the array of dataElements\n\t\t\t}\n\t\t\tif (_Parameters.sort)\n\t\t\t{\n\t\t\t\ttmpFoxHound.parameters.sort = _Parameters.sort.slice(); // Copy the sort array.\n\t\t\t\t// TODO: Fix the side affect nature of these being objects in the array .. they are technically clones of the previous.\n\t\t\t}\n\t\t\tif (_Parameters.filter)\n\t\t\t{\n\t\t\t\ttmpFoxHound.parameters.filter = _Parameters.filter.slice(); // Copy the filter array.\n\t\t\t\t// TODO: Fix the side affect nature of these being objects in the array .. they are technically clones of the previous.\n\t\t\t}\n\n\t\t\treturn tmpFoxHound;\n\t\t};\n\n\n\t\t/**\n\t\t* Reset the parameters of the FoxHound Query to the Default. Default\n\t\t* parameters were set during object construction.\n\t\t*\n\t\t* @method resetParameters\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar resetParameters = function()\n\t\t{\n\t\t\t_Parameters = _Fable.Utility.extend({}, baseParameters, _DefaultParameters);\n\t\t\t_Parameters.query = ({\n\t\t\t\tdisableAutoIdentity: false,\n\t\t\t\tdisableAutoDateStamp: false,\n\t\t\t\tdisableAutoUserStamp: false,\n\t\t\t\tdisableDeleteTracking: false,\n\t\t\t\tbody: false,\n\t\t\t\tschema: false, // The schema to intersect with our records\n\t\t\t\tIDUser: 0, // The user to stamp into records\n\t\t\t\tUUID: _Fable.getUUID(), // A UUID for this record\n\t\t\t\trecords: false, // The records to be created or changed\n\t\t\t\tparameters: {}\n\t\t\t});\n\n\t\t\t_Parameters.result = ({\n\t\t\t\texecuted: false, // True once we've run a query.\n\t\t\t\tvalue: false, // The return value of the last query run\n\t\t\t\terror: false // The error message of the last run query\n\t\t\t});\n\n\t\t\treturn this;\n\t\t};\n\t\tresetParameters();\n\n\t\t/**\n\t\t* Reset the parameters of the FoxHound Query to the Default. Default\n\t\t* parameters were set during object construction.\n\t\t*\n\t\t* @method mergeParameters\n\t\t* @param {Object} pFromParameters A Parameters Object to merge from\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar mergeParameters = function(pFromParameters)\n\t\t{\n\t\t\t_Parameters = _Fable.Utility.extend({}, _Parameters, pFromParameters);\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the the Logging level.\n\t\t*\n\t\t* The log levels are:\n\t\t* 0 - Don't log anything\n\t\t* 1 - Log queries\n\t\t* 2 - Log queries and non-parameterized queries\n\t\t* 3 - Log everything\n\t\t*\n\t\t* @method setLogLevel\n\t\t* @param {Number} pLogLevel The log level for our object\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setLogLevel = function(pLogLevel)\n\t\t{\n\t\t\tvar tmpLogLevel = 0;\n\n\t\t\tif (typeof(pLogLevel) === 'number' && (pLogLevel % 1) === 0)\n\t\t\t{\n\t\t\t\ttmpLogLevel = pLogLevel;\n\t\t\t}\n\n\t\t\t_LogLevel = tmpLogLevel;\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the Scope for the Query. *Scope* is the source for the data being\n\t\t* pulled. In TSQL this would be the _table_, whereas in MongoDB this\n\t\t* would be the _collection_.\n\t\t*\n\t\t* A scope can be either a string, or an array (for JOINs and such).\n\t\t*\n\t\t* @method setScope\n\t\t* @param {String} pScope A Scope for the Query.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setScope = function(pScope)\n\t\t{\n\t\t\tvar tmpScope = false;\n\n\t\t\tif (typeof(pScope) === 'string')\n\t\t\t{\n\t\t\t\ttmpScope = pScope;\n\t\t\t}\n\t\t\telse if (pScope !== false)\n\t\t\t{\n\t\t\t\t_Fable.log.error('Scope set failed. You must pass in a string or array.', {queryUUID:_UUID, parameters:_Parameters, invalidScope:pScope});\n\t\t\t}\n\n\t\t\t_Parameters.scope = tmpScope;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Scope set: '+tmpScope, {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\t\t/**\n\t\t* Set whether the query returns DISTINCT results.\n\t\t* For count queries, returns the distinct for the selected fields, or all fields in the base table by default.\n\t\t*\n\t\t* @method setDistinct\n\t\t* @param {Boolean} pDistinct True if the query should be distinct.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setDistinct = function(pDistinct)\n\t\t{\n\t\t\t_Parameters.distinct = !!pDistinct;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Distinct set: '+_Parameters.distinct, {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the Data Elements for the Query. *Data Elements* are the fields\n\t\t* being pulled by the query. In TSQL this would be the _columns_,\n\t\t* whereas in MongoDB this would be the _fields_.\n\t\t*\n\t\t* The passed values can be either a string, or an array.\n\t\t*\n\t\t* @method setDataElements\n\t\t* @param {String} pDataElements The Data Element(s) for the Query.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setDataElements = function(pDataElements)\n\t\t{\n\t\t\tvar tmpDataElements = false;\n\n\t\t\tif (Array.isArray(pDataElements))\n\t\t\t{\n\t\t\t\t// TODO: Check each entry of the array are all strings\n\t\t\t\ttmpDataElements = pDataElements;\n\t\t\t}\n\t\t\tif (typeof(pDataElements) === 'string')\n\t\t\t{\n\t\t\t\ttmpDataElements = [pDataElements];\n\t\t\t}\n\n\t\t\t_Parameters.dataElements = tmpDataElements;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Data Elements set', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the sort data element\n\t\t*\n\t\t* The passed values can be either a string, an object or an array of objects.\n\t\t*\n\t\t* The Sort object has two values:\n\t\t* {Column:'Birthday', Direction:'Ascending'}\n\t\t*\n\t\t* @method setSort\n\t\t* @param {String} pSort The sort criteria(s) for the Query.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setSort = function(pSort)\n\t\t{\n\t\t\tvar tmpSort = false;\n\n\t\t\tif (Array.isArray(pSort))\n\t\t\t{\n\t\t\t\t// TODO: Check each entry of the array are all conformant sort objects\n\t\t\t\ttmpSort = pSort;\n\t\t\t}\n\t\t\telse if (typeof(pSort) === 'string')\n\t\t\t{\n\t\t\t\t// Default to ascending\n\t\t\t\ttmpSort = [{Column:pSort, Direction:'Ascending'}];\n\t\t\t}\n\t\t\telse if (typeof(pSort) === 'object')\n\t\t\t{\n\t\t\t\t// TODO: Check that this sort entry conforms to a sort entry\n\t\t\t\ttmpSort = [pSort];\n\t\t\t}\n\n\t\t\t_Parameters.sort = tmpSort;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Sort set', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\t\t/**\n\t\t* Set the join data element\n\t\t*\n\t\t* The passed values can be either an object or an array of objects.\n\t\t*\n\t\t* The join object has four values:\n\t\t* {Type:'INNER JOIN', Table:'Test', From:'Test.ID', To:'Scope.IDItem'}\n\t\t*\n\t\t* @method setJoin\n\t\t* @param {Object} pJoin The join criteria(s) for the Query.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setJoin = function(pJoin)\n\t\t{\n\t\t\t_Parameters.join = [];\n\n\t\t\tif (Array.isArray(pJoin))\n\t\t\t{\n\t\t\t\tpJoin.forEach(function(join)\n\t\t\t\t{\n\t\t\t\t\taddJoin(join.Table, join.From, join.To, join.Type);\n\t\t\t\t});\n\t\t\t}\n\t\t\telse if (typeof(pJoin) === 'object')\n\t\t\t{\n\t\t\t\taddJoin(pJoin.Table, pJoin.From, pJoin.To, pJoin.Type);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Add a sort data element\n\t\t*\n\t\t* The passed values can be either a string, an object or an array of objects.\n\t\t*\n\t\t* The Sort object has two values:\n\t\t* {Column:'Birthday', Direction:'Ascending'}\n\t\t*\n\t\t* @method setSort\n\t\t* @param {String} pSort The sort criteria to add to the Query.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar addSort = function(pSort)\n\t\t{\n\t\t\tvar tmpSort = false;\n\n\t\t\tif (typeof(pSort) === 'string')\n\t\t\t{\n\t\t\t\t// Default to ascending\n\t\t\t\ttmpSort = {Column:pSort, Direction:'Ascending'};\n\t\t\t}\n\t\t\tif (typeof(pSort) === 'object')\n\t\t\t{\n\t\t\t\t// TODO: Check that this sort entry conforms to a sort entry\n\t\t\t\ttmpSort = pSort;\n\t\t\t}\n\n\t\t\tif (!_Parameters.sort)\n\t\t\t{\n\t\t\t\t_Parameters.sort = [];\n\t\t\t}\n\n\t\t\t_Parameters.sort.push(tmpSort);\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Sort set', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the the Begin index for the Query. *Begin* is the index at which\n\t\t* a query should start returning rows. In TSQL this would be the n\n\t\t* parameter of ```LIMIT 1,n```, whereas in MongoDB this would be the\n\t\t* n in ```skip(n)```.\n\t\t*\n\t\t* The passed value must be an Integer >= 0.\n\t\t*\n\t\t* @method setBegin\n\t\t* @param {Number} pBeginAmount The index to begin returning Query data.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setBegin = function(pBeginAmount)\n\t\t{\n\t\t\tvar tmpBegin = false;\n\n\t\t\t// Test if it is an integer > -1\n\t\t\t// http://jsperf.com/numbers-and-integers\n\t\t\tif (typeof(pBeginAmount) === 'number' && (pBeginAmount % 1) === 0 && pBeginAmount >= 0)\n\t\t\t{\n\t\t\t\ttmpBegin = pBeginAmount;\n\t\t\t}\n\t\t\telse if (pBeginAmount !== false)\n\t\t\t{\n\t\t\t\t_Fable.log.error('Begin set failed; non-positive or non-numeric argument.', {queryUUID:_UUID, parameters:_Parameters, invalidBeginAmount:pBeginAmount});\n\t\t\t}\n\n\t\t\t_Parameters.begin = tmpBegin;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Begin set: '+pBeginAmount, {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the the Cap for the Query. *Cap* is the maximum number of records\n\t\t* a Query should return in a set. In TSQL this would be the n\n\t\t* parameter of ```LIMIT n```, whereas in MongoDB this would be the\n\t\t* n in ```limit(n)```.\n\t\t*\n\t\t* The passed value must be an Integer >= 0.\n\t\t*\n\t\t* @method setCap\n\t\t* @param {Number} pCapAmount The maximum records for the Query set.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setCap = function(pCapAmount)\n\t\t{\n\t\t\tvar tmpCapAmount = false;\n\n\t\t\tif (typeof(pCapAmount) === 'number' && (pCapAmount % 1) === 0 && pCapAmount >= 0)\n\t\t\t{\n\t\t\t\ttmpCapAmount = pCapAmount;\n\t\t\t}\n\t\t\telse if (pCapAmount !== false)\n\t\t\t{\n\t\t\t\t_Fable.log.error('Cap set failed; non-positive or non-numeric argument.', {queryUUID:_UUID, parameters:_Parameters, invalidCapAmount:pCapAmount});\n\t\t\t}\n\n\n\t\t\t_Parameters.cap = tmpCapAmount;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Cap set to: '+tmpCapAmount, {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the filter expression\n\t\t*\n\t\t* The passed values can be either an object or an array of objects.\n\t\t*\n\t\t* The Filter object has a minimum of two values (which expands to the following):\n\t\t* {Column:'Name', Value:'John'}\n\t\t* {Column:'Name', Operator:'EQ', Value:'John', Connector:'And', Parameter:'Name'}\n\t\t*\n\t\t* @method setFilter\n\t\t* @param {String} pFilter The filter(s) for the Query.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setFilter = function(pFilter)\n\t\t{\n\t\t\tvar tmpFilter = false;\n\n\t\t\tif (Array.isArray(pFilter))\n\t\t\t{\n\t\t\t\t// TODO: Check each entry of the array are all conformant Filter objects\n\t\t\t\ttmpFilter = pFilter;\n\t\t\t}\n\t\t\telse if (typeof(pFilter) === 'object')\n\t\t\t{\n\t\t\t\t// TODO: Check that this Filter entry conforms to a Filter entry\n\t\t\t\ttmpFilter = [pFilter];\n\t\t\t}\n\n\t\t\t_Parameters.filter = tmpFilter;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Filter set', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\n\t\t/**\n\t\t* Add a filter expression\n\t\t*\n\t\t* {Column:'Name', Operator:'EQ', Value:'John', Connector:'And', Parameter:'Name'}\n\t\t*\n\t\t* @method addFilter\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar addFilter = function(pColumn, pValue, pOperator, pConnector, pParameter)\n\t\t{\n\t\t\tif (typeof(pColumn) !== 'string')\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid query filter column', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tif (typeof(pValue) === 'undefined')\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid query filter value', {queryUUID:_UUID, parameters:_Parameters, invalidColumn:pColumn});\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tvar tmpOperator = (typeof(pOperator) === 'undefined') ? '=' : pOperator;\n\t\t\tvar tmpConnector = (typeof(pConnector) === 'undefined') ? 'AND' : pConnector;\n\t\t\tvar tmpParameter = (typeof(pParameter) === 'undefined') ? pColumn : pParameter;\n\n\t\t\t//support table.field notation (mysql2 requires this)\n\t\t\ttmpParameter = tmpParameter.replace('.', '_');\n\n\t\t\tvar tmpFilter = (\n\t\t\t\t{\n\t\t\t\t\tColumn: pColumn,\n\t\t\t\t\tOperator: tmpOperator,\n\t\t\t\t\tValue: pValue,\n\t\t\t\t\tConnector: tmpConnector,\n\t\t\t\t\tParameter: tmpParameter\n\t\t\t\t});\n\n\t\t\tif (!Array.isArray(_Parameters.filter))\n\t\t\t{\n\t\t\t\t_Parameters.filter = [tmpFilter];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_Parameters.filter.push(tmpFilter);\n\t\t\t}\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Added a filter', {queryUUID:_UUID, parameters:_Parameters, newFilter:tmpFilter});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\t\t/**\n\t\t* Add a join expression\n\t\t*\n\t\t* {Type:'INNER JOIN', Table:'Test', From:'Test.ID', To:'Scope.IDItem'}\n\t\t*\n\t\t* @method addJoin\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar addJoin = function(pTable, pFrom, pTo, pType)\n\t\t{\n\t\t\tif (typeof(pTable) !== 'string')\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid query join table', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tif (typeof(pFrom) === 'undefined' || typeof(pTo) === 'undefined')\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid query join field', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\t//sanity check the join fields\n\t\t\tif (pFrom.indexOf(pTable)!=0)\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid query join field, join must come FROM the join table!', {queryUUID:_UUID, parameters:_Parameters, invalidField:pFrom});\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tif (pTo.indexOf('.')<=0)\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid query join field, join must go TO a field on another table ([table].[field])!', {queryUUID:_UUID, parameters:_Parameters, invalidField:pTo});\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tvar tmpType = (typeof(pType) === 'undefined') ? 'INNER JOIN' : pType;\n\n\t\t\tvar tmpJoin = (\n\t\t\t\t{\n\t\t\t\t\tType: tmpType,\n\t\t\t\t\tTable: pTable,\n\t\t\t\t\tFrom: pFrom,\n\t\t\t\t\tTo: pTo\n\t\t\t\t});\n\n\t\t\tif (!Array.isArray(_Parameters.join))\n\t\t\t{\n\t\t\t\t_Parameters.join = [tmpJoin];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_Parameters.join.push(tmpJoin);\n\t\t\t}\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Added a join', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\n\t\t/**\n\t\t* Add a record (for UPDATE and INSERT)\n\t\t*\n\t\t*\n\t\t* @method addRecord\n\t\t* @param {Object} pRecord The record to add.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar addRecord = function(pRecord)\n\t\t{\n\t\t\tif (typeof(pRecord) !== 'object')\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid record to the query -- records must be an object', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tif (!Array.isArray(_Parameters.query.records))\n\t\t\t{\n\t\t\t\t_Parameters.query.records = [pRecord];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_Parameters.query.records.push(pRecord);\n\t\t\t}\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Added a record to the query', {queryUUID:_UUID, parameters:_Parameters, newRecord:pRecord});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\n\t\t/**\n\t\t* Set the Dialect for Query generation.\n\t\t*\n\t\t* This function expects a string, case sensitive, which matches both the\n\t\t* folder and filename\n\t\t*\n\t\t* @method setDialect\n\t\t* @param {String} pDialectName The dialect for query generation.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setDialect = function(pDialectName)\n\t\t{\n\n\t\t\tif (typeof(pDialectName) !== 'string')\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Dialect set to English - invalid name', {queryUUID:_UUID, parameters:_Parameters, invalidDialect:pDialectName});\n\t\t\t\treturn setDialect('English');\n\t\t\t}\n\n\t\t\tif (_Dialects.hasOwnProperty(pDialectName))\n\t\t\t{\n\t\t\t\t_Dialect = _Dialects[pDialectName](_Fable);\n\t\t\t\tif (_LogLevel > 2)\n\t\t\t\t{\n\t\t\t\t\t_Fable.log.info('Dialog set to: '+pDialectName, {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_Fable.log.error('Dialect not set - unknown dialect \"'+pDialectName+\"'\", {queryUUID:_UUID, parameters:_Parameters, invalidDialect:pDialectName});\n\t\t\t\tsetDialect('English');\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\t\t/**\n\t\t* User to use for this query\n\t\t*\n\t\t* @method setIDUser\n\t\t*/\n\t\tvar setIDUser = function(pIDUser)\n\t\t{\n\n\t\t\tvar tmpUserID = 0;\n\n\t\t\tif (typeof(pIDUser) === 'number' && (pIDUser % 1) === 0 && pIDUser >= 0)\n\t\t\t{\n\t\t\t\ttmpUserID = pIDUser;\n\t\t\t}\n\t\t\telse if (pIDUser !== false)\n\t\t\t{\n\t\t\t\t_Fable.log.error('User set failed; non-positive or non-numeric argument.', {queryUUID:_UUID, parameters:_Parameters, invalidIDUser:pIDUser});\n\t\t\t}\n\n\n\t\t\t_Parameters.userID = tmpUserID;\n\t\t\t_Parameters.query.IDUser = tmpUserID;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('IDUser set to: '+tmpUserID, {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\t\t/**\n\t\t* Flag to disable auto identity\n\t\t*\n\t\t* @method setDisableAutoIdentity\n\t\t*/\n\t\tvar setDisableAutoIdentity = function(pFlag)\n\t\t{\n\t\t\t_Parameters.query.disableAutoIdentity = pFlag;\n\n\t\t\treturn this; //chainable\n\t\t};\n\n\t\t/**\n\t\t* Flag to disable auto datestamp\n\t\t*\n\t\t* @method setDisableAutoDateStamp\n\t\t*/\n\t\tvar setDisableAutoDateStamp = function(pFlag)\n\t\t{\n\t\t\t_Parameters.query.disableAutoDateStamp = pFlag;\n\n\t\t\treturn this; //chainable\n\t\t};\n\n\t\t/**\n\t\t* Flag to disable auto userstamp\n\t\t*\n\t\t* @method setDisableAutoUserStamp\n\t\t*/\n\t\tvar setDisableAutoUserStamp = function(pFlag)\n\t\t{\n\t\t\t_Parameters.query.disableAutoUserStamp = pFlag;\n\n\t\t\treturn this; //chainable\n\t\t};\n\n\t\t/**\n\t\t* Flag to disable delete tracking\n\t\t*\n\t\t* @method setDisableDeleteTracking\n\t\t*/\n\t\tvar setDisableDeleteTracking = function(pFlag)\n\t\t{\n\t\t\t_Parameters.query.disableDeleteTracking = pFlag;\n\n\t\t\treturn this; //chainable\n\t\t};\n\n\t\t/**\n\t\t* Check that a valid Dialect has been set\n\t\t*\n\t\t* If there has not been a dialect set, it defaults to English.\n\t\t* TODO: Have the json configuration define a \"default\" dialect.\n\t\t*\n\t\t* @method checkDialect\n\t\t*/\n\t\tvar checkDialect = function()\n\t\t{\n\t\t\tif (_Dialect === false)\n\t\t\t{\n\t\t\t\tsetDialect('English');\n\t\t\t}\n\t\t};\n\n\n\t\tvar buildCreateQuery = function()\n\t\t{\n\t\t\tcheckDialect();\n\t\t\t_Parameters.query.body = _Dialect.Create(_Parameters);\n\t\t\treturn this;\n\t\t};\n\n\t\tvar buildReadQuery = function()\n\t\t{\n\t\t\tcheckDialect();\n\t\t\t_Parameters.query.body = _Dialect.Read(_Parameters);\n\t\t\treturn this;\n\t\t};\n\n\t\tvar buildUpdateQuery = function()\n\t\t{\n\t\t\tcheckDialect();\n\t\t\t_Parameters.query.body = _Dialect.Update(_Parameters);\n\t\t\treturn this;\n\t\t};\n\n\t\tvar buildDeleteQuery = function()\n\t\t{\n\t\t\tcheckDialect();\n\t\t\t_Parameters.query.body = _Dialect.Delete(_Parameters);\n\t\t\treturn this;\n\t\t};\n\n\t\tvar buildUndeleteQuery = function()\n\t\t{\n\t\t\tcheckDialect();\n\t\t\t_Parameters.query.body = _Dialect.Undelete(_Parameters);\n\t\t\treturn this;\n\t\t};\n\n\t\tvar buildCountQuery = function()\n\t\t{\n\t\t\tcheckDialect();\n\t\t\t_Parameters.query.body = _Dialect.Count(_Parameters);\n\t\t\treturn this;\n\t\t};\n\n\t\t/**\n\t\t* Container Object for our Factory Pattern\n\t\t*/\n\t\tvar tmpNewFoxHoundObject = (\n\t\t{\n\t\t\tresetParameters: resetParameters,\n\t\t\tmergeParameters: mergeParameters,\n\n\t\t\tsetLogLevel: setLogLevel,\n\n\t\t\tsetScope: setScope,\n\t\t\tsetDistinct: setDistinct,\n\t\t\tsetIDUser: setIDUser,\n\t\t\tsetDataElements: setDataElements,\n\t\t\tsetBegin: setBegin,\n\t\t\tsetCap: setCap,\n\t\t\tsetFilter: setFilter,\n\t\t\taddFilter: addFilter,\n\t\t\tsetSort: setSort,\n\t\t\taddSort: addSort,\n\t\t\tsetJoin: setJoin,\n\t\t\taddJoin: addJoin,\n\n\t\t\taddRecord: addRecord,\n\t\t\tsetDisableAutoIdentity: setDisableAutoIdentity,\n\t\t\tsetDisableAutoDateStamp: setDisableAutoDateStamp,\n\t\t\tsetDisableAutoUserStamp: setDisableAutoUserStamp,\n\t\t\tsetDisableDeleteTracking: setDisableDeleteTracking,\n\n\t\t\tsetDialect: setDialect,\n\n\t\t\tbuildCreateQuery: buildCreateQuery,\n\t\t\tbuildReadQuery: buildReadQuery,\n\t\t\tbuildUpdateQuery: buildUpdateQuery,\n\t\t\tbuildDeleteQuery: buildDeleteQuery,\n\t\t\tbuildUndeleteQuery: buildUndeleteQuery,\n\t\t\tbuildCountQuery: buildCountQuery,\n\n\t\t\tclone: clone,\n\t\t\tnew: createNew\n\t\t});\n\n\t\t/**\n\t\t * Query\n\t\t *\n\t\t * @property query\n\t\t * @type Object\n\t\t */\n\t\tObject.defineProperty(tmpNewFoxHoundObject, 'query',\n\t\t\t{\n\t\t\t\tget: function() { return _Parameters.query; },\n\t\t\t\tset: function(pQuery) { _Parameters.query = pQuery; },\n\t\t\t\tenumerable: true\n\t\t\t});\n\n\t\t/**\n\t\t * Result\n\t\t *\n\t\t * @property result\n\t\t * @type Object\n\t\t */\n\t\tObject.defineProperty(tmpNewFoxHoundObject, 'result',\n\t\t\t{\n\t\t\t\tget: function() { return _Parameters.result; },\n\t\t\t\tset: function(pResult) { _Parameters.result = pResult; },\n\t\t\t\tenumerable: true\n\t\t\t});\n\n\t\t/**\n\t\t * Query Parameters\n\t\t *\n\t\t * @property parameters\n\t\t * @type Object\n\t\t */\n\t\tObject.defineProperty(tmpNewFoxHoundObject, 'parameters',\n\t\t\t{\n\t\t\t\tget: function() { return _Parameters; },\n\t\t\t\tset: function(pParameters) { _Parameters = pParameters; },\n\t\t\t\tenumerable: true\n\t\t\t});\n\n\t\t/**\n\t\t * Dialect\n\t\t *\n\t\t * @property dialect\n\t\t * @type Object\n\t\t */\n\t\tObject.defineProperty(tmpNewFoxHoundObject, 'dialect',\n\t\t\t{\n\t\t\t\tget: function() { return _Dialect; },\n\t\t\t\tenumerable: true\n\t\t\t});\n\n\t\t/**\n\t\t * Universally Unique Identifier\n\t\t *\n\t\t * @property uuid\n\t\t * @type String\n\t\t */\n\t\tObject.defineProperty(tmpNewFoxHoundObject, 'uuid',\n\t\t\t{\n\t\t\t\tget: function() { return _UUID; },\n\t\t\t\tenumerable: true\n\t\t\t});\n\n\t\t/**\n\t\t * Log Level\n\t\t *\n\t\t * @property logLevel\n\t\t * @type Integer\n\t\t */\n\t\tObject.defineProperty(tmpNewFoxHoundObject, 'logLevel',\n\t\t\t{\n\t\t\t\tget: function() { return _LogLevel; },\n\t\t\t\tenumerable: true\n\t\t\t});\n\n\t\treturn tmpNewFoxHoundObject;\n\t}\n\n\treturn createNew();\n};\n\nmodule.exports = FoxHound();\n","/**\n* Query Parameters Object\n*\n* @class FoxHoundQueryParameters\n* @constructor\n*/\nvar FoxHoundQueryParameters = (\n{\n\t\tscope: false, // STR: The scope of the data\n\t\t\t\t\t\t\t\t// TSQL: the \"Table\" or \"View\"\n\t\t\t\t\t\t\t\t// MongoDB: the \"Collection\"\n\n\t\tdataElements: false, // ARR of STR: The data elements to return\n\t\t\t\t\t\t\t\t// TSQL: the \"Columns\"\n\t\t\t\t\t\t\t\t// MongoDB: the \"Fields\"\n\n\t\tbegin: false, // INT: Record index to start at\n\t\t\t\t\t\t\t\t// TSQL: n in LIMIT 1,n\n\t\t\t\t\t\t\t\t// MongoDB: n in Skip(n)\n\n\t\tcap: false, // INT: Maximum number of records to return\n\t\t\t\t\t\t\t\t// TSQL: n in LIMIT n\n\t\t\t\t\t\t\t\t// MongoDB: n in limit(n)\n\n\t\t// Serialization example for a query:\n\t\t// Take the filter and return an array of filter instructions\n\t\t// Basic instruction anatomy:\n\t\t// INSTRUCTION~FIELD~OPERATOR~VALUE\n\t\t// FOP - Filter Open Paren\n\t\t// FOP~~(~\n\t\t// FCP - Filter Close Paren\n\t\t// FCP~~)~\n\t\t// FBV - Filter By Value\n\t\t// FBV~Category~EQ~Books\n\t\t// Possible comparisons:\n\t\t// * EQ - Equals To (=)\n\t\t// * NE - Not Equals To (!=)\n\t\t// * GT - Greater Than (>)\n\t\t// * GE - Greater Than or Equals To (>=)\n\t\t// * LT - Less Than (<)\n\t\t// * LE - Less Than or Equals To (<=)\n\t\t// * LK - Like (Like)\n\t\t// FBL - Filter By List (value list, separated by commas)\n\t\t// FBL~Category~EQ~Books,Movies\n\t\t// FSF - Filter Sort Field\n\t\t// FSF~Category~ASC~0\n\t\t// FSF~Category~DESC~0\n\t\t// FCC - Filter Constraint Cap (the limit of what is returned)\n\t\t// FCC~~10~\n\t\t// FCB - Filter Constraint Begin (the zero-based start index of what is returned)\n\t\t// FCB~~10~\n\t\t//\n\t\t// This means: FBV~Category~EQ~Books~FBV~PublishedYear~GT~2000~FSF~PublishedYear~DESC~0\n\t\t// Filters down to ALL BOOKS PUBLISHED AFTER 2000 IN DESCENDING ORDER\n\t\tfilter: false, // ARR of OBJ: Data filter expression list {Column:'Name', Operator:'EQ', Value:'John', Connector:'And', Parameter:'Name'}\n\t\t\t\t\t\t\t\t// TSQL: the WHERE clause\n\t\t\t\t\t\t\t\t// MongoDB: a find() expression\n\n\t\tsort: false, // ARR of OBJ: The sort order {Column:'Birthday', Direction:'Ascending'}\n\t\t\t\t\t\t\t\t// TSQL: ORDER BY\n\t\t\t\t\t\t\t\t// MongoDB: sort()\n\n\t\tjoin: false, // ARR of OBJ: The join tables {Type:'INNER JOIN', Table:'test', From: 'Test.ID', To: 'Scope.IDItem' }\n\t\t\t\t\t\t\t\t// TSQL: JOIN\n\n\t\t// Force a specific query to run regardless of above ... this is used to override the query generator.\n\t\tqueryOverride: false,\n\n\t\t// Where the generated query goes\n\t\tquery: false,\n\t\t/*\n\t\t\t{\n\t\t\t\tbody: false,\n\t\t\t\tschema: false, // The schema to intersect with our records\n\t\t\t\tIDUser: 0, // The User ID to stamp into records\n\t\t\t\tUUID: A_UUID, // Some globally unique record id, different per cloned query.\n\t\t\t\trecords: false, // The records to be created or changed\n\t\t\t\tparameters: {}\n\t\t\t}\n\t\t*/\n\t\t\n\t\t// Who is making the query\n\t\tuserID: 0,\n\n\t\t// Where the query results are stuck\n\t\tresult: false\n\t\t/*\n\t\t\t{\n\t\t\t\texecuted: false, // True once we've run a query.\n\t\t\t\tvalue: false, // The return value of the last query run\n\t\t\t\terror: false // The error message of the last run query\n\t\t\t}\n\t\t*/\n});\n\nmodule.exports = FoxHoundQueryParameters;","/**\n* FoxHound ALASQL Dialect\n*\n* @license MIT\n*\n* For an ALASQL query override:\n// An underscore template with the following values:\n// <%= DataElements %> = Field1, Field2, Field3, Field4\n// <%= Begin %> = 0\n// <%= Cap %> = 10\n// <%= Filter %> = WHERE StartDate > :MyStartDate\n// <%= Sort %> = ORDER BY Field1\n// The values are empty strings if they aren't set.\n*\n* @author Steven Velozo <steven@velozo.com>\n* @class FoxHoundDialectALASQL\n*/\n\nvar FoxHoundDialectALASQL = function(pFable)\n{\n\t//Request time from SQL server with microseconds resolution\n\tconst SQL_NOW = \"NOW(3)\";\n\n\t_Fable = pFable;\n\n\t/**\n\t* Generate a table name from the scope.\n\t*\n\t* Because ALASQL is all in-memory, and can be run in two modes (anonymous\n\t* working on arrays or table-based) we are going to make this a programmable\n\t* value. Then we can share the code across both providers.\n\t*\n\t* @method: generateTableName\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateTableName = function(pParameters)\n\t{\n\t\treturn ' '+pParameters.scope;\n\t};\n\n\t/**\n\t* Escape columns, because ALASQL has more reserved KWs than most SQL dialects\n\t*/\n\tvar escapeColumn = (pColumn, pParameters) =>\n\t{\n\t\tif (pColumn.indexOf('.') < 0)\n\t\t{\n\t\t\treturn '`'+pColumn+'`';\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// This could suck if the scope is not the same\n\t\t\tvar tmpTableName = pParameters.scope;\n\t\t\tif (pColumn.indexOf(tmpTableName+'.') > -1)\n\t\t\t{\n\t\t\t\treturn '`'+pColumn.replace(tmpTableName+'.', '')+'`';\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// This doesn't work well but we'll try it.\n\t\t\t\treturn '`'+pColumn+'`';\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t* Generate a field list from the array of dataElements\n\t*\n\t* Each entry in the dataElements is a simple string\n\t*\n\t* @method: generateFieldList\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @param {Boolean} pIsForCountClause (optional) If true, generate fields for use within a count clause.\n\t* @return: {String} Returns the field list clause, or empty string if explicit fields are requested but cannot be fulfilled\n\t* due to missing schema.\n\t*/\n\tvar generateFieldList = function(pParameters, pIsForCountClause)\n\t{\n\t\tvar tmpDataElements = pParameters.dataElements;\n\t\tif (!Array.isArray(tmpDataElements) || tmpDataElements.length < 1)\n\t\t{\n\t\t\tif (!pIsForCountClause)\n\t\t\t{\n\t\t\t\treturn ' *';\n\t\t\t}\n\t\t\t// we need to list all of the table fields explicitly; get them from the schema\n\t\t\tconst tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\t\t\tif (tmpSchema.length < 1)\n\t\t\t{\n\t\t\t\t// this means we have no schema; returning an empty string here signals the calling code to handle this case\n\t\t\t\treturn '';\n\t\t\t}\n\t\t\tconst idColumn = tmpSchema.find((entry) => entry.Type === 'AutoIdentity');\n\t\t\tif (!idColumn)\n\t\t\t{\n\t\t\t\t// this means there is no autoincrementing unique ID column; treat as above\n\t\t\t\treturn '';\n\t\t\t}\n\t\t\treturn ` ${idColumn.Column}`;\n\t\t}\n\n\t\tvar tmpFieldList = ' ';\n\t\tfor (var i = 0; i < tmpDataElements.length; i++)\n\t\t{\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\ttmpFieldList += ', ';\n\t\t\t}\n\t\t\ttmpFieldList += escapeColumn(tmpDataElements[i], pParameters);\n\t\t}\n\t\treturn tmpFieldList;\n\t};\n\n\t/**\n\t* Generate a query from the array of where clauses\n\t*\n\t* Each clause is an object like:\n\t\t{\n\t\t\tColumn:'Name',\n\t\t\tOperator:'EQ',\n\t\t\tValue:'John',\n\t\t\tConnector:'And',\n\t\t\tParameter:'Name'\n\t\t}\n\t*\n\t* @method: generateWhere\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the WHERE clause prefixed with WHERE, or an empty string if unnecessary\n\t*/\n\tvar generateWhere = function(pParameters)\n\t{\n\t\tvar tmpFilter = Array.isArray(pParameters.filter) ? pParameters.filter : [];\n\t\tvar tmpTableName = generateTableName(pParameters).trim();\n\n\t\tif (!pParameters.query.disableDeleteTracking)\n\t\t{\n\t\t\t// Check if there is a Deleted column on the Schema. If so, we add this to the filters automatically (if not already present)\n\t\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\tvar tmpSchemaEntry = tmpSchema[i];\n\n\t\t\t\tif (tmpSchemaEntry.Type === 'Deleted')\n\t\t\t\t{\n\t\t\t\t\tvar tmpHasDeletedParameter = false;\n\n\t\t\t\t\t//first, check to see if filters are already looking for Deleted column\n\t\t\t\t\tif (tmpFilter.length > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (var x = 0; x < tmpFilter.length; x++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (tmpFilter[x].Column === tmpSchemaEntry.Column)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttmpHasDeletedParameter = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (!tmpHasDeletedParameter)\n\t\t\t\t\t{\n\t\t\t\t\t\t//if not, we need to add it\n\t\t\t\t\t\ttmpFilter.push(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tColumn: tmpTableName + '.' + tmpSchemaEntry.Column,\n\t\t\t\t\t\t\tOperator: '=',\n\t\t\t\t\t\t\tValue: 0,\n\t\t\t\t\t\t\tConnector: 'AND',\n\t\t\t\t\t\t\tParameter: 'Deleted'\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (tmpFilter.length < 1)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpWhere = ' WHERE';\n\n\t\t// This is used to disable the connectors for subsequent queries.\n\t\t// Only the open parenthesis operator uses this, currently.\n\t\tvar tmpLastOperatorNoConnector = false;\n\n\t\tfor (var i = 0; i < tmpFilter.length; i++)\n\t\t{\n\t\t\tif ((tmpFilter[i].Connector != 'NONE') && (tmpFilter[i].Operator != ')') && (tmpWhere != ' WHERE') && (tmpLastOperatorNoConnector == false))\n\t\t\t{\n\t\t\t\ttmpWhere += ' '+tmpFilter[i].Connector;\n\t\t\t}\n\n\t\t\ttmpLastOperatorNoConnector = false;\n\n\t\t\tvar tmpColumnParameter;\n\n\t\t\tif (tmpFilter[i].Operator === '(')\n\t\t\t{\n\t\t\t\t// Open a logical grouping\n\t\t\t\ttmpWhere += ' (';\n\t\t\t\ttmpLastOperatorNoConnector = true;\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === ')')\n\t\t\t{\n\t\t\t\t// Close a logical grouping\n\t\t\t\ttmpWhere += ' )';\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IN')\n\t\t\t{\n\t\t\t\ttmpColumnParameter = tmpFilter[i].Parameter+'_w'+i;\n\t\t\t\t// Add the column name, operator and parameter name to the list of where value parenthetical\n\t\t\t\ttmpWhere += ' '+escapeColumn(tmpFilter[i].Column, pParameters)+' '+tmpFilter[i].Operator+' ( :'+tmpColumnParameter+' )';\n\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = tmpFilter[i].Value;\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IS NOT NULL')\n\t\t\t{\n\t\t\t\t// IS NOT NULL is a special operator which doesn't require a value, or parameter\n\t\t\t\ttmpWhere += ' '+escapeColumn(tmpFilter[i].Column, pParameters)+' '+tmpFilter[i].Operator;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpColumnParameter = tmpFilter[i].Parameter+'_w'+i;\n\t\t\t\t// Add the column name, operator and parameter name to the list of where value parenthetical\n\t\t\t\ttmpWhere += ' '+escapeColumn(tmpFilter[i].Column, pParameters)+' '+tmpFilter[i].Operator+' :'+tmpColumnParameter;\n\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = tmpFilter[i].Value;\n\t\t\t}\n\t\t}\n\n\t\treturn tmpWhere;\n\t};\n\n\t/**\n\t* Generate an ORDER BY clause from the sort array\n\t*\n\t* Each entry in the sort is an object like:\n\t* {Column:'Color',Direction:'Descending'}\n\t*\n\t* @method: generateOrderBy\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the field list clause\n\t*/\n\tvar generateOrderBy = function(pParameters)\n\t{\n\t\tvar tmpOrderBy = pParameters.sort;\n\t\tif (!Array.isArray(tmpOrderBy) || tmpOrderBy.length < 1)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpOrderClause = ' ORDER BY';\n\t\tfor (var i = 0; i < tmpOrderBy.length; i++)\n\t\t{\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\ttmpOrderClause += ',';\n\t\t\t}\n\t\t\ttmpOrderClause += ' '+escapeColumn(tmpOrderBy[i].Column, pParameters);\n\n\t\t\tif (tmpOrderBy[i].Direction == 'Descending')\n\t\t\t{\n\t\t\t\ttmpOrderClause += ' DESC';\n\t\t\t}\n\t\t}\n\t\treturn tmpOrderClause;\n\t};\n\n\t/**\n\t* Generate the limit clause\n\t*\n\t* @method: generateLimit\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateLimit = function(pParameters)\n\t{\n\t\tif (!pParameters.cap)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpLimit = ' LIMIT';\n\t\t// Cap is required for a limit clause.\n\t\ttmpLimit += ' ' + pParameters.cap;\n\n\t\t// If there is a begin record, we'll pass that in as well.\n\t\tif (pParameters.begin !== false)\n\t\t{\n\t\t\ttmpLimit += ' FETCH ' + pParameters.begin;\n\t\t}\n\n\t\treturn tmpLimit;\n\t};\n\n\t/**\n\t* Generate the update SET clause\n\t*\n\t* @method: generateUpdateSetters\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateUpdateSetters = function(pParameters)\n\t{\n\t\tvar tmpRecords = pParameters.query.records;\n\t\t// We need to tell the query not to generate improperly if there are no values to set.\n\t\tif (!Array.isArray(tmpRecords) || tmpRecords.length < 1)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpUpdate = '';\n\t\t// If there is more than one record in records, we are going to ignore them for now.\n\t\tvar tmpCurrentColumn = 0;\n\t\tfor(var tmpColumn in tmpRecords[0])\n\t\t{\n\t\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\t\tvar tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\tif (tmpColumn == tmpSchema[i].Column)\n\t\t\t\t{\n\t\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\t\ttmpSchemaEntry = tmpSchema[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (pParameters.query.disableAutoDateStamp &&\n\t\t\t\ttmpSchemaEntry.Type === 'UpdateDate')\n\t\t\t{\n\t\t\t\t// This is ignored if flag is set\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (pParameters.query.disableAutoUserStamp &&\n\t\t\t\ttmpSchemaEntry.Type === 'UpdateIDUser')\n\t\t\t{\n\t\t\t\t// This is ignored if flag is set\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'AutoIdentity':\n\t\t\t\tcase 'CreateDate':\n\t\t\t\tcase 'CreateIDUser':\n\t\t\t\tcase 'DeleteDate':\n\t\t\t\tcase 'DeleteIDUser':\n\t\t\t\t\t// These are all ignored on update\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpUpdate += ',';\n\t\t\t}\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\ttmpUpdate += ' '+escapeColumn(tmpColumn, pParameters)+' = NOW()';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateIDUser':\n\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\tvar tmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdate += ' '+escapeColumn(tmpColumn, pParameters)+' = :'+tmpColumnParameter;\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tvar tmpColumnDefaultParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdate += ' '+escapeColumn(tmpColumn, pParameters)+' = :'+tmpColumnDefaultParameter;\n\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnDefaultParameter] = tmpRecords[0][tmpColumn];\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// We use a number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (tmpUpdate === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpUpdate;\n\t};\n\n\t/**\n\t* Generate the update-delete SET clause\n\t*\n\t* @method: generateUpdateDeleteSetters\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateUpdateDeleteSetters = function(pParameters)\n\t{\n\t\tif (pParameters.query.disableDeleteTracking)\n\t\t{\n\t\t\t//Don't generate an UPDATE query if Delete tracking is disabled\n\t\t\treturn false;\n\t\t}\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpCurrentColumn = 0;\n\t\tvar tmpHasDeletedField = false;\n\t\tvar tmpUpdate = '';\n\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\tvar tmpSchemaEntry = {Type:'Default'};\n\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t{\n\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\ttmpSchemaEntry = tmpSchema[i];\n\n\t\t\tvar tmpUpdateSql = null;\n\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'Deleted':\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = 1';\n\t\t\t\t\ttmpHasDeletedField = true; //this field is required in order for query to be built\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'DeleteDate':\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = NOW()';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\t\t// Delete operation is an Update, so we should stamp the update time\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = NOW()';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'DeleteIDUser':\n\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\tvar tmpColumnParameter = tmpSchemaEntry.Column+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = :'+tmpColumnParameter;\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t//DON'T allow update of other fields in this query\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpUpdate += ',';\n\t\t\t}\n\n\t\t\ttmpUpdate += tmpUpdateSql;\n\n\t\t\t// We use a number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (!tmpHasDeletedField ||\n\t\t\ttmpUpdate === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpUpdate;\n\t};\n\n\t/**\n\t* Generate the update-delete SET clause\n\t*\n\t* @method: generateUpdateDeleteSetters\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateUpdateUndeleteSetters = function(pParameters)\n\t{\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpCurrentColumn = 0;\n\t\tvar tmpHasDeletedField = false;\n\t\tvar tmpUpdate = '';\n\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\tvar tmpSchemaEntry = {Type:'Default'};\n\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t{\n\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\ttmpSchemaEntry = tmpSchema[i];\n\n\t\t\tvar tmpUpdateSql = null;\n\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'Deleted':\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = 0';\n\t\t\t\t\ttmpHasDeletedField = true; //this field is required in order for query to be built\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\t\t// Delete operation is an Update, so we should stamp the update time\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = NOW()';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateIDUser':\n\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\tvar tmpColumnParameter = tmpSchemaEntry.Column+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = :'+tmpColumnParameter;\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t//DON'T allow update of other fields in this query\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpUpdate += ',';\n\t\t\t}\n\n\t\t\ttmpUpdate += tmpUpdateSql;\n\n\t\t\t// We use a number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (!tmpHasDeletedField ||\n\t\t\ttmpUpdate === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpUpdate;\n\t};\n\n\t/**\n\t* Generate the create SET clause\n\t*\n\t* @method: generateCreateSetList\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateCreateSetValues = function(pParameters)\n\t{\n\t\tvar tmpRecords = pParameters.query.records;\n\t\t// We need to tell the query not to generate improperly if there are no values to set.\n\t\tif (!Array.isArray(tmpRecords) || tmpRecords.length < 1)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\n\t\tvar tmpCreateSet = '';\n\t\t// If there is more than one record in records, we are going to ignore them for now.\n\t\tvar tmpCurrentColumn = 0;\n\t\tfor(var tmpColumn in tmpRecords[0])\n\t\t{\n\t\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\t\tvar tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\tif (tmpColumn == tmpSchema[i].Column)\n\t\t\t\t{\n\t\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\t\ttmpSchemaEntry = tmpSchema[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!pParameters.query.disableDeleteTracking)\n\t\t\t{\n\t\t\t\tif (tmpSchemaEntry.Type === 'DeleteDate' ||\n\t\t\t\t\ttmpSchemaEntry.Type === 'DeleteIDUser')\n\t\t\t\t{\n\t\t\t\t\t// These are all ignored on insert (if delete tracking is enabled as normal)\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpCreateSet += ',';\n\t\t\t}\n\n\t\t\t//define a re-usable method for setting up field definitions in a default pattern\n\t\t\tvar buildDefaultDefinition = function()\n\t\t\t{\n\t\t\t\tvar tmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\ttmpCreateSet += ' :'+tmpColumnParameter;\n\t\t\t\t// Set the query parameter\n\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = tmpRecords[0][tmpColumn];\n\t\t\t};\n\n\t\t\tvar tmpColumnParameter;\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'AutoIdentity':\n\t\t\t\t\tif (pParameters.query.disableAutoIdentity)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\t\ttmpCreateSet += ' NULL';\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'AutoGUID':\n\t\t\t\t\tif (pParameters.query.disableAutoIdentity)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse if (tmpRecords[0][tmpColumn] &&\n\t\t\t\t\t\t\ttmpRecords[0][tmpColumn].length >= 5 &&\n\t\t\t\t\t\t\ttmpRecords[0][tmpColumn] !== '0x0000000000000000') //stricture default\n\t\t\t\t\t{\n\t\t\t\t\t\t// Allow consumer to override AutoGUID\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\t\ttmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\t\ttmpCreateSet += ' :'+tmpColumnParameter;\n\t\t\t\t\t\t// Set the query parameter\n\t\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.UUID;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\tcase 'CreateDate':\n\t\t\t\tcase 'DeleteDate':\n\t\t\t\t\tif (pParameters.query.disableAutoDateStamp)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\t\ttmpCreateSet += ' NOW()';\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateIDUser':\n\t\t\t\tcase 'CreateIDUser':\n\t\t\t\tcase 'DeleteIDUser':\n\t\t\t\t\tif (pParameters.query.disableAutoUserStamp)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\t\ttmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\t\ttmpCreateSet += ' :'+tmpColumnParameter;\n\t\t\t\t\t\t// Set the query parameter\n\t\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// We use an appended number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (tmpCreateSet === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpCreateSet;\n\t};\n\n\t/**\n\t* Generate the create SET clause\n\t*\n\t* @method: generateCreateSetList\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateCreateSetList = function(pParameters)\n\t{\n\t\t// The records were already validated by generateCreateSetValues\n\t\tvar tmpRecords = pParameters.query.records;\n\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpCreateSet = '';\n\t\t// If there is more than one record in records, we are going to ignore them for now.\n\t\tfor(var tmpColumn in tmpRecords[0])\n\t\t{\n\t\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\t\tvar tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\tif (tmpColumn == tmpSchema[i].Column)\n\t\t\t\t{\n\t\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\t\ttmpSchemaEntry = tmpSchema[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!pParameters.query.disableDeleteTracking)\n\t\t\t{\n\t\t\t\tif (tmpSchemaEntry.Type === 'DeleteDate' ||\n\t\t\t\t\ttmpSchemaEntry.Type === 'DeleteIDUser')\n\t\t\t\t{\n\t\t\t\t\t// These are all ignored on insert (if delete tracking is enabled as normal)\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tdefault:\n\t\t\t\t\tif (tmpCreateSet != '')\n\t\t\t\t\t{\n\t\t\t\t\t\ttmpCreateSet += ',';\n\t\t\t\t\t}\n\t\t\t\t\ttmpCreateSet += ' '+escapeColumn(tmpColumn, pParameters);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn tmpCreateSet;\n\t};\n\n\n\tvar Create = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpCreateSetList = generateCreateSetList(pParameters);\n\t\tvar tmpCreateSetValues = generateCreateSetValues(pParameters);\n\n\t\tif (!tmpCreateSetValues)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn 'INSERT INTO'+tmpTableName+' ('+tmpCreateSetList+') VALUES ('+tmpCreateSetValues+');';\n\t};\n\n\n\t/**\n\t* Read one or many records\n\t*\n\t* Some examples:\n\t* SELECT * FROM WIDGETS;\n\t* SELECT * FROM WIDGETS LIMIT 0, 20;\n\t* SELECT * FROM WIDGETS LIMIT 5, 20;\n\t* SELECT ID, Name, Cost FROM WIDGETS LIMIT 5, 20;\n\t* SELECT ID, Name, Cost FROM WIDGETS LIMIT 5, 20 WHERE LastName = 'Smith';\n\t*\n\t* @method Read\n\t* @param {Object} pParameters SQL Query parameters\n\t* @return {String} Returns the current Query for chaining.\n\t*/\n\tvar Read = function(pParameters)\n\t{\n\t\tvar tmpFieldList = generateFieldList(pParameters);\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpOrderBy = generateOrderBy(pParameters);\n\t\tvar tmpLimit = generateLimit(pParameters);\n\t\tconst tmpOptDistinct = pParameters.distinct ? ' DISTINCT' : '';\n\n\t\tif (pParameters.queryOverride)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tvar tmpQueryTemplate = _Fable.Utility.template(pParameters.queryOverride);\n\t\t\t\treturn tmpQueryTemplate({FieldList:tmpFieldList, TableName:tmpTableName, Where:tmpWhere, OrderBy:tmpOrderBy, Limit:tmpLimit, Distinct: tmpOptDistinct, _Params: pParameters});\n\t\t\t}\n\t\t\tcatch (pError)\n\t\t\t{\n\t\t\t\t// This pokemon is here to give us a convenient way of not throwing up totally if the query fails.\n\t\t\t\tconsole.log('Error with custom Read Query ['+pParameters.queryOverride+']: '+pError);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn `SELECT${tmpOptDistinct}${tmpFieldList} FROM${tmpTableName}${tmpWhere}${tmpOrderBy}${tmpLimit};`;\n\t};\n\n\tvar Update = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpUpdateSetters = generateUpdateSetters(pParameters);\n\n\t\tif (!tmpUpdateSetters)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn 'UPDATE'+tmpTableName+' SET'+tmpUpdateSetters+tmpWhere+';';\n\t};\n\n\tvar Delete = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpUpdateDeleteSetters = generateUpdateDeleteSetters(pParameters);\n\n\t\tif (tmpUpdateDeleteSetters)\n\t\t{\n\t\t\t//If it has a deleted bit, update it instead of actually deleting the record\n\t\t\treturn 'UPDATE'+tmpTableName+' SET'+tmpUpdateDeleteSetters+tmpWhere+';';\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn 'DELETE FROM'+tmpTableName+tmpWhere+';';\n\t\t}\n\t};\n\n\tvar Undelete = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tlet tmpDeleteTrackingState = pParameters.query.disableDeleteTracking;\n\t\tpParameters.query.disableDeleteTracking = true;\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpUpdateUndeleteSetters = generateUpdateUndeleteSetters(pParameters);\n\t\tpParameters.query.disableDeleteTracking = tmpDeleteTrackingState;\n\n\t\tif (tmpUpdateUndeleteSetters)\n\t\t{\n\t\t\t//If it has a deleted bit, update it instead of actually deleting the record\n\t\t\treturn 'UPDATE'+tmpTableName+' SET'+tmpUpdateUndeleteSetters+tmpWhere+';';\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn 'SELECT NULL;';\n\t\t}\n\t};\n\n\tvar Count = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tconst tmpFieldList = pParameters.distinct ? generateFieldList(pParameters, true) : '*';\n\n\t\t// here, we ignore the distinct keyword if no fields have been specified and\n\t\tif (pParameters.distinct && tmpFieldList.length < 1)\n\t\t{\n\t\t\tconsole.warn('Distinct requested but no field list or schema are available, so not honoring distinct for count query.');\n\t\t}\n\t\tconst tmpOptDistinct = pParameters.distinct && tmpFieldList.length > 0 ? 'DISTINCT' : '';\n\t\tif (pParameters.queryOverride)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tvar tmpQueryTemplate = _Fable.Utility.template(pParameters.queryOverride);\n\t\t\t\treturn tmpQueryTemplate({FieldList:[], TableName:tmpTableName, Where:tmpWhere, OrderBy:'', Limit:'', Distinct: tmpOptDistinct, _Params: pParameters});\n\t\t\t}\n\t\t\tcatch (pError)\n\t\t\t{\n\t\t\t\t// This pokemon is here to give us a convenient way of not throwing up totally if the query fails.\n\t\t\t\tconsole.log('Error with custom Count Query ['+pParameters.queryOverride+']: '+pError);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn `SELECT COUNT(${tmpOptDistinct}${tmpFieldList || '*'}) AS RowCount FROM${tmpTableName}${tmpWhere};`;\n\t};\n\n\tvar tmpDialect = ({\n\t\tCreate: Create,\n\t\tRead: Read,\n\t\tUpdate: Update,\n\t\tDelete: Delete,\n\t\tUndelete: Undelete,\n\t\tCount: Count\n\t});\n\n\t/**\n\t* Dialect Name\n\t*\n\t* @property name\n\t* @type string\n\t*/\n\tObject.defineProperty(tmpDialect, 'name',\n\t\t{\n\t\t\tget: function() { return 'ALASQL'; },\n\t\t\tenumerable: true\n\t\t});\n\n\treturn tmpDialect;\n};\n\nmodule.exports = FoxHoundDialectALASQL;\n","/**\n* FoxHound English Dialect\n*\n* Because if I can't ask for it in my native tongue, how am I going to ask a\n* complicated server for it?\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n* @class FoxHoundDialectEnglish\n*/\nvar FoxHoundDialectEnglish = function()\n{\n\tvar Create = function(pParameters)\n\t{\n\t\tvar tmpScope = pParameters.scope;\n\n\t\treturn 'Here is a '+tmpScope+'.';\n\t};\n\n\t/**\n\t* Read one or many records\n\t*\n\t* Some examples:\n\t* Please give me all your Widget records. Thanks.\n\t* Please give me 20 Widget records. Thanks.\n\t* Please give me 20 Widget records starting with record 5. Thanks.\n\t* Please give me the ID, Name and Cost of 20 Widget records starting with record 5. Thanks.\n\t* Please give me the ID and Name of 20 Widget records starting with record 5, when LastName equals \"Smith\". Thanks.\n\t*\n\t* @method Read\n\t* @param {Number} pLogLevel The log level for our object\n\t* @return {String} Returns the current Query for chaining.\n\t*/\n\tvar Read = function(pParameters)\n\t{\n\t\tvar tmpScope = pParameters.scope;\n\t\tconst tmpDistinct = pParameters.distinct ? 'unique ' : '';\n\n\t\treturn `Please give me all your ${tmpDistinct}${tmpScope} records. Thanks.`;\n\t};\n\n\tvar Update = function(pParameters)\n\t{\n\t\tvar tmpScope = pParameters.scope;\n\n\t\treturn 'I am changing your '+tmpScope+'.';\n\t};\n\n\tvar Delete = function(pParameters)\n\t{\n\t\tvar tmpScope = pParameters.scope;\n\n\t\treturn 'I am deleting your '+tmpScope+'.';\n\t};\n\n\tvar Undelete = function(pParameters)\n\t{\n\t\tvar tmpScope = pParameters.scope;\n\n\t\treturn 'I am undeleting your '+tmpScope+'.';\n\t};\n\n\tvar Count = function(pParameters)\n\t{\n\t\tvar tmpScope = pParameters.scope;\n\t\tconst tmpDistinct = pParameters.distinct ? 'unique ' : '';\n\n\t\treturn `Count your ${tmpDistinct}${tmpScope}.`;\n\t};\n\n\tvar tmpDialect = ({\n\t\tCreate: Create,\n\t\tRead: Read,\n\t\tUpdate: Update,\n\t\tDelete: Delete,\n\t\tUndelete: Undelete,\n\t\tCount: Count\n\t});\n\n\t/**\n\t * Dialect Name\n\t *\n\t * @property name\n\t * @type string\n\t */\n\tObject.defineProperty(tmpDialect, 'name',\n\t\t{\n\t\t\tget: function() { return 'English'; },\n\t\t\tenumerable: true\n\t\t});\n\n\treturn tmpDialect;\n};\n\nmodule.exports = FoxHoundDialectEnglish;\n","/**\n* FoxHound Meadow Endpoints Dialect\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n* @class FoxHoundDialectMeadowEndpoints\n*/\n\nvar FoxHoundDialectMeadowEndpoints = function()\n{\n\t/**\n\t * Generate a table name from the scope\n\t *\n\t * @method: generateTableName\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Returns the table name clause\n\t */\n\tvar generateTableName = function(pParameters)\n\t{\n\t\treturn pParameters.scope;\n\t};\n\n\t/**\n\t * Generate the Identity column from the schema or scope\n\t * \n\t * @method: generateIdentityColumnName\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Returns the table name clause\n\t */\n\tvar generateIdentityColumnName = function(pParameters)\n\t{\n\t\t// TODO: See about using the Schema or the Schemata for this\n\t\treturn `ID${pParameters.scope}`;\n\t};\n\n\t/**\n\t * Generate a field list from the array of dataElements\n\t *\n\t * Each entry in the dataElements is a simple string\n\t *\n\t * @method: generateFieldList\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Returns the field list clause\n\t */\n\tvar generateFieldList = function(pParameters)\n\t{\n\t\tvar tmpDataElements = pParameters.dataElements;\n\t\tif (!Array.isArray(tmpDataElements) || tmpDataElements.length < 1)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpFieldList = '';\n\t\tfor (var i = 0; i < tmpDataElements.length; i++)\n\t\t{\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\ttmpFieldList += ',';\n\t\t\t}\n\n tmpFieldList += tmpDataElements[i];\n\t\t}\n\t\treturn tmpFieldList;\n\t};\n\n\t/**\n\t * Generate a query from the array of where clauses\n\t *\n\t * Each clause is an object like:\n\t\t{\n\t\t\tColumn:'Name', \n\t\t\tOperator:'EQ', \n\t\t\tValue:'John', \n\t\t\tConnector:'And', \n\t\t\tParameter:'Name'\n\t\t}\n\t *\n\t * @method: generateWhere\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Returns the WHERE clause prefixed with WHERE, or an empty string if unnecessary\n\t */\n\tvar generateWhere = function(pParameters)\n\t{\n\t\tvar tmpFilter = Array.isArray(pParameters.filter) ? pParameters.filter : [];\n\t\tvar tmpTableName = generateTableName(pParameters);\n \n var tmpURL = '';\n\n let tmpfAddFilter = (pFilterCommand, pFilterParameters) =>\n {\n if (tmpURL.length > 0)\n {\n tmpURL += '~';\n }\n \n tmpURL += `${pFilterCommand}~${pFilterParameters[0]}~${pFilterParameters[1]}~${pFilterParameters[2]}`;\n };\n\n let tmpfTranslateOperator = (pOperator) =>\n {\n tmpNewOperator = 'EQ';\n switch(pOperator.toUpperCase())\n {\n case '!=':\n tmpNewOperator = 'NE';\n break;\n case '>':\n tmpNewOperator = 'GT';\n break;\n case '>=':\n tmpNewOperator = 'GE';\n break;\n case '<=':\n tmpNewOperator = 'LE';\n break;\n case '<':\n tmpNewOperator = 'LT';\n break;\n case 'LIKE':\n tmpNewOperator = 'LK';\n break;\n case 'IN':\n tmpNewOperator = 'INN';\n break;\n case 'NOT IN':\n tmpNewOperator = 'NI';\n break;\n }\n return tmpNewOperator;\n }\n\n // Translating Delete Tracking bit on query to a query with automagic\n // This will eventually deprecate this as part of the necessary query\n if (pParameters.query.disableDeleteTracking)\n {\n tmpfAddFilter('FBV',['Deleted','GE','0'])\n }\n\n\t\tfor (var i = 0; i < tmpFilter.length; i++)\n\t\t{\n\t\t\tif (tmpFilter[i].Operator === '(')\n\t\t\t{\n tmpfAddFilter('FOP',['0','(','0']);\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === ')')\n\t\t\t{\n\t\t\t\t// Close a logical grouping\n tmpfAddFilter('FCP',['0',')','0']);\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IN' || tmpFilter[i].Operator === \"NOT IN\")\n\t\t\t{\n let tmpFilterCommand = 'FBV';\n if (tmpFilter[i].Connector == 'OR')\n {\n tmpFilterCommand = 'FBVOR';\n }\n\t\t\t\t// Add the column name, operator and parameter name to the list of where value parenthetical\n tmpfAddFilter(tmpFilterCommand, [tmpFilter[i].Column, tmpfTranslateOperator(tmpFilter[i].Operator), tmpFilter[i].Value.map(encodeURIComponent).join(',')])\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IS NULL')\n\t\t\t{\n\t\t\t\t// IS NULL is a special operator which doesn't require a value, or parameter\n tmpfAddFilter('FBV', [tmpFilter[i].Column, 'IN', '0']);\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IS NOT NULL')\n\t\t\t{\n\t\t\t\t// IS NOT NULL is a special operator which doesn't require a value, or parameter\n tmpfAddFilter('FBV', [tmpFilter[i].Column, 'NN', '0']);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n let tmpFilterCommand = 'FBV';\n if (tmpFilter[i].Connector == 'OR')\n {\n tmpFilterCommand = 'FBVOR';\n }\n\t\t\t\t// Add the column name, operator and parameter name to the list of where value parenthetical\n tmpfAddFilter(tmpFilterCommand, [tmpFilter[i].Column, tmpfTranslateOperator(tmpFilter[i].Operator), encodeURIComponent(tmpFilter[i].Value)]);\n\t\t\t}\n\t\t}\n\n let tmpOrderBy = generateOrderBy(pParameters);\n if (tmpOrderBy)\n {\n if (tmpURL)\n {\n tmpURL += '~';\n }\n tmpURL += tmpOrderBy;\n }\n\n\t\treturn tmpURL;\n\t};\n\n /**\n\t * Get the flags for the request\n * \n * These are usually passed in for Update and Create when extra tracking is disabled.\n\t *\n\t * @method: generateFlags\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Flags to be sent, if any.\n\t */\n function generateFlags(pParameters)\n {\n let tmpDisableAutoDateStamp = pParameters.query.disableAutoDateStamp;\n let tmpDisableDeleteTracking = pParameters.query.disableDeleteTracking;\n let tmpDisableAutoIdentity = pParameters.query.disableAutoIdentity;\n let tmpDisableAutoUserStamp = pParameters.query.disableAutoUserStamp;\n\n let tmpFlags = '';\n\n let fAddFlag = (pFlagSet, pFlag) =>\n {\n if (pFlagSet)\n {\n if (tmpFlags.length > 0)\n {\n tmpFlags += ',';\n }\n tmpFlags += pFlag;\n }\n };\n\n fAddFlag(tmpDisableAutoDateStamp, 'DisableAutoDateStamp');\n fAddFlag(tmpDisableDeleteTracking, 'DisableDeleteTracking');\n fAddFlag(tmpDisableAutoIdentity, 'DisableAutoIdentity');\n fAddFlag(tmpDisableAutoUserStamp, 'DisableAutoUserStamp');\n\n return tmpFlags;\n };\n\n /**\n\t * Get the ID for the record, to be used in URIs\n\t *\n\t * @method: getIDRecord\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} ID of the record in string form for the URI\n\t */\n\tvar getIDRecord = function(pParameters)\n\t{\n var tmpFilter = Array.isArray(pParameters.filter) ? pParameters.filter : [];\n\n\t\tvar tmpIDRecord = false;\n\n if (tmpFilter.length < 1)\n\t\t{\n\t\t\treturn tmpIDRecord;\n\t\t}\n\n\t\tfor (var i = 0; i < tmpFilter.length; i++)\n\t\t{\n // Check Schema Entry Type\n var tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\t\t\tvar tmpSchemaEntry = {Column:tmpFilter[i].Column, Type:'Default'};\n\t\t\tfor (var j = 0; j < tmpSchema.length; j++)\n\t\t\t{\n // If this column is the AutoIdentity, set it.\n\t\t\t\tif ((tmpFilter[i].Column == tmpSchema[j].Column) &&\n (tmpSchema[j].Type == 'AutoIdentity'))\n\t\t\t\t{\n tmpIDRecord = tmpFilter[i].Value;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn tmpIDRecord;\n }\n\t\n /**\n\t * Generate an ORDER BY clause from the sort array\n\t *\n\t * Each entry in the sort is an object like:\n\t * {Column:'Color',Direction:'Descending'}\n\t *\n\t * @method: generateOrderBy\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Returns the field list clause\n\t */\n\tvar generateOrderBy = function(pParameters)\n\t{\n\t\tvar tmpOrderBy = pParameters.sort;\n\t\tvar tmpOrderClause = false;\n\n if (!Array.isArray(tmpOrderBy) || tmpOrderBy.length < 1)\n\t\t{\n\t\t\treturn tmpOrderClause;\n\t\t}\n\n tmpOrderClause = '';\n\n for (var i = 0; i < tmpOrderBy.length; i++)\n\t\t{\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\ttmpOrderClause += '~';\n\t\t\t}\n\t\t\ttmpOrderClause += `FSF~${tmpOrderBy[i].Column}~`;\n\n\t\t\tif (tmpOrderBy[i].Direction == 'Descending')\n\t\t\t{\n\t\t\t\ttmpOrderClause += 'DESC~0';\n\t\t\t}\n else\n {\n tmpOrderClause += 'ASC~0'\n }\n\t\t}\n\t\treturn tmpOrderClause;\n\t};\n\n\t/**\n\t * Generate the limit clause\n\t *\n\t * @method: generateLimit\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Returns the table name clause\n\t */\n\tvar generateLimit = function(pParameters)\n\t{\n\t\tif (!pParameters.cap)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n let tmpBegin = (pParameters.begin !== false) ? pParameters.begin : 0;\n\n return `${tmpBegin}/${pParameters.cap}`;\n\t};\n\n\tvar Create = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n var tmpFlags = generateFlags(pParameters);\n\n if (tmpTableName)\n {\n let tmpURL = tmpTableName;\n if (tmpFlags)\n {\n tmpURL = `${tmpURL}/WithFlags/${tmpFlags}`\n }\n return tmpURL;\n }\n else\n {\n return false;\n }\n\t};\n\n\n\t/**\n\t* Read one or many records\n\t*\n\t* @method Read\n\t* @param {Object} pParameters SQL Query parameters\n\t* @return {String} Returns the current Query for chaining.\n\t*/\n\tvar Read = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpFieldList = generateFieldList(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpLimit = generateLimit(pParameters);\n\n\t\tvar tmpURL = `${tmpTableName}`;\n\t\t// In the case that there is only a single query parameter, and the parameter is a single identity, \n\t\t// we will cast it to the READ endpoint rather than READS.\n\t\tif ((pParameters.filter)\n\t\t\t && (pParameters.filter.length == 1)\n // If there is exactly one query filter parameter\n\t\t\t && (pParameters.filter[0].Column === generateIdentityColumnName(pParameters))\n\t\t\t // AND It is the Identity column\n\t\t\t && (pParameters.filter[0].Operator === '=')\n\t\t\t // AND The comparators is a simple equals \n\t\t\t && (tmpLimit == '') && (tmpFieldList == '')\n\t\t\t // AND There is no limit or field list set\n\t\t\t && (!pParameters.sort))\n\t\t\t // AND There is no sort clause\n\t\t{\n\t\t\t// THEN This is a SINGLE READ by presumption.\n\t\t\t// There are some bad side affects this could cause with chaining and overridden behaviors, if \n\t\t\t// we are requesting a filtered list of 1 record.\n\t\t\ttmpURL = `${tmpURL}/${pParameters.filter[0].Value}`;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpURL = `${tmpURL}s`;\n\t\t\tif (tmpFieldList)\n\t\t\t{\n\t\t\t\ttmpURL = `${tmpURL}/LiteExtended/${tmpFieldList}`\n\t\t\t}\n\t\t\tif (tmpWhere)\n\t\t\t{\n\t\t\t\ttmpURL = `${tmpURL}/FilteredTo/${tmpWhere}`;\n\t\t\t}\n\t\t\tif (tmpLimit)\n\t\t\t{\n\t\t\t\ttmpURL = `${tmpURL}/${tmpLimit}`;\n\t\t\t}\n\t\t}\n\n\t\treturn tmpURL;\n\t};\n\n\tvar Update = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n var tmpFlags = generateFlags(pParameters);\n\n if (tmpTableName)\n {\n let tmpURL = tmpTableName;\n if (tmpFlags)\n {\n tmpURL = `${tmpURL}/WithFlags/${tmpFlags}`\n }\n return tmpURL;\n }\n else\n {\n return false;\n }\n\t};\n\n\tvar Delete = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpIDRecord = getIDRecord(pParameters);\n\n if (!tmpIDRecord)\n {\n return false;\n }\n\n\t\treturn `${tmpTableName}/${tmpIDRecord}`;\n\t};\n\n\tvar Count = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\n let tmpCountQuery = `${tmpTableName}s/Count`;\n\n if (tmpWhere)\n {\n return `${tmpTableName}s/Count/FilteredTo/${tmpWhere}`;\n }\n\n return tmpCountQuery;\n\t};\n\n\tvar tmpDialect = ({\n\t\tCreate: Create,\n\t\tRead: Read,\n\t\tUpdate: Update,\n\t\tDelete: Delete,\n\t\tCount: Count\n\t});\n\n\t/**\n\t * Dialect Name\n\t *\n\t * @property name\n\t * @type string\n\t */\n\tObject.defineProperty(tmpDialect, 'name',\n\t\t{\n\t\t\tget: function() { return 'MeadowEndpoints'; },\n\t\t\tenumerable: true\n\t\t});\n\n\treturn tmpDialect;\n};\n\nmodule.exports = FoxHoundDialectMeadowEndpoints;\n","/**\n* FoxHound MySQL Dialect\n*\n* @license MIT\n*\n* For a MySQL query override:\n// An underscore template with the following values:\n// <%= DataElements %> = Field1, Field2, Field3, Field4\n// <%= Begin %> = 0\n// <%= Cap %> = 10\n// <%= Filter %> = WHERE StartDate > :MyStartDate\n// <%= Sort %> = ORDER BY Field1\n// The values are empty strings if they aren't set.\n*\n* @author Steven Velozo <steven@velozo.com>\n* @class FoxHoundDialectMySQL\n*/\n\nvar FoxHoundDialectMySQL = function(pFable)\n{\n\t//Request time from SQL server with microseconds resolution\n\tconst SQL_NOW = \"NOW(3)\";\n\n\t_Fable = pFable;\n\n\t/**\n\t* Generate a table name from the scope\n\t*\n\t* @method: generateTableName\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateTableName = function(pParameters)\n\t{\n\t\tif (pParameters.scope && pParameters.scope.indexOf('`') >= 0)\n\t\t\treturn ' '+pParameters.scope+'';\n\t\telse\n\t\t\treturn ' `'+pParameters.scope+'`';\n\t};\n\n\t/**\n\t* Generate a field list from the array of dataElements\n\t*\n\t* Each entry in the dataElements is a simple string\n\t*\n\t* @method: generateFieldList\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @param {Boolean} pIsForCountClause (optional) If true, generate fields for use within a count clause.\n\t* @return: {String} Returns the field list clause, or empty string if explicit fields are requested but cannot be fulfilled\n\t* due to missing schema.\n\t*/\n\tvar generateFieldList = function(pParameters, pIsForCountClause)\n\t{\n\t\tvar tmpDataElements = pParameters.dataElements;\n\t\tif (!Array.isArray(tmpDataElements) || tmpDataElements.length < 1)\n\t\t{\n\t\t\tconst tmpTableName = generateTableName(pParameters);\n\t\t\tif (!pIsForCountClause)\n\t\t\t{\n\t\t\t\treturn tmpTableName + '.*';\n\t\t\t}\n\t\t\t// we need to list all of the table fields explicitly; get them from the schema\n\t\t\tconst tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\t\t\tif (tmpSchema.length < 1)\n\t\t\t{\n\t\t\t\t// this means we have no schema; returning an empty string here signals the calling code to handle this case\n\t\t\t\treturn '';\n\t\t\t}\n\t\t\tconst idColumn = tmpSchema.find((entry) => entry.Type === 'AutoIdentity');\n\t\t\tif (!idColumn)\n\t\t\t{\n\t\t\t\t// this means there is no autoincrementing unique ID column; treat as above\n\t\t\t\treturn '';\n\t\t\t}\n\t\t\tconst qualifiedIDColumn = `${tmpTableName}.${idColumn.Column}`;\n\t\t\treturn ` ${generateSafeFieldName(qualifiedIDColumn)}`;\n\t\t}\n\n\t\tvar tmpFieldList = ' ';\n\t\tfor (var i = 0; i < tmpDataElements.length; i++)\n\t\t{\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\ttmpFieldList += ', ';\n\t\t\t}\n\t\t\tif (Array.isArray(tmpDataElements[i]))\n\t\t\t{\n\t\t\t\ttmpFieldList += generateSafeFieldName(tmpDataElements[i][0]);\n\t\t\t\tif (tmpDataElements[i].length > 1 && tmpDataElements[i][1])\n\t\t\t\t{\n\t\t\t\t\ttmpFieldList += \" AS \" + generateSafeFieldName(tmpDataElements[i][1]);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpFieldList += generateSafeFieldName(tmpDataElements[i]);\n\t\t\t}\n\t\t}\n\t\treturn tmpFieldList;\n\t};\n\n\tconst SURROUNDING_QUOTES_AND_WHITESPACE_REGEX = /^[` ]+|[` ]+$/g;\n\n\tconst cleanseQuoting = (str) =>\n\t{\n\t\treturn str.replace(SURROUNDING_QUOTES_AND_WHITESPACE_REGEX, '');\n\t};\n\n\t/**\n\t* Ensure a field name is properly escaped.\n\t*/\n\tvar generateSafeFieldName = function(pFieldName)\n\t{\n\t\tlet pFieldNames = pFieldName.split('.');\n\t\tif (pFieldNames.length > 1)\n\t\t{\n\t\t\tconst cleansedFieldName = cleanseQuoting(pFieldNames[1]);\n\t\t\tif (cleansedFieldName === '*')\n\t\t\t{\n\t\t\t\t// do not put * as `*`\n\t\t\t\treturn \"`\" + cleanseQuoting(pFieldNames[0]) + \"`.*\";\n\t\t\t}\n\t\t\treturn \"`\" + cleanseQuoting(pFieldNames[0]) + \"`.`\" + cleansedFieldName + \"`\";\n\t\t}\n\t\tconst cleansedFieldName = cleanseQuoting(pFieldNames[0]);\n\t\tif (cleansedFieldName === '*')\n\t\t{\n\t\t\t// do not put * as `*`\n\t\t\treturn '*';\n\t\t}\n\t\treturn \"`\" + cleanseQuoting(pFieldNames[0]) + \"`\";\n\t}\n\n\t/**\n\t* Generate a query from the array of where clauses\n\t*\n\t* Each clause is an object like:\n\t\t{\n\t\t\tColumn:'Name',\n\t\t\tOperator:'EQ',\n\t\t\tValue:'John',\n\t\t\tConnector:'And',\n\t\t\tParameter:'Name'\n\t\t}\n\t*\n\t* @method: generateWhere\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the WHERE clause prefixed with WHERE, or an empty string if unnecessary\n\t*/\n\tvar generateWhere = function(pParameters)\n\t{\n\t\tvar tmpFilter = Array.isArray(pParameters.filter) ? pParameters.filter : [];\n\t\tvar tmpTableName = generateTableName(pParameters);\n\n\t\tif (!pParameters.query.disableDeleteTracking)\n\t\t{\n\t\t\t// Check if there is a Deleted column on the Schema. If so, we add this to the filters automatically (if not already present)\n\t\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\tvar tmpSchemaEntry = tmpSchema[i];\n\n\t\t\t\tif (tmpSchemaEntry.Type === 'Deleted')\n\t\t\t\t{\n\t\t\t\t\tvar tmpHasDeletedParameter = false;\n\n\t\t\t\t\t//first, check to see if filters are already looking for Deleted column\n\t\t\t\t\tif (tmpFilter.length > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (var x = 0; x < tmpFilter.length; x++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (tmpFilter[x].Column === tmpSchemaEntry.Column)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttmpHasDeletedParameter = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (!tmpHasDeletedParameter)\n\t\t\t\t\t{\n\t\t\t\t\t\t//if not, we need to add it\n\t\t\t\t\t\ttmpFilter.push(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tColumn: tmpTableName + '.' + tmpSchemaEntry.Column,\n\t\t\t\t\t\t\tOperator: '=',\n\t\t\t\t\t\t\tValue: 0,\n\t\t\t\t\t\t\tConnector: 'AND',\n\t\t\t\t\t\t\tParameter: 'Deleted'\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (tmpFilter.length < 1)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpWhere = ' WHERE';\n\n\t\t// This is used to disable the connectors for subsequent queries.\n\t\t// Only the open parenthesis operator uses this, currently.\n\t\tvar tmpLastOperatorNoConnector = false;\n\n\t\tfor (var i = 0; i < tmpFilter.length; i++)\n\t\t{\n\t\t\tif ((tmpFilter[i].Connector != 'NONE') && (tmpFilter[i].Operator != ')') && (tmpWhere != ' WHERE') && (tmpLastOperatorNoConnector == false))\n\t\t\t{\n\t\t\t\ttmpWhere += ' '+tmpFilter[i].Connector;\n\t\t\t}\n\n\t\t\ttmpLastOperatorNoConnector = false;\n\n\t\t\tvar tmpColumnParameter;\n\n\t\t\tif (tmpFilter[i].Operator === '(')\n\t\t\t{\n\t\t\t\t// Open a logical grouping\n\t\t\t\ttmpWhere += ' (';\n\t\t\t\ttmpLastOperatorNoConnector = true;\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === ')')\n\t\t\t{\n\t\t\t\t// Close a logical grouping\n\t\t\t\ttmpWhere += ' )';\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IN' || tmpFilter[i].Operator === \"NOT IN\")\n\t\t\t{\n\t\t\t\ttmpColumnParameter = tmpFilter[i].Parameter+'_w'+i;\n\t\t\t\t// Add the column name, operator and parameter name to the list of where value parenthetical\n\t\t\t\ttmpWhere += ' '+tmpFilter[i].Column+' '+tmpFilter[i].Operator+' ( :'+tmpColumnParameter+' )';\n\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = tmpFilter[i].Value;\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IS NULL')\n\t\t\t{\n\t\t\t\t// IS NULL is a special operator which doesn't require a value, or parameter\n\t\t\t\ttmpWhere += ' '+tmpFilter[i].Column+' '+tmpFilter[i].Operator;\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IS NOT NULL')\n\t\t\t{\n\t\t\t\t// IS NOT NULL is a special operator which doesn't require a value, or parameter\n\t\t\t\ttmpWhere += ' '+tmpFilter[i].Column+' '+tmpFilter[i].Operator;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpColumnParameter = tmpFilter[i].Parameter+'_w'+i;\n\t\t\t\t// Add the column name, operator and parameter name to the list of where value parenthetical\n\t\t\t\ttmpWhere += ' '+tmpFilter[i].Column+' '+tmpFilter[i].Operator+' :'+tmpColumnParameter;\n\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = tmpFilter[i].Value;\n\t\t\t}\n\t\t}\n\n\t\treturn tmpWhere;\n\t};\n\n\t/**\n\t* Generate an ORDER BY clause from the sort array\n\t*\n\t* Each entry in the sort is an object like:\n\t* {Column:'Color',Direction:'Descending'}\n\t*\n\t* @method: generateOrderBy\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the field list clause\n\t*/\n\tvar generateOrderBy = function(pParameters)\n\t{\n\t\tvar tmpOrderBy = pParameters.sort;\n\t\tif (!Array.isArray(tmpOrderBy) || tmpOrderBy.length < 1)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpOrderClause = ' ORDER BY';\n\t\tfor (var i = 0; i < tmpOrderBy.length; i++)\n\t\t{\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\ttmpOrderClause += ',';\n\t\t\t}\n\t\t\ttmpOrderClause += ' '+tmpOrderBy[i].Column;\n\n\t\t\tif (tmpOrderBy[i].Direction == 'Descending')\n\t\t\t{\n\t\t\t\ttmpOrderClause += ' DESC';\n\t\t\t}\n\t\t}\n\t\treturn tmpOrderClause;\n\t};\n\n\t/**\n\t* Generate the limit clause\n\t*\n\t* @method: generateLimit\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateLimit = function(pParameters)\n\t{\n\t\tif (!pParameters.cap)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpLimit = ' LIMIT';\n\t\t// If there is a begin record, we'll pass that in as well.\n\t\tif (pParameters.begin !== false)\n\t\t{\n\t\t\ttmpLimit += ' ' + pParameters.begin + ',';\n\t\t}\n\t\t// Cap is required for a limit clause.\n\t\ttmpLimit += ' ' + pParameters.cap;\n\n\t\treturn tmpLimit;\n\t};\n\n\t/**\n\t* Generate the join clause\n\t*\n\t* @method: generateJoins\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the join clause\n\t*/\n\tvar generateJoins = function(pParameters)\n\t{\n\t\tvar tmpJoins = pParameters.join;\n\t\tif (!Array.isArray(tmpJoins) || tmpJoins.length < 1)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpJoinClause = ''; //ex. ' INNER JOIN';\n\t\tfor (var i = 0; i < tmpJoins.length; i++)\n\t\t{\n\t\t\tvar join = tmpJoins[i];\n\t\t\t//verify that all required fields are valid\n\t\t\tif (join.Type && join.Table && join.From && join.To)\n\t\t\t{\n\t\t\t\ttmpJoinClause += ` ${join.Type} ${join.Table} ON ${join.From} = ${join.To}`;\n\t\t\t}\n\t\t}\n\n\t\treturn tmpJoinClause;\n\t}\n\n\t/**\n\t* Generate the update SET clause\n\t*\n\t* @method: generateUpdateSetters\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateUpdateSetters = function(pParameters)\n\t{\n\t\tvar tmpRecords = pParameters.query.records;\n\t\t// We need to tell the query not to generate improperly if there are no values to set.\n\t\tif (!Array.isArray(tmpRecords) || tmpRecords.length < 1)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpUpdate = '';\n\t\t// If there is more than one record in records, we are going to ignore them for now.\n\t\tvar tmpCurrentColumn = 0;\n\t\tfor(var tmpColumn in tmpRecords[0])\n\t\t{\n\t\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\t\tvar tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\tif (tmpColumn == tmpSchema[i].Column)\n\t\t\t\t{\n\t\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\t\ttmpSchemaEntry = tmpSchema[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (pParameters.query.disableAutoDateStamp &&\n\t\t\t\ttmpSchemaEntry.Type === 'UpdateDate')\n\t\t\t{\n\t\t\t\t// This is ignored if flag is set\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (pParameters.query.disableAutoUserStamp &&\n\t\t\t\ttmpSchemaEntry.Type === 'UpdateIDUser')\n\t\t\t{\n\t\t\t\t// This is ignored if flag is set\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'AutoIdentity':\n\t\t\t\tcase 'CreateDate':\n\t\t\t\tcase 'CreateIDUser':\n\t\t\t\tcase 'DeleteDate':\n\t\t\t\tcase 'DeleteIDUser':\n\t\t\t\t\t// These are all ignored on update\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpUpdate += ',';\n\t\t\t}\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\ttmpUpdate += ' '+tmpColumn+' = ' + SQL_NOW;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateIDUser':\n\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\tvar tmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdate += ' '+tmpColumn+' = :'+tmpColumnParameter;\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tvar tmpColumnDefaultParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdate += ' '+tmpColumn+' = :'+tmpColumnDefaultParameter;\n\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnDefaultParameter] = tmpRecords[0][tmpColumn];\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// We use a number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (tmpUpdate === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpUpdate;\n\t};\n\n\t/**\n\t* Generate the update-delete SET clause\n\t*\n\t* @method: generateUpdateDeleteSetters\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateUpdateDeleteSetters = function(pParameters)\n\t{\n\t\tif (pParameters.query.disableDeleteTracking)\n\t\t{\n\t\t\t//Don't generate an UPDATE query if Delete tracking is disabled\n\t\t\treturn false;\n\t\t}\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpCurrentColumn = 0;\n\t\tvar tmpHasDeletedField = false;\n\t\tvar tmpUpdate = '';\n\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\tvar tmpSchemaEntry = {Type:'Default'};\n\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t{\n\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\ttmpSchemaEntry = tmpSchema[i];\n\n\t\t\tvar tmpUpdateSql = null;\n\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'Deleted':\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = 1';\n\t\t\t\t\ttmpHasDeletedField = true; //this field is required in order for query to be built\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'DeleteDate':\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = ' + SQL_NOW;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\t\t// Delete operation is an Update, so we should stamp the update time\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = ' + SQL_NOW;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'DeleteIDUser':\n\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\tvar tmpColumnParameter = tmpSchemaEntry.Column+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = :'+tmpColumnParameter;\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t//DON'T allow update of other fields in this query\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpUpdate += ',';\n\t\t\t}\n\n\t\t\ttmpUpdate += tmpUpdateSql;\n\n\t\t\t// We use a number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (!tmpHasDeletedField ||\n\t\t\ttmpUpdate === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpUpdate;\n\t};\n\n\t/**\n\t* Generate the update-undelete SET clause\n\t*\n\t* @method: generateUpdateUndeleteSetters\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateUpdateUndeleteSetters = function(pParameters)\n\t{\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpCurrentColumn = 0;\n\t\tvar tmpHasDeletedField = false;\n\t\tvar tmpUpdate = '';\n\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\tvar tmpSchemaEntry = {Type:'Default'};\n\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t{\n\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\ttmpSchemaEntry = tmpSchema[i];\n\n\t\t\tvar tmpUpdateSql = null;\n\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'Deleted':\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = 0';\n\t\t\t\t\ttmpHasDeletedField = true; //this field is required in order for query to be built\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\t\t// The undelete operation is an Update, so we should stamp the update time\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = ' + SQL_NOW;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateIDUser':\n\t\t\t\t\tvar tmpColumnParameter = tmpSchemaEntry.Column+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = :'+tmpColumnParameter;\n\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t//DON'T allow update of other fields in this query\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpUpdate += ',';\n\t\t\t}\n\n\t\t\ttmpUpdate += tmpUpdateSql;\n\n\t\t\t// We use a number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (!tmpHasDeletedField ||\n\t\t\ttmpUpdate === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpUpdate;\n\t};\n\n\t/**\n\t* Generate the create SET clause\n\t*\n\t* @method: generateCreateSetList\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateCreateSetValues = function(pParameters)\n\t{\n\t\tvar tmpRecords = pParameters.query.records;\n\t\t// We need to tell the query not to generate improperly if there are no values to set.\n\t\tif (!Array.isArray(tmpRecords) || tmpRecords.length < 1)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\n\t\tvar tmpCreateSet = '';\n\t\t// If there is more than one record in records, we are going to ignore them for now.\n\t\tvar tmpCurrentColumn = 0;\n\t\tfor(var tmpColumn in tmpRecords[0])\n\t\t{\n\t\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\t\tvar tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\tif (tmpColumn == tmpSchema[i].Column)\n\t\t\t\t{\n\t\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\t\ttmpSchemaEntry = tmpSchema[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!pParameters.query.disableDeleteTracking)\n\t\t\t{\n\t\t\t\tif (tmpSchemaEntry.Type === 'DeleteDate' ||\n\t\t\t\t\ttmpSchemaEntry.Type === 'DeleteIDUser')\n\t\t\t\t{\n\t\t\t\t\t// These are all ignored on insert (if delete tracking is enabled as normal)\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpCreateSet += ',';\n\t\t\t}\n\n\t\t\t//define a re-usable method for setting up field definitions in a default pattern\n\t\t\tvar buildDefaultDefinition = function()\n\t\t\t{\n\t\t\t\tvar tmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\ttmpCreateSet += ' :'+tmpColumnParameter;\n\t\t\t\t// Set the query parameter\n\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = tmpRecords[0][tmpColumn];\n\t\t\t};\n\n\t\t\tvar tmpColumnParameter;\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'AutoIdentity':\n\t\t\t\t\tif (pParameters.query.disableAutoIdentity)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\t\ttmpCreateSet += ' NULL';\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'AutoGUID':\n\t\t\t\t\tif (pParameters.query.disableAutoIdentity)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse if (tmpRecords[0][tmpColumn] &&\n\t\t\t\t\t\t\ttmpRecords[0][tmpColumn].length >= 5 &&\n\t\t\t\t\t\t\ttmpRecords[0][tmpColumn] !== '0x0000000000000000') //stricture default\n\t\t\t\t\t{\n\t\t\t\t\t\t// Allow consumer to override AutoGUID\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\t\ttmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\t\ttmpCreateSet += ' :'+tmpColumnParameter;\n\t\t\t\t\t\t// Set the query parameter\n\t\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.UUID;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\tcase 'CreateDate':\n\t\t\t\tcase 'DeleteDate':\n\t\t\t\t\tif (pParameters.query.disableAutoDateStamp)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\t\ttmpCreateSet += ' ' + SQL_NOW;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'DeleteIDUser':\n\t\t\t\tcase 'UpdateIDUser':\n\t\t\t\tcase 'CreateIDUser':\n\t\t\t\t\tif (pParameters.query.disableAutoUserStamp)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\t\ttmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\t\ttmpCreateSet += ' :'+tmpColumnParameter;\n\t\t\t\t\t\t// Set the query parameter\n\t\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// We use an appended number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (tmpCreateSet === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpCreateSet;\n\t};\n\n\t/**\n\t* Generate the create SET clause\n\t*\n\t* @method: generateCreateSetList\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateCreateSetList = function(pParameters)\n\t{\n\t\t// The records were already validated by generateCreateSetValues\n\t\tvar tmpRecords = pParameters.query.records;\n\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpCreateSet = '';\n\t\t// If there is more than one record in records, we are going to ignore them for now.\n\t\tfor(var tmpColumn in tmpRecords[0])\n\t\t{\n\t\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\t\tvar tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\tif (tmpColumn == tmpSchema[i].Column)\n\t\t\t\t{\n\t\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\t\ttmpSchemaEntry = tmpSchema[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!pParameters.query.disableDeleteTracking)\n\t\t\t{\n\t\t\t\tif (tmpSchemaEntry.Type === 'DeleteDate' ||\n\t\t\t\t\ttmpSchemaEntry.Type === 'DeleteIDUser')\n\t\t\t\t{\n\t\t\t\t\t// These are all ignored on insert (if delete tracking is enabled as normal)\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tdefault:\n\t\t\t\t\tif (tmpCreateSet != '')\n\t\t\t\t\t{\n\t\t\t\t\t\ttmpCreateSet += ',';\n\t\t\t\t\t}\n\t\t\t\t\ttmpCreateSet += ' '+tmpColumn;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn tmpCreateSet;\n\t};\n\n\n\tvar Create = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpCreateSetList = generateCreateSetList(pParameters);\n\t\tvar tmpCreateSetValues = generateCreateSetValues(pParameters);\n\n\t\tif (!tmpCreateSetValues)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn 'INSERT INTO'+tmpTableName+' ('+tmpCreateSetList+') VALUES ('+tmpCreateSetValues+');';\n\t};\n\n\n\t/**\n\t* Read one or many records\n\t*\n\t* Some examples:\n\t* SELECT * FROM WIDGETS;\n\t* SELECT * FROM WIDGETS LIMIT 0, 20;\n\t* SELECT * FROM WIDGETS LIMIT 5, 20;\n\t* SELECT ID, Name, Cost FROM WIDGETS LIMIT 5, 20;\n\t* SELECT ID, Name, Cost FROM WIDGETS LIMIT 5, 20 WHERE LastName = 'Smith';\n\t*\n\t* @method Read\n\t* @param {Object} pParameters SQL Query parameters\n\t* @return {String} Returns the current Query for chaining.\n\t*/\n\tvar Read = function(pParameters)\n\t{\n\t\tvar tmpFieldList = generateFieldList(pParameters);\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpJoin = generateJoins(pParameters);\n\t\tvar tmpOrderBy = generateOrderBy(pParameters);\n\t\tvar tmpLimit = generateLimit(pParameters);\n\t\tconst tmpOptDistinct = pParameters.distinct ? ' DISTINCT' : '';\n\n\t\tif (pParameters.queryOverride)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tvar tmpQueryTemplate = _Fable.Utility.template(pParameters.queryOverride);\n\t\t\t\treturn tmpQueryTemplate({FieldList:tmpFieldList, TableName:tmpTableName, Where:tmpWhere, Join:tmpJoin, OrderBy:tmpOrderBy, Limit:tmpLimit, Distinct: tmpOptDistinct, _Params: pParameters});\n\t\t\t}\n\t\t\tcatch (pError)\n\t\t\t{\n\t\t\t\t// This pokemon is here to give us a convenient way of not throwing up totally if the query fails.\n\t\t\t\tconsole.log('Error with custom Read Query ['+pParameters.queryOverride+']: '+pError);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn `SELECT${tmpOptDistinct}${tmpFieldList} FROM${tmpTableName}${tmpJoin}${tmpWhere}${tmpOrderBy}${tmpLimit};`;\n\t};\n\n\tvar Update = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpUpdateSetters = generateUpdateSetters(pParameters);\n\n\t\tif (!tmpUpdateSetters)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn 'UPDATE'+tmpTableName+' SET'+tmpUpdateSetters+tmpWhere+';';\n\t};\n\n\tvar Delete = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpUpdateDeleteSetters = generateUpdateDeleteSetters(pParameters);\n\n\t\tif (tmpUpdateDeleteSetters)\n\t\t{\n\t\t\t//If it has a deleted bit, update it instead of actually deleting the record\n\t\t\treturn 'UPDATE'+tmpTableName+' SET'+tmpUpdateDeleteSetters+tmpWhere+';';\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn 'DELETE FROM'+tmpTableName+tmpWhere+';';\n\t\t}\n\t};\n\n\tvar Undelete = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\t// TODO: Fix these\n\t\tlet tmpDeleteTrackingState = pParameters.query.disableDeleteTracking;\n\t\tpParameters.query.disableDeleteTracking = true;\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpUpdateUndeleteSetters = generateUpdateUndeleteSetters(pParameters);\n\t\tpParameters.query.disableDeleteTracking = tmpDeleteTrackingState;\n\n\t\tif (tmpUpdateUndeleteSetters)\n\t\t{\n\t\t\t//If the table has a deleted bit, go forward with the update to change things.\n\t\t\treturn 'UPDATE'+tmpTableName+' SET'+tmpUpdateUndeleteSetters+tmpWhere+';';\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// This is a no-op because the record can't be undeleted.\n\t\t\t// TODO: Should it throw instead?\n\t\t\treturn 'SELECT NULL;';\n\t\t}\n\t};\n\n\tvar Count = function(pParameters)\n\t{\n\t\tvar tmpFieldList = pParameters.distinct ? generateFieldList(pParameters, true) : '*';\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpJoin = generateJoins(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\t// here, we ignore the distinct keyword if no fields have been specified and\n\t\tif (pParameters.distinct && tmpFieldList.length < 1)\n\t\t{\n\t\t\tconsole.warn('Distinct requested but no field list or schema are available, so not honoring distinct for count query.');\n\t\t}\n\t\tconst tmpOptDistinct = pParameters.distinct && tmpFieldList.length > 0 ? 'DISTINCT' : '';\n\n\t\tif (pParameters.queryOverride)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tvar tmpQueryTemplate = _Fable.Utility.template(pParameters.queryOverride);\n\t\t\t\treturn tmpQueryTemplate({FieldList:[], TableName:tmpTableName, Where:tmpWhere, OrderBy:'', Limit:'', Distinct: tmpOptDistinct, _Params: pParameters});\n\t\t\t}\n\t\t\tcatch (pError)\n\t\t\t{\n\t\t\t\t// This pokemon is here to give us a convenient way of not throwing up totally if the query fails.\n\t\t\t\tconsole.log('Error with custom Count Query ['+pParameters.queryOverride+']: '+pError);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn `SELECT COUNT(${tmpOptDistinct}${tmpFieldList || '*'}) AS RowCount FROM${tmpTableName}${tmpJoin}${tmpWhere};`;\n\t};\n\n\tvar tmpDialect = ({\n\t\tCreate: Create,\n\t\tRead: Read,\n\t\tUpdate: Update,\n\t\tDelete: Delete,\n\t\tUndelete: Undelete,\n\t\tCount: Count\n\t});\n\n\t/**\n\t* Dialect Name\n\t*\n\t* @property name\n\t* @type string\n\t*/\n\tObject.defineProperty(tmpDialect, 'name',\n\t\t{\n\t\t\tget: function() { return 'MySQL'; },\n\t\t\tenumerable: true\n\t\t});\n\n\treturn tmpDialect;\n};\n\nmodule.exports = FoxHoundDialectMySQL;\n"]}
|
|
1
|
+
{"version":3,"sources":["node_modules/browser-pack/_prelude.js","source/Foxhound-Browser-Shim.js","foxhound.min.js","source/Foxhound-Dialects.js","source/Foxhound.js","source/Parameters.js","source/dialects/ALASQL/FoxHound-Dialect-ALASQL.js","source/dialects/English/FoxHound-Dialect-English.js","source/dialects/MeadowEndpoints/FoxHound-Dialect-MeadowEndpoints.js","source/dialects/MySQL/FoxHound-Dialect-MySQL.js"],"names":["f","exports","module","define","amd","window","global","self","this","Foxhound","r","e","n","t","o","i","c","require","u","a","Error","code","p","call","length","libNPMModuleWrapper","hasOwnProperty","getDialects","tmpDialects","ALASQL","English","MeadowEndpoints","MySQL","default","baseParameters","createNew","pFable","pFromParameters","new","_Fable","_DefaultParameters","_Parameters","_Dialects","_UUID","getUUID","_LogLevel","_Dialect","resetParameters","Utility","extend","query","disableAutoIdentity","disableAutoDateStamp","disableAutoUserStamp","disableDeleteTracking","body","schema","IDUser","UUID","records","parameters","result","executed","value","error","undefined","addJoin","pTable","pFrom","pTo","pType","log","warn","queryUUID","indexOf","invalidField","tmpJoin","Type","Table","From","To","Array","isArray","join","push","info","setDialect","pDialectName","invalidDialect","checkDialect","tmpNewFoxHoundObject","mergeParameters","setLogLevel","pLogLevel","tmpLogLevel","setScope","pScope","tmpScope","invalidScope","scope","setDistinct","pDistinct","distinct","setIDUser","pIDUser","tmpUserID","invalidIDUser","userID","setDataElements","pDataElements","tmpDataElements","dataElements","setBegin","pBeginAmount","tmpBegin","invalidBeginAmount","begin","setCap","pCapAmount","tmpCapAmount","invalidCapAmount","cap","setFilter","pFilter","tmpFilter","filter","addFilter","pColumn","pValue","pOperator","pConnector","pParameter","invalidColumn","tmpParameter","Column","Operator","Value","Connector","Parameter","replace","newFilter","setSort","pSort","tmpSort","Direction","sort","addSort","setJoin","pJoin","forEach","addRecord","pRecord","newRecord","setDisableAutoIdentity","pFlag","setDisableAutoDateStamp","setDisableAutoUserStamp","setDisableDeleteTracking","buildCreateQuery","Create","buildReadQuery","Read","buildUpdateQuery","Update","buildDeleteQuery","Delete","buildUndeleteQuery","Undelete","buildCountQuery","Count","clone","tmpFoxHound","slice","Object","defineProperty","get","set","pQuery","enumerable","pResult","pParameters","queryOverride","generateTableName","escapeColumn","tmpTableName","generateFieldList","pIsForCountClause","tmpSchema","idColumn","find","entry","tmpFieldList","generateWhere","trim","tmpSchemaEntry","tmpHasDeletedParameter","x","tmpWhere","tmpLastOperatorNoConnector","tmpColumnParameter","tmpDialect","tmpCreateSetList","tmpRecords","tmpCreateSet","tmpColumn","generateCreateSetList","tmpCreateSetValues","tmpCurrentColumn","buildDefaultDefinition","generateCreateSetValues","tmpOrderBy","tmpOrderClause","generateOrderBy","tmpLimit","generateLimit","tmpOptDistinct","template","tmpQueryTemplate","FieldList","TableName","Where","OrderBy","Limit","Distinct","_Params","pError","console","tmpUpdateSetters","tmpUpdate","tmpColumnDefaultParameter","generateUpdateSetters","tmpUpdateDeleteSetters","tmpHasDeletedField","tmpUpdateSql","generateUpdateDeleteSetters","tmpDeleteTrackingState","tmpUpdateUndeleteSetters","generateUpdateUndeleteSetters","tmpURL","tmpfAddFilter","pFilterCommand","pFilterParameters","tmpfTranslateOperator","tmpNewOperator","toUpperCase","tmpFilterCommand","map","encodeURIComponent","generateFlags","tmpDisableAutoDateStamp","tmpDisableDeleteTracking","tmpDisableAutoIdentity","tmpDisableAutoUserStamp","tmpFlags","fAddFlag","pFlagSet","generateIdentityColumnName","tmpIDRecord","j","getIDRecord","SQL_NOW","qualifiedIDColumn","generateSafeFieldName","SURROUNDING_QUOTES_AND_WHITESPACE_REGEX","cleanseQuoting","str","pFieldName","pFieldNames","split","cleansedFieldName","generateJoins","tmpJoins","tmpJoinClause","Join"],"mappings":"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","file":"foxhound.min.js","sourcesContent":["(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()","/**\n* Simple browser shim loader - assign the npm module to a window global automatically\n*\n* @license MIT\n* @author <steven@velozo.com>\n*/\nvar libNPMModuleWrapper = require('./Foxhound.js');\n\nif ((typeof(window) === 'object') && !window.hasOwnProperty('Foxhound'))\n{\n\twindow.Foxhound = libNPMModuleWrapper;\n}\n\nmodule.exports = libNPMModuleWrapper;","(function(f){if(typeof exports===\"object\"&&typeof module!==\"undefined\"){module.exports=f()}else if(typeof define===\"function\"&&define.amd){define([],f)}else{var g;if(typeof window!==\"undefined\"){g=window}else if(typeof global!==\"undefined\"){g=global}else if(typeof self!==\"undefined\"){g=self}else{g=this}g.Foxhound = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){\n/**\n* Simple browser shim loader - assign the npm module to a window global automatically\n*\n* @license MIT\n* @author <steven@velozo.com>\n*/\nvar libNPMModuleWrapper = require('./Foxhound.js');\n\nif ((typeof(window) === 'object') && !window.hasOwnProperty('Foxhound'))\n{\n\twindow.Foxhound = libNPMModuleWrapper;\n}\n\nmodule.exports = libNPMModuleWrapper;\n},{\"./Foxhound.js\":3}],2:[function(require,module,exports){\ngetDialects = () =>\n{\n\tlet tmpDialects = {};\n\n\ttmpDialects.ALASQL = require('./dialects/ALASQL/FoxHound-Dialect-ALASQL.js');\n\ttmpDialects.English = require('./dialects/English/FoxHound-Dialect-English.js');\n\ttmpDialects.MeadowEndpoints = require('./dialects/MeadowEndpoints/FoxHound-Dialect-MeadowEndpoints.js');\n\ttmpDialects.MySQL = require('./dialects/MySQL/FoxHound-Dialect-MySQL.js');\n\n\ttmpDialects.default = tmpDialects.English;\n\n\treturn tmpDialects;\n}\n\nmodule.exports = getDialects();\n},{\"./dialects/ALASQL/FoxHound-Dialect-ALASQL.js\":5,\"./dialects/English/FoxHound-Dialect-English.js\":6,\"./dialects/MeadowEndpoints/FoxHound-Dialect-MeadowEndpoints.js\":7,\"./dialects/MySQL/FoxHound-Dialect-MySQL.js\":8}],3:[function(require,module,exports){\n/**\n* FoxHound Query Generation Library\n* @license MIT\n* @author Steven Velozo <steven@velozo.com>\n*/\n\n// Load our base parameters skeleton object\nconst baseParameters = require('./Parameters.js');\n\nvar FoxHound = function()\n{\n\tfunction createNew(pFable, pFromParameters)\n\t{\n\t\t// If a valid Fable object isn't passed in, return a constructor\n\t\tif ((typeof(pFable) !== 'object') || !('fable' in pFable))\n\t\t{\n\t\t\treturn {new: createNew};\n\t\t}\n\n\t\tvar _Fable = pFable;\n\n\t\t// The default parameters config object, used as a template for all new\n\t\t// queries created from this query.\n\t\tvar _DefaultParameters = (typeof(pFromParameters) === 'undefined') ? {} : pFromParameters;\n\n\t\t// The parameters config object for the current query. This is the only\n\t\t// piece of internal state that is important to operation.\n\t\tvar _Parameters = false;\n\n\t\tvar _Dialects = require('./Foxhound-Dialects.js');\n\n\t\t// The unique identifier for a query\n\t\tvar _UUID = _Fable.getUUID();\n\n\t\t// The log level, for debugging chattiness.\n\t\tvar _LogLevel = 0;\n\n\t\t// The dialect to use when generating queries\n\t\tvar _Dialect = false;\n\n\t\t/**\n\t\t* Clone the current FoxHound Query into a new Query object, copying all\n\t\t* parameters as the new default. Clone also copies the log level.\n\t\t*\n\t\t* @method clone\n\t\t* @return {Object} Returns a cloned Query. This is still chainable.\n\t\t*/\n\t\tvar clone = function()\n\t\t{\n\t\t\tvar tmpFoxHound = createNew(_Fable, baseParameters)\n\t\t\t\t.setScope(_Parameters.scope)\n\t\t\t\t.setBegin(_Parameters.begin)\n\t\t\t\t.setCap(_Parameters.cap);\n\n\t\t\t// Schema is the only part of a query that carries forward.\n\t\t\ttmpFoxHound.query.schema = _Parameters.query.schema;\n\n\t\t\tif (_Parameters.dataElements)\n\t\t\t{\n\t\t\t\ttmpFoxHound.parameters.dataElements = _Parameters.dataElements.slice(); // Copy the array of dataElements\n\t\t\t}\n\t\t\tif (_Parameters.sort)\n\t\t\t{\n\t\t\t\ttmpFoxHound.parameters.sort = _Parameters.sort.slice(); // Copy the sort array.\n\t\t\t\t// TODO: Fix the side affect nature of these being objects in the array .. they are technically clones of the previous.\n\t\t\t}\n\t\t\tif (_Parameters.filter)\n\t\t\t{\n\t\t\t\ttmpFoxHound.parameters.filter = _Parameters.filter.slice(); // Copy the filter array.\n\t\t\t\t// TODO: Fix the side affect nature of these being objects in the array .. they are technically clones of the previous.\n\t\t\t}\n\n\t\t\treturn tmpFoxHound;\n\t\t};\n\n\n\t\t/**\n\t\t* Reset the parameters of the FoxHound Query to the Default. Default\n\t\t* parameters were set during object construction.\n\t\t*\n\t\t* @method resetParameters\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar resetParameters = function()\n\t\t{\n\t\t\t_Parameters = _Fable.Utility.extend({}, baseParameters, _DefaultParameters);\n\t\t\t_Parameters.query = ({\n\t\t\t\tdisableAutoIdentity: false,\n\t\t\t\tdisableAutoDateStamp: false,\n\t\t\t\tdisableAutoUserStamp: false,\n\t\t\t\tdisableDeleteTracking: false,\n\t\t\t\tbody: false,\n\t\t\t\tschema: false, // The schema to intersect with our records\n\t\t\t\tIDUser: 0, // The user to stamp into records\n\t\t\t\tUUID: _Fable.getUUID(), // A UUID for this record\n\t\t\t\trecords: false, // The records to be created or changed\n\t\t\t\tparameters: {}\n\t\t\t});\n\n\t\t\t_Parameters.result = ({\n\t\t\t\texecuted: false, // True once we've run a query.\n\t\t\t\tvalue: false, // The return value of the last query run\n\t\t\t\t// Updated below due to changes in how Async.js responds to a false value here\n\t\t\t\terror: undefined // The error message of the last run query\n\t\t\t});\n\n\t\t\treturn this;\n\t\t};\n\t\tresetParameters();\n\n\t\t/**\n\t\t* Reset the parameters of the FoxHound Query to the Default. Default\n\t\t* parameters were set during object construction.\n\t\t*\n\t\t* @method mergeParameters\n\t\t* @param {Object} pFromParameters A Parameters Object to merge from\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar mergeParameters = function(pFromParameters)\n\t\t{\n\t\t\t_Parameters = _Fable.Utility.extend({}, _Parameters, pFromParameters);\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the the Logging level.\n\t\t*\n\t\t* The log levels are:\n\t\t* 0 - Don't log anything\n\t\t* 1 - Log queries\n\t\t* 2 - Log queries and non-parameterized queries\n\t\t* 3 - Log everything\n\t\t*\n\t\t* @method setLogLevel\n\t\t* @param {Number} pLogLevel The log level for our object\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setLogLevel = function(pLogLevel)\n\t\t{\n\t\t\tvar tmpLogLevel = 0;\n\n\t\t\tif (typeof(pLogLevel) === 'number' && (pLogLevel % 1) === 0)\n\t\t\t{\n\t\t\t\ttmpLogLevel = pLogLevel;\n\t\t\t}\n\n\t\t\t_LogLevel = tmpLogLevel;\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the Scope for the Query. *Scope* is the source for the data being\n\t\t* pulled. In TSQL this would be the _table_, whereas in MongoDB this\n\t\t* would be the _collection_.\n\t\t*\n\t\t* A scope can be either a string, or an array (for JOINs and such).\n\t\t*\n\t\t* @method setScope\n\t\t* @param {String} pScope A Scope for the Query.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setScope = function(pScope)\n\t\t{\n\t\t\tvar tmpScope = false;\n\n\t\t\tif (typeof(pScope) === 'string')\n\t\t\t{\n\t\t\t\ttmpScope = pScope;\n\t\t\t}\n\t\t\telse if (pScope !== false)\n\t\t\t{\n\t\t\t\t_Fable.log.error('Scope set failed. You must pass in a string or array.', {queryUUID:_UUID, parameters:_Parameters, invalidScope:pScope});\n\t\t\t}\n\n\t\t\t_Parameters.scope = tmpScope;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Scope set: '+tmpScope, {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\t\t/**\n\t\t* Set whether the query returns DISTINCT results.\n\t\t* For count queries, returns the distinct for the selected fields, or all fields in the base table by default.\n\t\t*\n\t\t* @method setDistinct\n\t\t* @param {Boolean} pDistinct True if the query should be distinct.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setDistinct = function(pDistinct)\n\t\t{\n\t\t\t_Parameters.distinct = !!pDistinct;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Distinct set: '+_Parameters.distinct, {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the Data Elements for the Query. *Data Elements* are the fields\n\t\t* being pulled by the query. In TSQL this would be the _columns_,\n\t\t* whereas in MongoDB this would be the _fields_.\n\t\t*\n\t\t* The passed values can be either a string, or an array.\n\t\t*\n\t\t* @method setDataElements\n\t\t* @param {String} pDataElements The Data Element(s) for the Query.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setDataElements = function(pDataElements)\n\t\t{\n\t\t\tvar tmpDataElements = false;\n\n\t\t\tif (Array.isArray(pDataElements))\n\t\t\t{\n\t\t\t\t// TODO: Check each entry of the array are all strings\n\t\t\t\ttmpDataElements = pDataElements;\n\t\t\t}\n\t\t\tif (typeof(pDataElements) === 'string')\n\t\t\t{\n\t\t\t\ttmpDataElements = [pDataElements];\n\t\t\t}\n\n\t\t\t_Parameters.dataElements = tmpDataElements;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Data Elements set', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the sort data element\n\t\t*\n\t\t* The passed values can be either a string, an object or an array of objects.\n\t\t*\n\t\t* The Sort object has two values:\n\t\t* {Column:'Birthday', Direction:'Ascending'}\n\t\t*\n\t\t* @method setSort\n\t\t* @param {String} pSort The sort criteria(s) for the Query.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setSort = function(pSort)\n\t\t{\n\t\t\tvar tmpSort = false;\n\n\t\t\tif (Array.isArray(pSort))\n\t\t\t{\n\t\t\t\t// TODO: Check each entry of the array are all conformant sort objects\n\t\t\t\ttmpSort = pSort;\n\t\t\t}\n\t\t\telse if (typeof(pSort) === 'string')\n\t\t\t{\n\t\t\t\t// Default to ascending\n\t\t\t\ttmpSort = [{Column:pSort, Direction:'Ascending'}];\n\t\t\t}\n\t\t\telse if (typeof(pSort) === 'object')\n\t\t\t{\n\t\t\t\t// TODO: Check that this sort entry conforms to a sort entry\n\t\t\t\ttmpSort = [pSort];\n\t\t\t}\n\n\t\t\t_Parameters.sort = tmpSort;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Sort set', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\t\t/**\n\t\t* Set the join data element\n\t\t*\n\t\t* The passed values can be either an object or an array of objects.\n\t\t*\n\t\t* The join object has four values:\n\t\t* {Type:'INNER JOIN', Table:'Test', From:'Test.ID', To:'Scope.IDItem'}\n\t\t*\n\t\t* @method setJoin\n\t\t* @param {Object} pJoin The join criteria(s) for the Query.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setJoin = function(pJoin)\n\t\t{\n\t\t\t_Parameters.join = [];\n\n\t\t\tif (Array.isArray(pJoin))\n\t\t\t{\n\t\t\t\tpJoin.forEach(function(join)\n\t\t\t\t{\n\t\t\t\t\taddJoin(join.Table, join.From, join.To, join.Type);\n\t\t\t\t});\n\t\t\t}\n\t\t\telse if (typeof(pJoin) === 'object')\n\t\t\t{\n\t\t\t\taddJoin(pJoin.Table, pJoin.From, pJoin.To, pJoin.Type);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Add a sort data element\n\t\t*\n\t\t* The passed values can be either a string, an object or an array of objects.\n\t\t*\n\t\t* The Sort object has two values:\n\t\t* {Column:'Birthday', Direction:'Ascending'}\n\t\t*\n\t\t* @method setSort\n\t\t* @param {String} pSort The sort criteria to add to the Query.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar addSort = function(pSort)\n\t\t{\n\t\t\tvar tmpSort = false;\n\n\t\t\tif (typeof(pSort) === 'string')\n\t\t\t{\n\t\t\t\t// Default to ascending\n\t\t\t\ttmpSort = {Column:pSort, Direction:'Ascending'};\n\t\t\t}\n\t\t\tif (typeof(pSort) === 'object')\n\t\t\t{\n\t\t\t\t// TODO: Check that this sort entry conforms to a sort entry\n\t\t\t\ttmpSort = pSort;\n\t\t\t}\n\n\t\t\tif (!_Parameters.sort)\n\t\t\t{\n\t\t\t\t_Parameters.sort = [];\n\t\t\t}\n\n\t\t\t_Parameters.sort.push(tmpSort);\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Sort set', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the the Begin index for the Query. *Begin* is the index at which\n\t\t* a query should start returning rows. In TSQL this would be the n\n\t\t* parameter of ```LIMIT 1,n```, whereas in MongoDB this would be the\n\t\t* n in ```skip(n)```.\n\t\t*\n\t\t* The passed value must be an Integer >= 0.\n\t\t*\n\t\t* @method setBegin\n\t\t* @param {Number} pBeginAmount The index to begin returning Query data.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setBegin = function(pBeginAmount)\n\t\t{\n\t\t\tvar tmpBegin = false;\n\n\t\t\t// Test if it is an integer > -1\n\t\t\t// http://jsperf.com/numbers-and-integers\n\t\t\tif (typeof(pBeginAmount) === 'number' && (pBeginAmount % 1) === 0 && pBeginAmount >= 0)\n\t\t\t{\n\t\t\t\ttmpBegin = pBeginAmount;\n\t\t\t}\n\t\t\telse if (pBeginAmount !== false)\n\t\t\t{\n\t\t\t\t_Fable.log.error('Begin set failed; non-positive or non-numeric argument.', {queryUUID:_UUID, parameters:_Parameters, invalidBeginAmount:pBeginAmount});\n\t\t\t}\n\n\t\t\t_Parameters.begin = tmpBegin;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Begin set: '+pBeginAmount, {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the the Cap for the Query. *Cap* is the maximum number of records\n\t\t* a Query should return in a set. In TSQL this would be the n\n\t\t* parameter of ```LIMIT n```, whereas in MongoDB this would be the\n\t\t* n in ```limit(n)```.\n\t\t*\n\t\t* The passed value must be an Integer >= 0.\n\t\t*\n\t\t* @method setCap\n\t\t* @param {Number} pCapAmount The maximum records for the Query set.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setCap = function(pCapAmount)\n\t\t{\n\t\t\tvar tmpCapAmount = false;\n\n\t\t\tif (typeof(pCapAmount) === 'number' && (pCapAmount % 1) === 0 && pCapAmount >= 0)\n\t\t\t{\n\t\t\t\ttmpCapAmount = pCapAmount;\n\t\t\t}\n\t\t\telse if (pCapAmount !== false)\n\t\t\t{\n\t\t\t\t_Fable.log.error('Cap set failed; non-positive or non-numeric argument.', {queryUUID:_UUID, parameters:_Parameters, invalidCapAmount:pCapAmount});\n\t\t\t}\n\n\n\t\t\t_Parameters.cap = tmpCapAmount;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Cap set to: '+tmpCapAmount, {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the filter expression\n\t\t*\n\t\t* The passed values can be either an object or an array of objects.\n\t\t*\n\t\t* The Filter object has a minimum of two values (which expands to the following):\n\t\t* {Column:'Name', Value:'John'}\n\t\t* {Column:'Name', Operator:'EQ', Value:'John', Connector:'And', Parameter:'Name'}\n\t\t*\n\t\t* @method setFilter\n\t\t* @param {String} pFilter The filter(s) for the Query.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setFilter = function(pFilter)\n\t\t{\n\t\t\tvar tmpFilter = false;\n\n\t\t\tif (Array.isArray(pFilter))\n\t\t\t{\n\t\t\t\t// TODO: Check each entry of the array are all conformant Filter objects\n\t\t\t\ttmpFilter = pFilter;\n\t\t\t}\n\t\t\telse if (typeof(pFilter) === 'object')\n\t\t\t{\n\t\t\t\t// TODO: Check that this Filter entry conforms to a Filter entry\n\t\t\t\ttmpFilter = [pFilter];\n\t\t\t}\n\n\t\t\t_Parameters.filter = tmpFilter;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Filter set', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\n\t\t/**\n\t\t* Add a filter expression\n\t\t*\n\t\t* {Column:'Name', Operator:'EQ', Value:'John', Connector:'And', Parameter:'Name'}\n\t\t*\n\t\t* @method addFilter\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar addFilter = function(pColumn, pValue, pOperator, pConnector, pParameter)\n\t\t{\n\t\t\tif (typeof(pColumn) !== 'string')\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid query filter column', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tif (typeof(pValue) === 'undefined')\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid query filter value', {queryUUID:_UUID, parameters:_Parameters, invalidColumn:pColumn});\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tvar tmpOperator = (typeof(pOperator) === 'undefined') ? '=' : pOperator;\n\t\t\tvar tmpConnector = (typeof(pConnector) === 'undefined') ? 'AND' : pConnector;\n\t\t\tvar tmpParameter = (typeof(pParameter) === 'undefined') ? pColumn : pParameter;\n\n\t\t\t//support table.field notation (mysql2 requires this)\n\t\t\ttmpParameter = tmpParameter.replace('.', '_');\n\n\t\t\tvar tmpFilter = (\n\t\t\t\t{\n\t\t\t\t\tColumn: pColumn,\n\t\t\t\t\tOperator: tmpOperator,\n\t\t\t\t\tValue: pValue,\n\t\t\t\t\tConnector: tmpConnector,\n\t\t\t\t\tParameter: tmpParameter\n\t\t\t\t});\n\n\t\t\tif (!Array.isArray(_Parameters.filter))\n\t\t\t{\n\t\t\t\t_Parameters.filter = [tmpFilter];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_Parameters.filter.push(tmpFilter);\n\t\t\t}\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Added a filter', {queryUUID:_UUID, parameters:_Parameters, newFilter:tmpFilter});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\t\t/**\n\t\t* Add a join expression\n\t\t*\n\t\t* {Type:'INNER JOIN', Table:'Test', From:'Test.ID', To:'Scope.IDItem'}\n\t\t*\n\t\t* @method addJoin\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar addJoin = function(pTable, pFrom, pTo, pType)\n\t\t{\n\t\t\tif (typeof(pTable) !== 'string')\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid query join table', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tif (typeof(pFrom) === 'undefined' || typeof(pTo) === 'undefined')\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid query join field', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\t//sanity check the join fields\n\t\t\tif (pFrom.indexOf(pTable)!=0)\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid query join field, join must come FROM the join table!', {queryUUID:_UUID, parameters:_Parameters, invalidField:pFrom});\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tif (pTo.indexOf('.')<=0)\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid query join field, join must go TO a field on another table ([table].[field])!', {queryUUID:_UUID, parameters:_Parameters, invalidField:pTo});\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tvar tmpType = (typeof(pType) === 'undefined') ? 'INNER JOIN' : pType;\n\n\t\t\tvar tmpJoin = (\n\t\t\t\t{\n\t\t\t\t\tType: tmpType,\n\t\t\t\t\tTable: pTable,\n\t\t\t\t\tFrom: pFrom,\n\t\t\t\t\tTo: pTo\n\t\t\t\t});\n\n\t\t\tif (!Array.isArray(_Parameters.join))\n\t\t\t{\n\t\t\t\t_Parameters.join = [tmpJoin];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_Parameters.join.push(tmpJoin);\n\t\t\t}\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Added a join', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\n\t\t/**\n\t\t* Add a record (for UPDATE and INSERT)\n\t\t*\n\t\t*\n\t\t* @method addRecord\n\t\t* @param {Object} pRecord The record to add.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar addRecord = function(pRecord)\n\t\t{\n\t\t\tif (typeof(pRecord) !== 'object')\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid record to the query -- records must be an object', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tif (!Array.isArray(_Parameters.query.records))\n\t\t\t{\n\t\t\t\t_Parameters.query.records = [pRecord];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_Parameters.query.records.push(pRecord);\n\t\t\t}\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Added a record to the query', {queryUUID:_UUID, parameters:_Parameters, newRecord:pRecord});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\n\t\t/**\n\t\t* Set the Dialect for Query generation.\n\t\t*\n\t\t* This function expects a string, case sensitive, which matches both the\n\t\t* folder and filename\n\t\t*\n\t\t* @method setDialect\n\t\t* @param {String} pDialectName The dialect for query generation.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setDialect = function(pDialectName)\n\t\t{\n\n\t\t\tif (typeof(pDialectName) !== 'string')\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Dialect set to English - invalid name', {queryUUID:_UUID, parameters:_Parameters, invalidDialect:pDialectName});\n\t\t\t\treturn setDialect('English');\n\t\t\t}\n\n\t\t\tif (_Dialects.hasOwnProperty(pDialectName))\n\t\t\t{\n\t\t\t\t_Dialect = _Dialects[pDialectName](_Fable);\n\t\t\t\tif (_LogLevel > 2)\n\t\t\t\t{\n\t\t\t\t\t_Fable.log.info('Dialog set to: '+pDialectName, {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_Fable.log.error('Dialect not set - unknown dialect \"'+pDialectName+\"'\", {queryUUID:_UUID, parameters:_Parameters, invalidDialect:pDialectName});\n\t\t\t\tsetDialect('English');\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\t\t/**\n\t\t* User to use for this query\n\t\t*\n\t\t* @method setIDUser\n\t\t*/\n\t\tvar setIDUser = function(pIDUser)\n\t\t{\n\n\t\t\tvar tmpUserID = 0;\n\n\t\t\tif (typeof(pIDUser) === 'number' && (pIDUser % 1) === 0 && pIDUser >= 0)\n\t\t\t{\n\t\t\t\ttmpUserID = pIDUser;\n\t\t\t}\n\t\t\telse if (pIDUser !== false)\n\t\t\t{\n\t\t\t\t_Fable.log.error('User set failed; non-positive or non-numeric argument.', {queryUUID:_UUID, parameters:_Parameters, invalidIDUser:pIDUser});\n\t\t\t}\n\n\n\t\t\t_Parameters.userID = tmpUserID;\n\t\t\t_Parameters.query.IDUser = tmpUserID;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('IDUser set to: '+tmpUserID, {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\t\t/**\n\t\t* Flag to disable auto identity\n\t\t*\n\t\t* @method setDisableAutoIdentity\n\t\t*/\n\t\tvar setDisableAutoIdentity = function(pFlag)\n\t\t{\n\t\t\t_Parameters.query.disableAutoIdentity = pFlag;\n\n\t\t\treturn this; //chainable\n\t\t};\n\n\t\t/**\n\t\t* Flag to disable auto datestamp\n\t\t*\n\t\t* @method setDisableAutoDateStamp\n\t\t*/\n\t\tvar setDisableAutoDateStamp = function(pFlag)\n\t\t{\n\t\t\t_Parameters.query.disableAutoDateStamp = pFlag;\n\n\t\t\treturn this; //chainable\n\t\t};\n\n\t\t/**\n\t\t* Flag to disable auto userstamp\n\t\t*\n\t\t* @method setDisableAutoUserStamp\n\t\t*/\n\t\tvar setDisableAutoUserStamp = function(pFlag)\n\t\t{\n\t\t\t_Parameters.query.disableAutoUserStamp = pFlag;\n\n\t\t\treturn this; //chainable\n\t\t};\n\n\t\t/**\n\t\t* Flag to disable delete tracking\n\t\t*\n\t\t* @method setDisableDeleteTracking\n\t\t*/\n\t\tvar setDisableDeleteTracking = function(pFlag)\n\t\t{\n\t\t\t_Parameters.query.disableDeleteTracking = pFlag;\n\n\t\t\treturn this; //chainable\n\t\t};\n\n\t\t/**\n\t\t* Check that a valid Dialect has been set\n\t\t*\n\t\t* If there has not been a dialect set, it defaults to English.\n\t\t* TODO: Have the json configuration define a \"default\" dialect.\n\t\t*\n\t\t* @method checkDialect\n\t\t*/\n\t\tvar checkDialect = function()\n\t\t{\n\t\t\tif (_Dialect === false)\n\t\t\t{\n\t\t\t\tsetDialect('English');\n\t\t\t}\n\t\t};\n\n\n\t\tvar buildCreateQuery = function()\n\t\t{\n\t\t\tcheckDialect();\n\t\t\t_Parameters.query.body = _Dialect.Create(_Parameters);\n\t\t\treturn this;\n\t\t};\n\n\t\tvar buildReadQuery = function()\n\t\t{\n\t\t\tcheckDialect();\n\t\t\t_Parameters.query.body = _Dialect.Read(_Parameters);\n\t\t\treturn this;\n\t\t};\n\n\t\tvar buildUpdateQuery = function()\n\t\t{\n\t\t\tcheckDialect();\n\t\t\t_Parameters.query.body = _Dialect.Update(_Parameters);\n\t\t\treturn this;\n\t\t};\n\n\t\tvar buildDeleteQuery = function()\n\t\t{\n\t\t\tcheckDialect();\n\t\t\t_Parameters.query.body = _Dialect.Delete(_Parameters);\n\t\t\treturn this;\n\t\t};\n\n\t\tvar buildUndeleteQuery = function()\n\t\t{\n\t\t\tcheckDialect();\n\t\t\t_Parameters.query.body = _Dialect.Undelete(_Parameters);\n\t\t\treturn this;\n\t\t};\n\n\t\tvar buildCountQuery = function()\n\t\t{\n\t\t\tcheckDialect();\n\t\t\t_Parameters.query.body = _Dialect.Count(_Parameters);\n\t\t\treturn this;\n\t\t};\n\n\t\t/**\n\t\t* Container Object for our Factory Pattern\n\t\t*/\n\t\tvar tmpNewFoxHoundObject = (\n\t\t{\n\t\t\tresetParameters: resetParameters,\n\t\t\tmergeParameters: mergeParameters,\n\n\t\t\tsetLogLevel: setLogLevel,\n\n\t\t\tsetScope: setScope,\n\t\t\tsetDistinct: setDistinct,\n\t\t\tsetIDUser: setIDUser,\n\t\t\tsetDataElements: setDataElements,\n\t\t\tsetBegin: setBegin,\n\t\t\tsetCap: setCap,\n\t\t\tsetFilter: setFilter,\n\t\t\taddFilter: addFilter,\n\t\t\tsetSort: setSort,\n\t\t\taddSort: addSort,\n\t\t\tsetJoin: setJoin,\n\t\t\taddJoin: addJoin,\n\n\t\t\taddRecord: addRecord,\n\t\t\tsetDisableAutoIdentity: setDisableAutoIdentity,\n\t\t\tsetDisableAutoDateStamp: setDisableAutoDateStamp,\n\t\t\tsetDisableAutoUserStamp: setDisableAutoUserStamp,\n\t\t\tsetDisableDeleteTracking: setDisableDeleteTracking,\n\n\t\t\tsetDialect: setDialect,\n\n\t\t\tbuildCreateQuery: buildCreateQuery,\n\t\t\tbuildReadQuery: buildReadQuery,\n\t\t\tbuildUpdateQuery: buildUpdateQuery,\n\t\t\tbuildDeleteQuery: buildDeleteQuery,\n\t\t\tbuildUndeleteQuery: buildUndeleteQuery,\n\t\t\tbuildCountQuery: buildCountQuery,\n\n\t\t\tclone: clone,\n\t\t\tnew: createNew\n\t\t});\n\n\t\t/**\n\t\t * Query\n\t\t *\n\t\t * @property query\n\t\t * @type Object\n\t\t */\n\t\tObject.defineProperty(tmpNewFoxHoundObject, 'query',\n\t\t\t{\n\t\t\t\tget: function() { return _Parameters.query; },\n\t\t\t\tset: function(pQuery) { _Parameters.query = pQuery; },\n\t\t\t\tenumerable: true\n\t\t\t});\n\n\t\t/**\n\t\t * Result\n\t\t *\n\t\t * @property result\n\t\t * @type Object\n\t\t */\n\t\tObject.defineProperty(tmpNewFoxHoundObject, 'result',\n\t\t\t{\n\t\t\t\tget: function() { return _Parameters.result; },\n\t\t\t\tset: function(pResult) { _Parameters.result = pResult; },\n\t\t\t\tenumerable: true\n\t\t\t});\n\n\t\t/**\n\t\t * Query Parameters\n\t\t *\n\t\t * @property parameters\n\t\t * @type Object\n\t\t */\n\t\tObject.defineProperty(tmpNewFoxHoundObject, 'parameters',\n\t\t\t{\n\t\t\t\tget: function() { return _Parameters; },\n\t\t\t\tset: function(pParameters) { _Parameters = pParameters; },\n\t\t\t\tenumerable: true\n\t\t\t});\n\n\t\t/**\n\t\t * Dialect\n\t\t *\n\t\t * @property dialect\n\t\t * @type Object\n\t\t */\n\t\tObject.defineProperty(tmpNewFoxHoundObject, 'dialect',\n\t\t\t{\n\t\t\t\tget: function() { return _Dialect; },\n\t\t\t\tenumerable: true\n\t\t\t});\n\n\t\t/**\n\t\t * Universally Unique Identifier\n\t\t *\n\t\t * @property uuid\n\t\t * @type String\n\t\t */\n\t\tObject.defineProperty(tmpNewFoxHoundObject, 'uuid',\n\t\t\t{\n\t\t\t\tget: function() { return _UUID; },\n\t\t\t\tenumerable: true\n\t\t\t});\n\n\t\t/**\n\t\t * Log Level\n\t\t *\n\t\t * @property logLevel\n\t\t * @type Integer\n\t\t */\n\t\tObject.defineProperty(tmpNewFoxHoundObject, 'logLevel',\n\t\t\t{\n\t\t\t\tget: function() { return _LogLevel; },\n\t\t\t\tenumerable: true\n\t\t\t});\n\n\t\treturn tmpNewFoxHoundObject;\n\t}\n\n\treturn createNew();\n};\n\nmodule.exports = FoxHound();\n\n},{\"./Foxhound-Dialects.js\":2,\"./Parameters.js\":4}],4:[function(require,module,exports){\n/**\n* Query Parameters Object\n*\n* @class FoxHoundQueryParameters\n* @constructor\n*/\nvar FoxHoundQueryParameters = (\n{\n\t\tscope: false, // STR: The scope of the data\n\t\t\t\t\t\t\t\t// TSQL: the \"Table\" or \"View\"\n\t\t\t\t\t\t\t\t// MongoDB: the \"Collection\"\n\n\t\tdataElements: false, // ARR of STR: The data elements to return\n\t\t\t\t\t\t\t\t// TSQL: the \"Columns\"\n\t\t\t\t\t\t\t\t// MongoDB: the \"Fields\"\n\n\t\tbegin: false, // INT: Record index to start at\n\t\t\t\t\t\t\t\t// TSQL: n in LIMIT 1,n\n\t\t\t\t\t\t\t\t// MongoDB: n in Skip(n)\n\n\t\tcap: false, // INT: Maximum number of records to return\n\t\t\t\t\t\t\t\t// TSQL: n in LIMIT n\n\t\t\t\t\t\t\t\t// MongoDB: n in limit(n)\n\n\t\t// Serialization example for a query:\n\t\t// Take the filter and return an array of filter instructions\n\t\t// Basic instruction anatomy:\n\t\t// INSTRUCTION~FIELD~OPERATOR~VALUE\n\t\t// FOP - Filter Open Paren\n\t\t// FOP~~(~\n\t\t// FCP - Filter Close Paren\n\t\t// FCP~~)~\n\t\t// FBV - Filter By Value\n\t\t// FBV~Category~EQ~Books\n\t\t// Possible comparisons:\n\t\t// * EQ - Equals To (=)\n\t\t// * NE - Not Equals To (!=)\n\t\t// * GT - Greater Than (>)\n\t\t// * GE - Greater Than or Equals To (>=)\n\t\t// * LT - Less Than (<)\n\t\t// * LE - Less Than or Equals To (<=)\n\t\t// * LK - Like (Like)\n\t\t// FBL - Filter By List (value list, separated by commas)\n\t\t// FBL~Category~EQ~Books,Movies\n\t\t// FSF - Filter Sort Field\n\t\t// FSF~Category~ASC~0\n\t\t// FSF~Category~DESC~0\n\t\t// FCC - Filter Constraint Cap (the limit of what is returned)\n\t\t// FCC~~10~\n\t\t// FCB - Filter Constraint Begin (the zero-based start index of what is returned)\n\t\t// FCB~~10~\n\t\t//\n\t\t// This means: FBV~Category~EQ~Books~FBV~PublishedYear~GT~2000~FSF~PublishedYear~DESC~0\n\t\t// Filters down to ALL BOOKS PUBLISHED AFTER 2000 IN DESCENDING ORDER\n\t\tfilter: false, // ARR of OBJ: Data filter expression list {Column:'Name', Operator:'EQ', Value:'John', Connector:'And', Parameter:'Name'}\n\t\t\t\t\t\t\t\t// TSQL: the WHERE clause\n\t\t\t\t\t\t\t\t// MongoDB: a find() expression\n\n\t\tsort: false, // ARR of OBJ: The sort order {Column:'Birthday', Direction:'Ascending'}\n\t\t\t\t\t\t\t\t// TSQL: ORDER BY\n\t\t\t\t\t\t\t\t// MongoDB: sort()\n\n\t\tjoin: false, // ARR of OBJ: The join tables {Type:'INNER JOIN', Table:'test', From: 'Test.ID', To: 'Scope.IDItem' }\n\t\t\t\t\t\t\t\t// TSQL: JOIN\n\n\t\t// Force a specific query to run regardless of above ... this is used to override the query generator.\n\t\tqueryOverride: false,\n\n\t\t// Where the generated query goes\n\t\tquery: false,\n\t\t/*\n\t\t\t{\n\t\t\t\tbody: false,\n\t\t\t\tschema: false, // The schema to intersect with our records\n\t\t\t\tIDUser: 0, // The User ID to stamp into records\n\t\t\t\tUUID: A_UUID, // Some globally unique record id, different per cloned query.\n\t\t\t\trecords: false, // The records to be created or changed\n\t\t\t\tparameters: {}\n\t\t\t}\n\t\t*/\n\t\t\n\t\t// Who is making the query\n\t\tuserID: 0,\n\n\t\t// Where the query results are stuck\n\t\tresult: false\n\t\t/*\n\t\t\t{\n\t\t\t\texecuted: false, // True once we've run a query.\n\t\t\t\tvalue: false, // The return value of the last query run\n\t\t\t\terror: false // The error message of the last run query\n\t\t\t}\n\t\t*/\n});\n\nmodule.exports = FoxHoundQueryParameters;\n},{}],5:[function(require,module,exports){\n/**\n* FoxHound ALASQL Dialect\n*\n* @license MIT\n*\n* For an ALASQL query override:\n// An underscore template with the following values:\n// <%= DataElements %> = Field1, Field2, Field3, Field4\n// <%= Begin %> = 0\n// <%= Cap %> = 10\n// <%= Filter %> = WHERE StartDate > :MyStartDate\n// <%= Sort %> = ORDER BY Field1\n// The values are empty strings if they aren't set.\n*\n* @author Steven Velozo <steven@velozo.com>\n* @class FoxHoundDialectALASQL\n*/\n\nvar FoxHoundDialectALASQL = function(pFable)\n{\n\t//Request time from SQL server with microseconds resolution\n\tconst SQL_NOW = \"NOW(3)\";\n\n\t_Fable = pFable;\n\n\t/**\n\t* Generate a table name from the scope.\n\t*\n\t* Because ALASQL is all in-memory, and can be run in two modes (anonymous\n\t* working on arrays or table-based) we are going to make this a programmable\n\t* value. Then we can share the code across both providers.\n\t*\n\t* @method: generateTableName\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateTableName = function(pParameters)\n\t{\n\t\treturn ' '+pParameters.scope;\n\t};\n\n\t/**\n\t* Escape columns, because ALASQL has more reserved KWs than most SQL dialects\n\t*/\n\tvar escapeColumn = (pColumn, pParameters) =>\n\t{\n\t\tif (pColumn.indexOf('.') < 0)\n\t\t{\n\t\t\treturn '`'+pColumn+'`';\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// This could suck if the scope is not the same\n\t\t\tvar tmpTableName = pParameters.scope;\n\t\t\tif (pColumn.indexOf(tmpTableName+'.') > -1)\n\t\t\t{\n\t\t\t\treturn '`'+pColumn.replace(tmpTableName+'.', '')+'`';\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// This doesn't work well but we'll try it.\n\t\t\t\treturn '`'+pColumn+'`';\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t* Generate a field list from the array of dataElements\n\t*\n\t* Each entry in the dataElements is a simple string\n\t*\n\t* @method: generateFieldList\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @param {Boolean} pIsForCountClause (optional) If true, generate fields for use within a count clause.\n\t* @return: {String} Returns the field list clause, or empty string if explicit fields are requested but cannot be fulfilled\n\t* due to missing schema.\n\t*/\n\tvar generateFieldList = function(pParameters, pIsForCountClause)\n\t{\n\t\tvar tmpDataElements = pParameters.dataElements;\n\t\tif (!Array.isArray(tmpDataElements) || tmpDataElements.length < 1)\n\t\t{\n\t\t\tif (!pIsForCountClause)\n\t\t\t{\n\t\t\t\treturn ' *';\n\t\t\t}\n\t\t\t// we need to list all of the table fields explicitly; get them from the schema\n\t\t\tconst tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\t\t\tif (tmpSchema.length < 1)\n\t\t\t{\n\t\t\t\t// this means we have no schema; returning an empty string here signals the calling code to handle this case\n\t\t\t\treturn '';\n\t\t\t}\n\t\t\tconst idColumn = tmpSchema.find((entry) => entry.Type === 'AutoIdentity');\n\t\t\tif (!idColumn)\n\t\t\t{\n\t\t\t\t// this means there is no autoincrementing unique ID column; treat as above\n\t\t\t\treturn '';\n\t\t\t}\n\t\t\treturn ` ${idColumn.Column}`;\n\t\t}\n\n\t\tvar tmpFieldList = ' ';\n\t\tfor (var i = 0; i < tmpDataElements.length; i++)\n\t\t{\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\ttmpFieldList += ', ';\n\t\t\t}\n\t\t\ttmpFieldList += escapeColumn(tmpDataElements[i], pParameters);\n\t\t}\n\t\treturn tmpFieldList;\n\t};\n\n\t/**\n\t* Generate a query from the array of where clauses\n\t*\n\t* Each clause is an object like:\n\t\t{\n\t\t\tColumn:'Name',\n\t\t\tOperator:'EQ',\n\t\t\tValue:'John',\n\t\t\tConnector:'And',\n\t\t\tParameter:'Name'\n\t\t}\n\t*\n\t* @method: generateWhere\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the WHERE clause prefixed with WHERE, or an empty string if unnecessary\n\t*/\n\tvar generateWhere = function(pParameters)\n\t{\n\t\tvar tmpFilter = Array.isArray(pParameters.filter) ? pParameters.filter : [];\n\t\tvar tmpTableName = generateTableName(pParameters).trim();\n\n\t\tif (!pParameters.query.disableDeleteTracking)\n\t\t{\n\t\t\t// Check if there is a Deleted column on the Schema. If so, we add this to the filters automatically (if not already present)\n\t\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\tvar tmpSchemaEntry = tmpSchema[i];\n\n\t\t\t\tif (tmpSchemaEntry.Type === 'Deleted')\n\t\t\t\t{\n\t\t\t\t\tvar tmpHasDeletedParameter = false;\n\n\t\t\t\t\t//first, check to see if filters are already looking for Deleted column\n\t\t\t\t\tif (tmpFilter.length > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (var x = 0; x < tmpFilter.length; x++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (tmpFilter[x].Column === tmpSchemaEntry.Column)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttmpHasDeletedParameter = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (!tmpHasDeletedParameter)\n\t\t\t\t\t{\n\t\t\t\t\t\t//if not, we need to add it\n\t\t\t\t\t\ttmpFilter.push(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tColumn: tmpTableName + '.' + tmpSchemaEntry.Column,\n\t\t\t\t\t\t\tOperator: '=',\n\t\t\t\t\t\t\tValue: 0,\n\t\t\t\t\t\t\tConnector: 'AND',\n\t\t\t\t\t\t\tParameter: 'Deleted'\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (tmpFilter.length < 1)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpWhere = ' WHERE';\n\n\t\t// This is used to disable the connectors for subsequent queries.\n\t\t// Only the open parenthesis operator uses this, currently.\n\t\tvar tmpLastOperatorNoConnector = false;\n\n\t\tfor (var i = 0; i < tmpFilter.length; i++)\n\t\t{\n\t\t\tif ((tmpFilter[i].Connector != 'NONE') && (tmpFilter[i].Operator != ')') && (tmpWhere != ' WHERE') && (tmpLastOperatorNoConnector == false))\n\t\t\t{\n\t\t\t\ttmpWhere += ' '+tmpFilter[i].Connector;\n\t\t\t}\n\n\t\t\ttmpLastOperatorNoConnector = false;\n\n\t\t\tvar tmpColumnParameter;\n\n\t\t\tif (tmpFilter[i].Operator === '(')\n\t\t\t{\n\t\t\t\t// Open a logical grouping\n\t\t\t\ttmpWhere += ' (';\n\t\t\t\ttmpLastOperatorNoConnector = true;\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === ')')\n\t\t\t{\n\t\t\t\t// Close a logical grouping\n\t\t\t\ttmpWhere += ' )';\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IN')\n\t\t\t{\n\t\t\t\ttmpColumnParameter = tmpFilter[i].Parameter+'_w'+i;\n\t\t\t\t// Add the column name, operator and parameter name to the list of where value parenthetical\n\t\t\t\ttmpWhere += ' '+escapeColumn(tmpFilter[i].Column, pParameters)+' '+tmpFilter[i].Operator+' ( :'+tmpColumnParameter+' )';\n\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = tmpFilter[i].Value;\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IS NOT NULL')\n\t\t\t{\n\t\t\t\t// IS NOT NULL is a special operator which doesn't require a value, or parameter\n\t\t\t\ttmpWhere += ' '+escapeColumn(tmpFilter[i].Column, pParameters)+' '+tmpFilter[i].Operator;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpColumnParameter = tmpFilter[i].Parameter+'_w'+i;\n\t\t\t\t// Add the column name, operator and parameter name to the list of where value parenthetical\n\t\t\t\ttmpWhere += ' '+escapeColumn(tmpFilter[i].Column, pParameters)+' '+tmpFilter[i].Operator+' :'+tmpColumnParameter;\n\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = tmpFilter[i].Value;\n\t\t\t}\n\t\t}\n\n\t\treturn tmpWhere;\n\t};\n\n\t/**\n\t* Generate an ORDER BY clause from the sort array\n\t*\n\t* Each entry in the sort is an object like:\n\t* {Column:'Color',Direction:'Descending'}\n\t*\n\t* @method: generateOrderBy\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the field list clause\n\t*/\n\tvar generateOrderBy = function(pParameters)\n\t{\n\t\tvar tmpOrderBy = pParameters.sort;\n\t\tif (!Array.isArray(tmpOrderBy) || tmpOrderBy.length < 1)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpOrderClause = ' ORDER BY';\n\t\tfor (var i = 0; i < tmpOrderBy.length; i++)\n\t\t{\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\ttmpOrderClause += ',';\n\t\t\t}\n\t\t\ttmpOrderClause += ' '+escapeColumn(tmpOrderBy[i].Column, pParameters);\n\n\t\t\tif (tmpOrderBy[i].Direction == 'Descending')\n\t\t\t{\n\t\t\t\ttmpOrderClause += ' DESC';\n\t\t\t}\n\t\t}\n\t\treturn tmpOrderClause;\n\t};\n\n\t/**\n\t* Generate the limit clause\n\t*\n\t* @method: generateLimit\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateLimit = function(pParameters)\n\t{\n\t\tif (!pParameters.cap)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpLimit = ' LIMIT';\n\t\t// Cap is required for a limit clause.\n\t\ttmpLimit += ' ' + pParameters.cap;\n\n\t\t// If there is a begin record, we'll pass that in as well.\n\t\tif (pParameters.begin !== false)\n\t\t{\n\t\t\ttmpLimit += ' FETCH ' + pParameters.begin;\n\t\t}\n\n\t\treturn tmpLimit;\n\t};\n\n\t/**\n\t* Generate the update SET clause\n\t*\n\t* @method: generateUpdateSetters\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateUpdateSetters = function(pParameters)\n\t{\n\t\tvar tmpRecords = pParameters.query.records;\n\t\t// We need to tell the query not to generate improperly if there are no values to set.\n\t\tif (!Array.isArray(tmpRecords) || tmpRecords.length < 1)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpUpdate = '';\n\t\t// If there is more than one record in records, we are going to ignore them for now.\n\t\tvar tmpCurrentColumn = 0;\n\t\tfor(var tmpColumn in tmpRecords[0])\n\t\t{\n\t\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\t\tvar tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\tif (tmpColumn == tmpSchema[i].Column)\n\t\t\t\t{\n\t\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\t\ttmpSchemaEntry = tmpSchema[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (pParameters.query.disableAutoDateStamp &&\n\t\t\t\ttmpSchemaEntry.Type === 'UpdateDate')\n\t\t\t{\n\t\t\t\t// This is ignored if flag is set\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (pParameters.query.disableAutoUserStamp &&\n\t\t\t\ttmpSchemaEntry.Type === 'UpdateIDUser')\n\t\t\t{\n\t\t\t\t// This is ignored if flag is set\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'AutoIdentity':\n\t\t\t\tcase 'CreateDate':\n\t\t\t\tcase 'CreateIDUser':\n\t\t\t\tcase 'DeleteDate':\n\t\t\t\tcase 'DeleteIDUser':\n\t\t\t\t\t// These are all ignored on update\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpUpdate += ',';\n\t\t\t}\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\ttmpUpdate += ' '+escapeColumn(tmpColumn, pParameters)+' = NOW()';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateIDUser':\n\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\tvar tmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdate += ' '+escapeColumn(tmpColumn, pParameters)+' = :'+tmpColumnParameter;\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tvar tmpColumnDefaultParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdate += ' '+escapeColumn(tmpColumn, pParameters)+' = :'+tmpColumnDefaultParameter;\n\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnDefaultParameter] = tmpRecords[0][tmpColumn];\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// We use a number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (tmpUpdate === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpUpdate;\n\t};\n\n\t/**\n\t* Generate the update-delete SET clause\n\t*\n\t* @method: generateUpdateDeleteSetters\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateUpdateDeleteSetters = function(pParameters)\n\t{\n\t\tif (pParameters.query.disableDeleteTracking)\n\t\t{\n\t\t\t//Don't generate an UPDATE query if Delete tracking is disabled\n\t\t\treturn false;\n\t\t}\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpCurrentColumn = 0;\n\t\tvar tmpHasDeletedField = false;\n\t\tvar tmpUpdate = '';\n\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\tvar tmpSchemaEntry = {Type:'Default'};\n\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t{\n\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\ttmpSchemaEntry = tmpSchema[i];\n\n\t\t\tvar tmpUpdateSql = null;\n\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'Deleted':\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = 1';\n\t\t\t\t\ttmpHasDeletedField = true; //this field is required in order for query to be built\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'DeleteDate':\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = NOW()';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\t\t// Delete operation is an Update, so we should stamp the update time\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = NOW()';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'DeleteIDUser':\n\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\tvar tmpColumnParameter = tmpSchemaEntry.Column+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = :'+tmpColumnParameter;\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t//DON'T allow update of other fields in this query\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpUpdate += ',';\n\t\t\t}\n\n\t\t\ttmpUpdate += tmpUpdateSql;\n\n\t\t\t// We use a number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (!tmpHasDeletedField ||\n\t\t\ttmpUpdate === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpUpdate;\n\t};\n\n\t/**\n\t* Generate the update-delete SET clause\n\t*\n\t* @method: generateUpdateDeleteSetters\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateUpdateUndeleteSetters = function(pParameters)\n\t{\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpCurrentColumn = 0;\n\t\tvar tmpHasDeletedField = false;\n\t\tvar tmpUpdate = '';\n\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\tvar tmpSchemaEntry = {Type:'Default'};\n\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t{\n\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\ttmpSchemaEntry = tmpSchema[i];\n\n\t\t\tvar tmpUpdateSql = null;\n\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'Deleted':\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = 0';\n\t\t\t\t\ttmpHasDeletedField = true; //this field is required in order for query to be built\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\t\t// Delete operation is an Update, so we should stamp the update time\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = NOW()';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateIDUser':\n\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\tvar tmpColumnParameter = tmpSchemaEntry.Column+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = :'+tmpColumnParameter;\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t//DON'T allow update of other fields in this query\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpUpdate += ',';\n\t\t\t}\n\n\t\t\ttmpUpdate += tmpUpdateSql;\n\n\t\t\t// We use a number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (!tmpHasDeletedField ||\n\t\t\ttmpUpdate === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpUpdate;\n\t};\n\n\t/**\n\t* Generate the create SET clause\n\t*\n\t* @method: generateCreateSetList\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateCreateSetValues = function(pParameters)\n\t{\n\t\tvar tmpRecords = pParameters.query.records;\n\t\t// We need to tell the query not to generate improperly if there are no values to set.\n\t\tif (!Array.isArray(tmpRecords) || tmpRecords.length < 1)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\n\t\tvar tmpCreateSet = '';\n\t\t// If there is more than one record in records, we are going to ignore them for now.\n\t\tvar tmpCurrentColumn = 0;\n\t\tfor(var tmpColumn in tmpRecords[0])\n\t\t{\n\t\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\t\tvar tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\tif (tmpColumn == tmpSchema[i].Column)\n\t\t\t\t{\n\t\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\t\ttmpSchemaEntry = tmpSchema[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!pParameters.query.disableDeleteTracking)\n\t\t\t{\n\t\t\t\tif (tmpSchemaEntry.Type === 'DeleteDate' ||\n\t\t\t\t\ttmpSchemaEntry.Type === 'DeleteIDUser')\n\t\t\t\t{\n\t\t\t\t\t// These are all ignored on insert (if delete tracking is enabled as normal)\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpCreateSet += ',';\n\t\t\t}\n\n\t\t\t//define a re-usable method for setting up field definitions in a default pattern\n\t\t\tvar buildDefaultDefinition = function()\n\t\t\t{\n\t\t\t\tvar tmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\ttmpCreateSet += ' :'+tmpColumnParameter;\n\t\t\t\t// Set the query parameter\n\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = tmpRecords[0][tmpColumn];\n\t\t\t};\n\n\t\t\tvar tmpColumnParameter;\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'AutoIdentity':\n\t\t\t\t\tif (pParameters.query.disableAutoIdentity)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\t\ttmpCreateSet += ' NULL';\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'AutoGUID':\n\t\t\t\t\tif (pParameters.query.disableAutoIdentity)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse if (tmpRecords[0][tmpColumn] &&\n\t\t\t\t\t\t\ttmpRecords[0][tmpColumn].length >= 5 &&\n\t\t\t\t\t\t\ttmpRecords[0][tmpColumn] !== '0x0000000000000000') //stricture default\n\t\t\t\t\t{\n\t\t\t\t\t\t// Allow consumer to override AutoGUID\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\t\ttmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\t\ttmpCreateSet += ' :'+tmpColumnParameter;\n\t\t\t\t\t\t// Set the query parameter\n\t\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.UUID;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\tcase 'CreateDate':\n\t\t\t\tcase 'DeleteDate':\n\t\t\t\t\tif (pParameters.query.disableAutoDateStamp)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\t\ttmpCreateSet += ' NOW()';\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateIDUser':\n\t\t\t\tcase 'CreateIDUser':\n\t\t\t\tcase 'DeleteIDUser':\n\t\t\t\t\tif (pParameters.query.disableAutoUserStamp)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\t\ttmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\t\ttmpCreateSet += ' :'+tmpColumnParameter;\n\t\t\t\t\t\t// Set the query parameter\n\t\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// We use an appended number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (tmpCreateSet === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpCreateSet;\n\t};\n\n\t/**\n\t* Generate the create SET clause\n\t*\n\t* @method: generateCreateSetList\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateCreateSetList = function(pParameters)\n\t{\n\t\t// The records were already validated by generateCreateSetValues\n\t\tvar tmpRecords = pParameters.query.records;\n\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpCreateSet = '';\n\t\t// If there is more than one record in records, we are going to ignore them for now.\n\t\tfor(var tmpColumn in tmpRecords[0])\n\t\t{\n\t\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\t\tvar tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\tif (tmpColumn == tmpSchema[i].Column)\n\t\t\t\t{\n\t\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\t\ttmpSchemaEntry = tmpSchema[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!pParameters.query.disableDeleteTracking)\n\t\t\t{\n\t\t\t\tif (tmpSchemaEntry.Type === 'DeleteDate' ||\n\t\t\t\t\ttmpSchemaEntry.Type === 'DeleteIDUser')\n\t\t\t\t{\n\t\t\t\t\t// These are all ignored on insert (if delete tracking is enabled as normal)\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tdefault:\n\t\t\t\t\tif (tmpCreateSet != '')\n\t\t\t\t\t{\n\t\t\t\t\t\ttmpCreateSet += ',';\n\t\t\t\t\t}\n\t\t\t\t\ttmpCreateSet += ' '+escapeColumn(tmpColumn, pParameters);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn tmpCreateSet;\n\t};\n\n\n\tvar Create = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpCreateSetList = generateCreateSetList(pParameters);\n\t\tvar tmpCreateSetValues = generateCreateSetValues(pParameters);\n\n\t\tif (!tmpCreateSetValues)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn 'INSERT INTO'+tmpTableName+' ('+tmpCreateSetList+') VALUES ('+tmpCreateSetValues+');';\n\t};\n\n\n\t/**\n\t* Read one or many records\n\t*\n\t* Some examples:\n\t* SELECT * FROM WIDGETS;\n\t* SELECT * FROM WIDGETS LIMIT 0, 20;\n\t* SELECT * FROM WIDGETS LIMIT 5, 20;\n\t* SELECT ID, Name, Cost FROM WIDGETS LIMIT 5, 20;\n\t* SELECT ID, Name, Cost FROM WIDGETS LIMIT 5, 20 WHERE LastName = 'Smith';\n\t*\n\t* @method Read\n\t* @param {Object} pParameters SQL Query parameters\n\t* @return {String} Returns the current Query for chaining.\n\t*/\n\tvar Read = function(pParameters)\n\t{\n\t\tvar tmpFieldList = generateFieldList(pParameters);\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpOrderBy = generateOrderBy(pParameters);\n\t\tvar tmpLimit = generateLimit(pParameters);\n\t\tconst tmpOptDistinct = pParameters.distinct ? ' DISTINCT' : '';\n\n\t\tif (pParameters.queryOverride)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tvar tmpQueryTemplate = _Fable.Utility.template(pParameters.queryOverride);\n\t\t\t\treturn tmpQueryTemplate({FieldList:tmpFieldList, TableName:tmpTableName, Where:tmpWhere, OrderBy:tmpOrderBy, Limit:tmpLimit, Distinct: tmpOptDistinct, _Params: pParameters});\n\t\t\t}\n\t\t\tcatch (pError)\n\t\t\t{\n\t\t\t\t// This pokemon is here to give us a convenient way of not throwing up totally if the query fails.\n\t\t\t\tconsole.log('Error with custom Read Query ['+pParameters.queryOverride+']: '+pError);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn `SELECT${tmpOptDistinct}${tmpFieldList} FROM${tmpTableName}${tmpWhere}${tmpOrderBy}${tmpLimit};`;\n\t};\n\n\tvar Update = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpUpdateSetters = generateUpdateSetters(pParameters);\n\n\t\tif (!tmpUpdateSetters)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn 'UPDATE'+tmpTableName+' SET'+tmpUpdateSetters+tmpWhere+';';\n\t};\n\n\tvar Delete = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpUpdateDeleteSetters = generateUpdateDeleteSetters(pParameters);\n\n\t\tif (tmpUpdateDeleteSetters)\n\t\t{\n\t\t\t//If it has a deleted bit, update it instead of actually deleting the record\n\t\t\treturn 'UPDATE'+tmpTableName+' SET'+tmpUpdateDeleteSetters+tmpWhere+';';\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn 'DELETE FROM'+tmpTableName+tmpWhere+';';\n\t\t}\n\t};\n\n\tvar Undelete = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tlet tmpDeleteTrackingState = pParameters.query.disableDeleteTracking;\n\t\tpParameters.query.disableDeleteTracking = true;\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpUpdateUndeleteSetters = generateUpdateUndeleteSetters(pParameters);\n\t\tpParameters.query.disableDeleteTracking = tmpDeleteTrackingState;\n\n\t\tif (tmpUpdateUndeleteSetters)\n\t\t{\n\t\t\t//If it has a deleted bit, update it instead of actually deleting the record\n\t\t\treturn 'UPDATE'+tmpTableName+' SET'+tmpUpdateUndeleteSetters+tmpWhere+';';\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn 'SELECT NULL;';\n\t\t}\n\t};\n\n\tvar Count = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tconst tmpFieldList = pParameters.distinct ? generateFieldList(pParameters, true) : '*';\n\n\t\t// here, we ignore the distinct keyword if no fields have been specified and\n\t\tif (pParameters.distinct && tmpFieldList.length < 1)\n\t\t{\n\t\t\tconsole.warn('Distinct requested but no field list or schema are available, so not honoring distinct for count query.');\n\t\t}\n\t\tconst tmpOptDistinct = pParameters.distinct && tmpFieldList.length > 0 ? 'DISTINCT' : '';\n\t\tif (pParameters.queryOverride)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tvar tmpQueryTemplate = _Fable.Utility.template(pParameters.queryOverride);\n\t\t\t\treturn tmpQueryTemplate({FieldList:[], TableName:tmpTableName, Where:tmpWhere, OrderBy:'', Limit:'', Distinct: tmpOptDistinct, _Params: pParameters});\n\t\t\t}\n\t\t\tcatch (pError)\n\t\t\t{\n\t\t\t\t// This pokemon is here to give us a convenient way of not throwing up totally if the query fails.\n\t\t\t\tconsole.log('Error with custom Count Query ['+pParameters.queryOverride+']: '+pError);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn `SELECT COUNT(${tmpOptDistinct}${tmpFieldList || '*'}) AS RowCount FROM${tmpTableName}${tmpWhere};`;\n\t};\n\n\tvar tmpDialect = ({\n\t\tCreate: Create,\n\t\tRead: Read,\n\t\tUpdate: Update,\n\t\tDelete: Delete,\n\t\tUndelete: Undelete,\n\t\tCount: Count\n\t});\n\n\t/**\n\t* Dialect Name\n\t*\n\t* @property name\n\t* @type string\n\t*/\n\tObject.defineProperty(tmpDialect, 'name',\n\t\t{\n\t\t\tget: function() { return 'ALASQL'; },\n\t\t\tenumerable: true\n\t\t});\n\n\treturn tmpDialect;\n};\n\nmodule.exports = FoxHoundDialectALASQL;\n\n},{}],6:[function(require,module,exports){\n/**\n* FoxHound English Dialect\n*\n* Because if I can't ask for it in my native tongue, how am I going to ask a\n* complicated server for it?\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n* @class FoxHoundDialectEnglish\n*/\nvar FoxHoundDialectEnglish = function()\n{\n\tvar Create = function(pParameters)\n\t{\n\t\tvar tmpScope = pParameters.scope;\n\n\t\treturn 'Here is a '+tmpScope+'.';\n\t};\n\n\t/**\n\t* Read one or many records\n\t*\n\t* Some examples:\n\t* Please give me all your Widget records. Thanks.\n\t* Please give me 20 Widget records. Thanks.\n\t* Please give me 20 Widget records starting with record 5. Thanks.\n\t* Please give me the ID, Name and Cost of 20 Widget records starting with record 5. Thanks.\n\t* Please give me the ID and Name of 20 Widget records starting with record 5, when LastName equals \"Smith\". Thanks.\n\t*\n\t* @method Read\n\t* @param {Number} pLogLevel The log level for our object\n\t* @return {String} Returns the current Query for chaining.\n\t*/\n\tvar Read = function(pParameters)\n\t{\n\t\tvar tmpScope = pParameters.scope;\n\t\tconst tmpDistinct = pParameters.distinct ? 'unique ' : '';\n\n\t\treturn `Please give me all your ${tmpDistinct}${tmpScope} records. Thanks.`;\n\t};\n\n\tvar Update = function(pParameters)\n\t{\n\t\tvar tmpScope = pParameters.scope;\n\n\t\treturn 'I am changing your '+tmpScope+'.';\n\t};\n\n\tvar Delete = function(pParameters)\n\t{\n\t\tvar tmpScope = pParameters.scope;\n\n\t\treturn 'I am deleting your '+tmpScope+'.';\n\t};\n\n\tvar Undelete = function(pParameters)\n\t{\n\t\tvar tmpScope = pParameters.scope;\n\n\t\treturn 'I am undeleting your '+tmpScope+'.';\n\t};\n\n\tvar Count = function(pParameters)\n\t{\n\t\tvar tmpScope = pParameters.scope;\n\t\tconst tmpDistinct = pParameters.distinct ? 'unique ' : '';\n\n\t\treturn `Count your ${tmpDistinct}${tmpScope}.`;\n\t};\n\n\tvar tmpDialect = ({\n\t\tCreate: Create,\n\t\tRead: Read,\n\t\tUpdate: Update,\n\t\tDelete: Delete,\n\t\tUndelete: Undelete,\n\t\tCount: Count\n\t});\n\n\t/**\n\t * Dialect Name\n\t *\n\t * @property name\n\t * @type string\n\t */\n\tObject.defineProperty(tmpDialect, 'name',\n\t\t{\n\t\t\tget: function() { return 'English'; },\n\t\t\tenumerable: true\n\t\t});\n\n\treturn tmpDialect;\n};\n\nmodule.exports = FoxHoundDialectEnglish;\n\n},{}],7:[function(require,module,exports){\n/**\n* FoxHound Meadow Endpoints Dialect\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n* @class FoxHoundDialectMeadowEndpoints\n*/\n\nvar FoxHoundDialectMeadowEndpoints = function()\n{\n\t/**\n\t * Generate a table name from the scope\n\t *\n\t * @method: generateTableName\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Returns the table name clause\n\t */\n\tvar generateTableName = function(pParameters)\n\t{\n\t\treturn pParameters.scope;\n\t};\n\n\t/**\n\t * Generate the Identity column from the schema or scope\n\t * \n\t * @method: generateIdentityColumnName\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Returns the table name clause\n\t */\n\tvar generateIdentityColumnName = function(pParameters)\n\t{\n\t\t// TODO: See about using the Schema or the Schemata for this\n\t\treturn `ID${pParameters.scope}`;\n\t};\n\n\t/**\n\t * Generate a field list from the array of dataElements\n\t *\n\t * Each entry in the dataElements is a simple string\n\t *\n\t * @method: generateFieldList\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Returns the field list clause\n\t */\n\tvar generateFieldList = function(pParameters)\n\t{\n\t\tvar tmpDataElements = pParameters.dataElements;\n\t\tif (!Array.isArray(tmpDataElements) || tmpDataElements.length < 1)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpFieldList = '';\n\t\tfor (var i = 0; i < tmpDataElements.length; i++)\n\t\t{\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\ttmpFieldList += ',';\n\t\t\t}\n\n tmpFieldList += tmpDataElements[i];\n\t\t}\n\t\treturn tmpFieldList;\n\t};\n\n\t/**\n\t * Generate a query from the array of where clauses\n\t *\n\t * Each clause is an object like:\n\t\t{\n\t\t\tColumn:'Name', \n\t\t\tOperator:'EQ', \n\t\t\tValue:'John', \n\t\t\tConnector:'And', \n\t\t\tParameter:'Name'\n\t\t}\n\t *\n\t * @method: generateWhere\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Returns the WHERE clause prefixed with WHERE, or an empty string if unnecessary\n\t */\n\tvar generateWhere = function(pParameters)\n\t{\n\t\tvar tmpFilter = Array.isArray(pParameters.filter) ? pParameters.filter : [];\n\t\tvar tmpTableName = generateTableName(pParameters);\n \n var tmpURL = '';\n\n let tmpfAddFilter = (pFilterCommand, pFilterParameters) =>\n {\n if (tmpURL.length > 0)\n {\n tmpURL += '~';\n }\n \n tmpURL += `${pFilterCommand}~${pFilterParameters[0]}~${pFilterParameters[1]}~${pFilterParameters[2]}`;\n };\n\n let tmpfTranslateOperator = (pOperator) =>\n {\n tmpNewOperator = 'EQ';\n switch(pOperator.toUpperCase())\n {\n case '!=':\n tmpNewOperator = 'NE';\n break;\n case '>':\n tmpNewOperator = 'GT';\n break;\n case '>=':\n tmpNewOperator = 'GE';\n break;\n case '<=':\n tmpNewOperator = 'LE';\n break;\n case '<':\n tmpNewOperator = 'LT';\n break;\n case 'LIKE':\n tmpNewOperator = 'LK';\n break;\n case 'IN':\n tmpNewOperator = 'INN';\n break;\n case 'NOT IN':\n tmpNewOperator = 'NI';\n break;\n }\n return tmpNewOperator;\n }\n\n // Translating Delete Tracking bit on query to a query with automagic\n // This will eventually deprecate this as part of the necessary query\n if (pParameters.query.disableDeleteTracking)\n {\n tmpfAddFilter('FBV',['Deleted','GE','0'])\n }\n\n\t\tfor (var i = 0; i < tmpFilter.length; i++)\n\t\t{\n\t\t\tif (tmpFilter[i].Operator === '(')\n\t\t\t{\n tmpfAddFilter('FOP',['0','(','0']);\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === ')')\n\t\t\t{\n\t\t\t\t// Close a logical grouping\n tmpfAddFilter('FCP',['0',')','0']);\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IN' || tmpFilter[i].Operator === \"NOT IN\")\n\t\t\t{\n let tmpFilterCommand = 'FBV';\n if (tmpFilter[i].Connector == 'OR')\n {\n tmpFilterCommand = 'FBVOR';\n }\n\t\t\t\t// Add the column name, operator and parameter name to the list of where value parenthetical\n tmpfAddFilter(tmpFilterCommand, [tmpFilter[i].Column, tmpfTranslateOperator(tmpFilter[i].Operator), tmpFilter[i].Value.map(encodeURIComponent).join(',')])\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IS NULL')\n\t\t\t{\n\t\t\t\t// IS NULL is a special operator which doesn't require a value, or parameter\n tmpfAddFilter('FBV', [tmpFilter[i].Column, 'IN', '0']);\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IS NOT NULL')\n\t\t\t{\n\t\t\t\t// IS NOT NULL is a special operator which doesn't require a value, or parameter\n tmpfAddFilter('FBV', [tmpFilter[i].Column, 'NN', '0']);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n let tmpFilterCommand = 'FBV';\n if (tmpFilter[i].Connector == 'OR')\n {\n tmpFilterCommand = 'FBVOR';\n }\n\t\t\t\t// Add the column name, operator and parameter name to the list of where value parenthetical\n tmpfAddFilter(tmpFilterCommand, [tmpFilter[i].Column, tmpfTranslateOperator(tmpFilter[i].Operator), encodeURIComponent(tmpFilter[i].Value)]);\n\t\t\t}\n\t\t}\n\n let tmpOrderBy = generateOrderBy(pParameters);\n if (tmpOrderBy)\n {\n if (tmpURL)\n {\n tmpURL += '~';\n }\n tmpURL += tmpOrderBy;\n }\n\n\t\treturn tmpURL;\n\t};\n\n /**\n\t * Get the flags for the request\n * \n * These are usually passed in for Update and Create when extra tracking is disabled.\n\t *\n\t * @method: generateFlags\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Flags to be sent, if any.\n\t */\n function generateFlags(pParameters)\n {\n let tmpDisableAutoDateStamp = pParameters.query.disableAutoDateStamp;\n let tmpDisableDeleteTracking = pParameters.query.disableDeleteTracking;\n let tmpDisableAutoIdentity = pParameters.query.disableAutoIdentity;\n let tmpDisableAutoUserStamp = pParameters.query.disableAutoUserStamp;\n\n let tmpFlags = '';\n\n let fAddFlag = (pFlagSet, pFlag) =>\n {\n if (pFlagSet)\n {\n if (tmpFlags.length > 0)\n {\n tmpFlags += ',';\n }\n tmpFlags += pFlag;\n }\n };\n\n fAddFlag(tmpDisableAutoDateStamp, 'DisableAutoDateStamp');\n fAddFlag(tmpDisableDeleteTracking, 'DisableDeleteTracking');\n fAddFlag(tmpDisableAutoIdentity, 'DisableAutoIdentity');\n fAddFlag(tmpDisableAutoUserStamp, 'DisableAutoUserStamp');\n\n return tmpFlags;\n };\n\n /**\n\t * Get the ID for the record, to be used in URIs\n\t *\n\t * @method: getIDRecord\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} ID of the record in string form for the URI\n\t */\n\tvar getIDRecord = function(pParameters)\n\t{\n var tmpFilter = Array.isArray(pParameters.filter) ? pParameters.filter : [];\n\n\t\tvar tmpIDRecord = false;\n\n if (tmpFilter.length < 1)\n\t\t{\n\t\t\treturn tmpIDRecord;\n\t\t}\n\n\t\tfor (var i = 0; i < tmpFilter.length; i++)\n\t\t{\n // Check Schema Entry Type\n var tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\t\t\tvar tmpSchemaEntry = {Column:tmpFilter[i].Column, Type:'Default'};\n\t\t\tfor (var j = 0; j < tmpSchema.length; j++)\n\t\t\t{\n // If this column is the AutoIdentity, set it.\n\t\t\t\tif ((tmpFilter[i].Column == tmpSchema[j].Column) &&\n (tmpSchema[j].Type == 'AutoIdentity'))\n\t\t\t\t{\n tmpIDRecord = tmpFilter[i].Value;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn tmpIDRecord;\n }\n\t\n /**\n\t * Generate an ORDER BY clause from the sort array\n\t *\n\t * Each entry in the sort is an object like:\n\t * {Column:'Color',Direction:'Descending'}\n\t *\n\t * @method: generateOrderBy\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Returns the field list clause\n\t */\n\tvar generateOrderBy = function(pParameters)\n\t{\n\t\tvar tmpOrderBy = pParameters.sort;\n\t\tvar tmpOrderClause = false;\n\n if (!Array.isArray(tmpOrderBy) || tmpOrderBy.length < 1)\n\t\t{\n\t\t\treturn tmpOrderClause;\n\t\t}\n\n tmpOrderClause = '';\n\n for (var i = 0; i < tmpOrderBy.length; i++)\n\t\t{\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\ttmpOrderClause += '~';\n\t\t\t}\n\t\t\ttmpOrderClause += `FSF~${tmpOrderBy[i].Column}~`;\n\n\t\t\tif (tmpOrderBy[i].Direction == 'Descending')\n\t\t\t{\n\t\t\t\ttmpOrderClause += 'DESC~0';\n\t\t\t}\n else\n {\n tmpOrderClause += 'ASC~0'\n }\n\t\t}\n\t\treturn tmpOrderClause;\n\t};\n\n\t/**\n\t * Generate the limit clause\n\t *\n\t * @method: generateLimit\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Returns the table name clause\n\t */\n\tvar generateLimit = function(pParameters)\n\t{\n\t\tif (!pParameters.cap)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n let tmpBegin = (pParameters.begin !== false) ? pParameters.begin : 0;\n\n return `${tmpBegin}/${pParameters.cap}`;\n\t};\n\n\tvar Create = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n var tmpFlags = generateFlags(pParameters);\n\n if (tmpTableName)\n {\n let tmpURL = tmpTableName;\n if (tmpFlags)\n {\n tmpURL = `${tmpURL}/WithFlags/${tmpFlags}`\n }\n return tmpURL;\n }\n else\n {\n return false;\n }\n\t};\n\n\n\t/**\n\t* Read one or many records\n\t*\n\t* @method Read\n\t* @param {Object} pParameters SQL Query parameters\n\t* @return {String} Returns the current Query for chaining.\n\t*/\n\tvar Read = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpFieldList = generateFieldList(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpLimit = generateLimit(pParameters);\n\n\t\tvar tmpURL = `${tmpTableName}`;\n\t\t// In the case that there is only a single query parameter, and the parameter is a single identity, \n\t\t// we will cast it to the READ endpoint rather than READS.\n\t\tif ((pParameters.filter)\n\t\t\t && (pParameters.filter.length == 1)\n // If there is exactly one query filter parameter\n\t\t\t && (pParameters.filter[0].Column === generateIdentityColumnName(pParameters))\n\t\t\t // AND It is the Identity column\n\t\t\t && (pParameters.filter[0].Operator === '=')\n\t\t\t // AND The comparators is a simple equals \n\t\t\t && (tmpLimit == '') && (tmpFieldList == '')\n\t\t\t // AND There is no limit or field list set\n\t\t\t && (!pParameters.sort))\n\t\t\t // AND There is no sort clause\n\t\t{\n\t\t\t// THEN This is a SINGLE READ by presumption.\n\t\t\t// There are some bad side affects this could cause with chaining and overridden behaviors, if \n\t\t\t// we are requesting a filtered list of 1 record.\n\t\t\ttmpURL = `${tmpURL}/${pParameters.filter[0].Value}`;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpURL = `${tmpURL}s`;\n\t\t\tif (tmpFieldList)\n\t\t\t{\n\t\t\t\ttmpURL = `${tmpURL}/LiteExtended/${tmpFieldList}`\n\t\t\t}\n\t\t\tif (tmpWhere)\n\t\t\t{\n\t\t\t\ttmpURL = `${tmpURL}/FilteredTo/${tmpWhere}`;\n\t\t\t}\n\t\t\tif (tmpLimit)\n\t\t\t{\n\t\t\t\ttmpURL = `${tmpURL}/${tmpLimit}`;\n\t\t\t}\n\t\t}\n\n\t\treturn tmpURL;\n\t};\n\n\tvar Update = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n var tmpFlags = generateFlags(pParameters);\n\n if (tmpTableName)\n {\n let tmpURL = tmpTableName;\n if (tmpFlags)\n {\n tmpURL = `${tmpURL}/WithFlags/${tmpFlags}`\n }\n return tmpURL;\n }\n else\n {\n return false;\n }\n\t};\n\n\tvar Delete = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpIDRecord = getIDRecord(pParameters);\n\n if (!tmpIDRecord)\n {\n return false;\n }\n\n\t\treturn `${tmpTableName}/${tmpIDRecord}`;\n\t};\n\n\tvar Count = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\n let tmpCountQuery = `${tmpTableName}s/Count`;\n\n if (tmpWhere)\n {\n return `${tmpTableName}s/Count/FilteredTo/${tmpWhere}`;\n }\n\n return tmpCountQuery;\n\t};\n\n\tvar tmpDialect = ({\n\t\tCreate: Create,\n\t\tRead: Read,\n\t\tUpdate: Update,\n\t\tDelete: Delete,\n\t\tCount: Count\n\t});\n\n\t/**\n\t * Dialect Name\n\t *\n\t * @property name\n\t * @type string\n\t */\n\tObject.defineProperty(tmpDialect, 'name',\n\t\t{\n\t\t\tget: function() { return 'MeadowEndpoints'; },\n\t\t\tenumerable: true\n\t\t});\n\n\treturn tmpDialect;\n};\n\nmodule.exports = FoxHoundDialectMeadowEndpoints;\n\n},{}],8:[function(require,module,exports){\n/**\n* FoxHound MySQL Dialect\n*\n* @license MIT\n*\n* For a MySQL query override:\n// An underscore template with the following values:\n// <%= DataElements %> = Field1, Field2, Field3, Field4\n// <%= Begin %> = 0\n// <%= Cap %> = 10\n// <%= Filter %> = WHERE StartDate > :MyStartDate\n// <%= Sort %> = ORDER BY Field1\n// The values are empty strings if they aren't set.\n*\n* @author Steven Velozo <steven@velozo.com>\n* @class FoxHoundDialectMySQL\n*/\n\nvar FoxHoundDialectMySQL = function(pFable)\n{\n\t//Request time from SQL server with microseconds resolution\n\tconst SQL_NOW = \"NOW(3)\";\n\n\t_Fable = pFable;\n\n\t/**\n\t* Generate a table name from the scope\n\t*\n\t* @method: generateTableName\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateTableName = function(pParameters)\n\t{\n\t\tif (pParameters.scope && pParameters.scope.indexOf('`') >= 0)\n\t\t\treturn ' '+pParameters.scope+'';\n\t\telse\n\t\t\treturn ' `'+pParameters.scope+'`';\n\t};\n\n\t/**\n\t* Generate a field list from the array of dataElements\n\t*\n\t* Each entry in the dataElements is a simple string\n\t*\n\t* @method: generateFieldList\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @param {Boolean} pIsForCountClause (optional) If true, generate fields for use within a count clause.\n\t* @return: {String} Returns the field list clause, or empty string if explicit fields are requested but cannot be fulfilled\n\t* due to missing schema.\n\t*/\n\tvar generateFieldList = function(pParameters, pIsForCountClause)\n\t{\n\t\tvar tmpDataElements = pParameters.dataElements;\n\t\tif (!Array.isArray(tmpDataElements) || tmpDataElements.length < 1)\n\t\t{\n\t\t\tconst tmpTableName = generateTableName(pParameters);\n\t\t\tif (!pIsForCountClause)\n\t\t\t{\n\t\t\t\treturn tmpTableName + '.*';\n\t\t\t}\n\t\t\t// we need to list all of the table fields explicitly; get them from the schema\n\t\t\tconst tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\t\t\tif (tmpSchema.length < 1)\n\t\t\t{\n\t\t\t\t// this means we have no schema; returning an empty string here signals the calling code to handle this case\n\t\t\t\treturn '';\n\t\t\t}\n\t\t\tconst idColumn = tmpSchema.find((entry) => entry.Type === 'AutoIdentity');\n\t\t\tif (!idColumn)\n\t\t\t{\n\t\t\t\t// this means there is no autoincrementing unique ID column; treat as above\n\t\t\t\treturn '';\n\t\t\t}\n\t\t\tconst qualifiedIDColumn = `${tmpTableName}.${idColumn.Column}`;\n\t\t\treturn ` ${generateSafeFieldName(qualifiedIDColumn)}`;\n\t\t}\n\n\t\tvar tmpFieldList = ' ';\n\t\tfor (var i = 0; i < tmpDataElements.length; i++)\n\t\t{\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\ttmpFieldList += ', ';\n\t\t\t}\n\t\t\tif (Array.isArray(tmpDataElements[i]))\n\t\t\t{\n\t\t\t\ttmpFieldList += generateSafeFieldName(tmpDataElements[i][0]);\n\t\t\t\tif (tmpDataElements[i].length > 1 && tmpDataElements[i][1])\n\t\t\t\t{\n\t\t\t\t\ttmpFieldList += \" AS \" + generateSafeFieldName(tmpDataElements[i][1]);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpFieldList += generateSafeFieldName(tmpDataElements[i]);\n\t\t\t}\n\t\t}\n\t\treturn tmpFieldList;\n\t};\n\n\tconst SURROUNDING_QUOTES_AND_WHITESPACE_REGEX = /^[` ]+|[` ]+$/g;\n\n\tconst cleanseQuoting = (str) =>\n\t{\n\t\treturn str.replace(SURROUNDING_QUOTES_AND_WHITESPACE_REGEX, '');\n\t};\n\n\t/**\n\t* Ensure a field name is properly escaped.\n\t*/\n\tvar generateSafeFieldName = function(pFieldName)\n\t{\n\t\tlet pFieldNames = pFieldName.split('.');\n\t\tif (pFieldNames.length > 1)\n\t\t{\n\t\t\tconst cleansedFieldName = cleanseQuoting(pFieldNames[1]);\n\t\t\tif (cleansedFieldName === '*')\n\t\t\t{\n\t\t\t\t// do not put * as `*`\n\t\t\t\treturn \"`\" + cleanseQuoting(pFieldNames[0]) + \"`.*\";\n\t\t\t}\n\t\t\treturn \"`\" + cleanseQuoting(pFieldNames[0]) + \"`.`\" + cleansedFieldName + \"`\";\n\t\t}\n\t\tconst cleansedFieldName = cleanseQuoting(pFieldNames[0]);\n\t\tif (cleansedFieldName === '*')\n\t\t{\n\t\t\t// do not put * as `*`\n\t\t\treturn '*';\n\t\t}\n\t\treturn \"`\" + cleanseQuoting(pFieldNames[0]) + \"`\";\n\t}\n\n\t/**\n\t* Generate a query from the array of where clauses\n\t*\n\t* Each clause is an object like:\n\t\t{\n\t\t\tColumn:'Name',\n\t\t\tOperator:'EQ',\n\t\t\tValue:'John',\n\t\t\tConnector:'And',\n\t\t\tParameter:'Name'\n\t\t}\n\t*\n\t* @method: generateWhere\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the WHERE clause prefixed with WHERE, or an empty string if unnecessary\n\t*/\n\tvar generateWhere = function(pParameters)\n\t{\n\t\tvar tmpFilter = Array.isArray(pParameters.filter) ? pParameters.filter : [];\n\t\tvar tmpTableName = generateTableName(pParameters);\n\n\t\tif (!pParameters.query.disableDeleteTracking)\n\t\t{\n\t\t\t// Check if there is a Deleted column on the Schema. If so, we add this to the filters automatically (if not already present)\n\t\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\tvar tmpSchemaEntry = tmpSchema[i];\n\n\t\t\t\tif (tmpSchemaEntry.Type === 'Deleted')\n\t\t\t\t{\n\t\t\t\t\tvar tmpHasDeletedParameter = false;\n\n\t\t\t\t\t//first, check to see if filters are already looking for Deleted column\n\t\t\t\t\tif (tmpFilter.length > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (var x = 0; x < tmpFilter.length; x++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (tmpFilter[x].Column === tmpSchemaEntry.Column)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttmpHasDeletedParameter = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (!tmpHasDeletedParameter)\n\t\t\t\t\t{\n\t\t\t\t\t\t//if not, we need to add it\n\t\t\t\t\t\ttmpFilter.push(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tColumn: tmpTableName + '.' + tmpSchemaEntry.Column,\n\t\t\t\t\t\t\tOperator: '=',\n\t\t\t\t\t\t\tValue: 0,\n\t\t\t\t\t\t\tConnector: 'AND',\n\t\t\t\t\t\t\tParameter: 'Deleted'\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (tmpFilter.length < 1)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpWhere = ' WHERE';\n\n\t\t// This is used to disable the connectors for subsequent queries.\n\t\t// Only the open parenthesis operator uses this, currently.\n\t\tvar tmpLastOperatorNoConnector = false;\n\n\t\tfor (var i = 0; i < tmpFilter.length; i++)\n\t\t{\n\t\t\tif ((tmpFilter[i].Connector != 'NONE') && (tmpFilter[i].Operator != ')') && (tmpWhere != ' WHERE') && (tmpLastOperatorNoConnector == false))\n\t\t\t{\n\t\t\t\ttmpWhere += ' '+tmpFilter[i].Connector;\n\t\t\t}\n\n\t\t\ttmpLastOperatorNoConnector = false;\n\n\t\t\tvar tmpColumnParameter;\n\n\t\t\tif (tmpFilter[i].Operator === '(')\n\t\t\t{\n\t\t\t\t// Open a logical grouping\n\t\t\t\ttmpWhere += ' (';\n\t\t\t\ttmpLastOperatorNoConnector = true;\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === ')')\n\t\t\t{\n\t\t\t\t// Close a logical grouping\n\t\t\t\ttmpWhere += ' )';\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IN' || tmpFilter[i].Operator === \"NOT IN\")\n\t\t\t{\n\t\t\t\ttmpColumnParameter = tmpFilter[i].Parameter+'_w'+i;\n\t\t\t\t// Add the column name, operator and parameter name to the list of where value parenthetical\n\t\t\t\ttmpWhere += ' '+tmpFilter[i].Column+' '+tmpFilter[i].Operator+' ( :'+tmpColumnParameter+' )';\n\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = tmpFilter[i].Value;\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IS NULL')\n\t\t\t{\n\t\t\t\t// IS NULL is a special operator which doesn't require a value, or parameter\n\t\t\t\ttmpWhere += ' '+tmpFilter[i].Column+' '+tmpFilter[i].Operator;\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IS NOT NULL')\n\t\t\t{\n\t\t\t\t// IS NOT NULL is a special operator which doesn't require a value, or parameter\n\t\t\t\ttmpWhere += ' '+tmpFilter[i].Column+' '+tmpFilter[i].Operator;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpColumnParameter = tmpFilter[i].Parameter+'_w'+i;\n\t\t\t\t// Add the column name, operator and parameter name to the list of where value parenthetical\n\t\t\t\ttmpWhere += ' '+tmpFilter[i].Column+' '+tmpFilter[i].Operator+' :'+tmpColumnParameter;\n\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = tmpFilter[i].Value;\n\t\t\t}\n\t\t}\n\n\t\treturn tmpWhere;\n\t};\n\n\t/**\n\t* Generate an ORDER BY clause from the sort array\n\t*\n\t* Each entry in the sort is an object like:\n\t* {Column:'Color',Direction:'Descending'}\n\t*\n\t* @method: generateOrderBy\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the field list clause\n\t*/\n\tvar generateOrderBy = function(pParameters)\n\t{\n\t\tvar tmpOrderBy = pParameters.sort;\n\t\tif (!Array.isArray(tmpOrderBy) || tmpOrderBy.length < 1)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpOrderClause = ' ORDER BY';\n\t\tfor (var i = 0; i < tmpOrderBy.length; i++)\n\t\t{\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\ttmpOrderClause += ',';\n\t\t\t}\n\t\t\ttmpOrderClause += ' '+tmpOrderBy[i].Column;\n\n\t\t\tif (tmpOrderBy[i].Direction == 'Descending')\n\t\t\t{\n\t\t\t\ttmpOrderClause += ' DESC';\n\t\t\t}\n\t\t}\n\t\treturn tmpOrderClause;\n\t};\n\n\t/**\n\t* Generate the limit clause\n\t*\n\t* @method: generateLimit\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateLimit = function(pParameters)\n\t{\n\t\tif (!pParameters.cap)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpLimit = ' LIMIT';\n\t\t// If there is a begin record, we'll pass that in as well.\n\t\tif (pParameters.begin !== false)\n\t\t{\n\t\t\ttmpLimit += ' ' + pParameters.begin + ',';\n\t\t}\n\t\t// Cap is required for a limit clause.\n\t\ttmpLimit += ' ' + pParameters.cap;\n\n\t\treturn tmpLimit;\n\t};\n\n\t/**\n\t* Generate the join clause\n\t*\n\t* @method: generateJoins\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the join clause\n\t*/\n\tvar generateJoins = function(pParameters)\n\t{\n\t\tvar tmpJoins = pParameters.join;\n\t\tif (!Array.isArray(tmpJoins) || tmpJoins.length < 1)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpJoinClause = ''; //ex. ' INNER JOIN';\n\t\tfor (var i = 0; i < tmpJoins.length; i++)\n\t\t{\n\t\t\tvar join = tmpJoins[i];\n\t\t\t//verify that all required fields are valid\n\t\t\tif (join.Type && join.Table && join.From && join.To)\n\t\t\t{\n\t\t\t\ttmpJoinClause += ` ${join.Type} ${join.Table} ON ${join.From} = ${join.To}`;\n\t\t\t}\n\t\t}\n\n\t\treturn tmpJoinClause;\n\t}\n\n\t/**\n\t* Generate the update SET clause\n\t*\n\t* @method: generateUpdateSetters\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateUpdateSetters = function(pParameters)\n\t{\n\t\tvar tmpRecords = pParameters.query.records;\n\t\t// We need to tell the query not to generate improperly if there are no values to set.\n\t\tif (!Array.isArray(tmpRecords) || tmpRecords.length < 1)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpUpdate = '';\n\t\t// If there is more than one record in records, we are going to ignore them for now.\n\t\tvar tmpCurrentColumn = 0;\n\t\tfor(var tmpColumn in tmpRecords[0])\n\t\t{\n\t\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\t\tvar tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\tif (tmpColumn == tmpSchema[i].Column)\n\t\t\t\t{\n\t\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\t\ttmpSchemaEntry = tmpSchema[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (pParameters.query.disableAutoDateStamp &&\n\t\t\t\ttmpSchemaEntry.Type === 'UpdateDate')\n\t\t\t{\n\t\t\t\t// This is ignored if flag is set\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (pParameters.query.disableAutoUserStamp &&\n\t\t\t\ttmpSchemaEntry.Type === 'UpdateIDUser')\n\t\t\t{\n\t\t\t\t// This is ignored if flag is set\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'AutoIdentity':\n\t\t\t\tcase 'CreateDate':\n\t\t\t\tcase 'CreateIDUser':\n\t\t\t\tcase 'DeleteDate':\n\t\t\t\tcase 'DeleteIDUser':\n\t\t\t\t\t// These are all ignored on update\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpUpdate += ',';\n\t\t\t}\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\ttmpUpdate += ' '+tmpColumn+' = ' + SQL_NOW;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateIDUser':\n\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\tvar tmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdate += ' '+tmpColumn+' = :'+tmpColumnParameter;\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tvar tmpColumnDefaultParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdate += ' '+tmpColumn+' = :'+tmpColumnDefaultParameter;\n\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnDefaultParameter] = tmpRecords[0][tmpColumn];\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// We use a number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (tmpUpdate === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpUpdate;\n\t};\n\n\t/**\n\t* Generate the update-delete SET clause\n\t*\n\t* @method: generateUpdateDeleteSetters\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateUpdateDeleteSetters = function(pParameters)\n\t{\n\t\tif (pParameters.query.disableDeleteTracking)\n\t\t{\n\t\t\t//Don't generate an UPDATE query if Delete tracking is disabled\n\t\t\treturn false;\n\t\t}\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpCurrentColumn = 0;\n\t\tvar tmpHasDeletedField = false;\n\t\tvar tmpUpdate = '';\n\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\tvar tmpSchemaEntry = {Type:'Default'};\n\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t{\n\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\ttmpSchemaEntry = tmpSchema[i];\n\n\t\t\tvar tmpUpdateSql = null;\n\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'Deleted':\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = 1';\n\t\t\t\t\ttmpHasDeletedField = true; //this field is required in order for query to be built\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'DeleteDate':\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = ' + SQL_NOW;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\t\t// Delete operation is an Update, so we should stamp the update time\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = ' + SQL_NOW;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'DeleteIDUser':\n\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\tvar tmpColumnParameter = tmpSchemaEntry.Column+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = :'+tmpColumnParameter;\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t//DON'T allow update of other fields in this query\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpUpdate += ',';\n\t\t\t}\n\n\t\t\ttmpUpdate += tmpUpdateSql;\n\n\t\t\t// We use a number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (!tmpHasDeletedField ||\n\t\t\ttmpUpdate === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpUpdate;\n\t};\n\n\t/**\n\t* Generate the update-undelete SET clause\n\t*\n\t* @method: generateUpdateUndeleteSetters\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateUpdateUndeleteSetters = function(pParameters)\n\t{\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpCurrentColumn = 0;\n\t\tvar tmpHasDeletedField = false;\n\t\tvar tmpUpdate = '';\n\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\tvar tmpSchemaEntry = {Type:'Default'};\n\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t{\n\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\ttmpSchemaEntry = tmpSchema[i];\n\n\t\t\tvar tmpUpdateSql = null;\n\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'Deleted':\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = 0';\n\t\t\t\t\ttmpHasDeletedField = true; //this field is required in order for query to be built\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\t\t// The undelete operation is an Update, so we should stamp the update time\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = ' + SQL_NOW;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateIDUser':\n\t\t\t\t\tvar tmpColumnParameter = tmpSchemaEntry.Column+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = :'+tmpColumnParameter;\n\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t//DON'T allow update of other fields in this query\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpUpdate += ',';\n\t\t\t}\n\n\t\t\ttmpUpdate += tmpUpdateSql;\n\n\t\t\t// We use a number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (!tmpHasDeletedField ||\n\t\t\ttmpUpdate === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpUpdate;\n\t};\n\n\t/**\n\t* Generate the create SET clause\n\t*\n\t* @method: generateCreateSetList\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateCreateSetValues = function(pParameters)\n\t{\n\t\tvar tmpRecords = pParameters.query.records;\n\t\t// We need to tell the query not to generate improperly if there are no values to set.\n\t\tif (!Array.isArray(tmpRecords) || tmpRecords.length < 1)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\n\t\tvar tmpCreateSet = '';\n\t\t// If there is more than one record in records, we are going to ignore them for now.\n\t\tvar tmpCurrentColumn = 0;\n\t\tfor(var tmpColumn in tmpRecords[0])\n\t\t{\n\t\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\t\tvar tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\tif (tmpColumn == tmpSchema[i].Column)\n\t\t\t\t{\n\t\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\t\ttmpSchemaEntry = tmpSchema[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!pParameters.query.disableDeleteTracking)\n\t\t\t{\n\t\t\t\tif (tmpSchemaEntry.Type === 'DeleteDate' ||\n\t\t\t\t\ttmpSchemaEntry.Type === 'DeleteIDUser')\n\t\t\t\t{\n\t\t\t\t\t// These are all ignored on insert (if delete tracking is enabled as normal)\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpCreateSet += ',';\n\t\t\t}\n\n\t\t\t//define a re-usable method for setting up field definitions in a default pattern\n\t\t\tvar buildDefaultDefinition = function()\n\t\t\t{\n\t\t\t\tvar tmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\ttmpCreateSet += ' :'+tmpColumnParameter;\n\t\t\t\t// Set the query parameter\n\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = tmpRecords[0][tmpColumn];\n\t\t\t};\n\n\t\t\tvar tmpColumnParameter;\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'AutoIdentity':\n\t\t\t\t\tif (pParameters.query.disableAutoIdentity)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\t\ttmpCreateSet += ' NULL';\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'AutoGUID':\n\t\t\t\t\tif (pParameters.query.disableAutoIdentity)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse if (tmpRecords[0][tmpColumn] &&\n\t\t\t\t\t\t\ttmpRecords[0][tmpColumn].length >= 5 &&\n\t\t\t\t\t\t\ttmpRecords[0][tmpColumn] !== '0x0000000000000000') //stricture default\n\t\t\t\t\t{\n\t\t\t\t\t\t// Allow consumer to override AutoGUID\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\t\ttmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\t\ttmpCreateSet += ' :'+tmpColumnParameter;\n\t\t\t\t\t\t// Set the query parameter\n\t\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.UUID;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\tcase 'CreateDate':\n\t\t\t\tcase 'DeleteDate':\n\t\t\t\t\tif (pParameters.query.disableAutoDateStamp)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\t\ttmpCreateSet += ' ' + SQL_NOW;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'DeleteIDUser':\n\t\t\t\tcase 'UpdateIDUser':\n\t\t\t\tcase 'CreateIDUser':\n\t\t\t\t\tif (pParameters.query.disableAutoUserStamp)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\t\ttmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\t\ttmpCreateSet += ' :'+tmpColumnParameter;\n\t\t\t\t\t\t// Set the query parameter\n\t\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// We use an appended number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (tmpCreateSet === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpCreateSet;\n\t};\n\n\t/**\n\t* Generate the create SET clause\n\t*\n\t* @method: generateCreateSetList\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateCreateSetList = function(pParameters)\n\t{\n\t\t// The records were already validated by generateCreateSetValues\n\t\tvar tmpRecords = pParameters.query.records;\n\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpCreateSet = '';\n\t\t// If there is more than one record in records, we are going to ignore them for now.\n\t\tfor(var tmpColumn in tmpRecords[0])\n\t\t{\n\t\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\t\tvar tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\tif (tmpColumn == tmpSchema[i].Column)\n\t\t\t\t{\n\t\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\t\ttmpSchemaEntry = tmpSchema[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!pParameters.query.disableDeleteTracking)\n\t\t\t{\n\t\t\t\tif (tmpSchemaEntry.Type === 'DeleteDate' ||\n\t\t\t\t\ttmpSchemaEntry.Type === 'DeleteIDUser')\n\t\t\t\t{\n\t\t\t\t\t// These are all ignored on insert (if delete tracking is enabled as normal)\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tdefault:\n\t\t\t\t\tif (tmpCreateSet != '')\n\t\t\t\t\t{\n\t\t\t\t\t\ttmpCreateSet += ',';\n\t\t\t\t\t}\n\t\t\t\t\ttmpCreateSet += ' '+tmpColumn;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn tmpCreateSet;\n\t};\n\n\n\tvar Create = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpCreateSetList = generateCreateSetList(pParameters);\n\t\tvar tmpCreateSetValues = generateCreateSetValues(pParameters);\n\n\t\tif (!tmpCreateSetValues)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn 'INSERT INTO'+tmpTableName+' ('+tmpCreateSetList+') VALUES ('+tmpCreateSetValues+');';\n\t};\n\n\n\t/**\n\t* Read one or many records\n\t*\n\t* Some examples:\n\t* SELECT * FROM WIDGETS;\n\t* SELECT * FROM WIDGETS LIMIT 0, 20;\n\t* SELECT * FROM WIDGETS LIMIT 5, 20;\n\t* SELECT ID, Name, Cost FROM WIDGETS LIMIT 5, 20;\n\t* SELECT ID, Name, Cost FROM WIDGETS LIMIT 5, 20 WHERE LastName = 'Smith';\n\t*\n\t* @method Read\n\t* @param {Object} pParameters SQL Query parameters\n\t* @return {String} Returns the current Query for chaining.\n\t*/\n\tvar Read = function(pParameters)\n\t{\n\t\tvar tmpFieldList = generateFieldList(pParameters);\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpJoin = generateJoins(pParameters);\n\t\tvar tmpOrderBy = generateOrderBy(pParameters);\n\t\tvar tmpLimit = generateLimit(pParameters);\n\t\tconst tmpOptDistinct = pParameters.distinct ? ' DISTINCT' : '';\n\n\t\tif (pParameters.queryOverride)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tvar tmpQueryTemplate = _Fable.Utility.template(pParameters.queryOverride);\n\t\t\t\treturn tmpQueryTemplate({FieldList:tmpFieldList, TableName:tmpTableName, Where:tmpWhere, Join:tmpJoin, OrderBy:tmpOrderBy, Limit:tmpLimit, Distinct: tmpOptDistinct, _Params: pParameters});\n\t\t\t}\n\t\t\tcatch (pError)\n\t\t\t{\n\t\t\t\t// This pokemon is here to give us a convenient way of not throwing up totally if the query fails.\n\t\t\t\tconsole.log('Error with custom Read Query ['+pParameters.queryOverride+']: '+pError);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn `SELECT${tmpOptDistinct}${tmpFieldList} FROM${tmpTableName}${tmpJoin}${tmpWhere}${tmpOrderBy}${tmpLimit};`;\n\t};\n\n\tvar Update = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpUpdateSetters = generateUpdateSetters(pParameters);\n\n\t\tif (!tmpUpdateSetters)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn 'UPDATE'+tmpTableName+' SET'+tmpUpdateSetters+tmpWhere+';';\n\t};\n\n\tvar Delete = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpUpdateDeleteSetters = generateUpdateDeleteSetters(pParameters);\n\n\t\tif (tmpUpdateDeleteSetters)\n\t\t{\n\t\t\t//If it has a deleted bit, update it instead of actually deleting the record\n\t\t\treturn 'UPDATE'+tmpTableName+' SET'+tmpUpdateDeleteSetters+tmpWhere+';';\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn 'DELETE FROM'+tmpTableName+tmpWhere+';';\n\t\t}\n\t};\n\n\tvar Undelete = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\t// TODO: Fix these\n\t\tlet tmpDeleteTrackingState = pParameters.query.disableDeleteTracking;\n\t\tpParameters.query.disableDeleteTracking = true;\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpUpdateUndeleteSetters = generateUpdateUndeleteSetters(pParameters);\n\t\tpParameters.query.disableDeleteTracking = tmpDeleteTrackingState;\n\n\t\tif (tmpUpdateUndeleteSetters)\n\t\t{\n\t\t\t//If the table has a deleted bit, go forward with the update to change things.\n\t\t\treturn 'UPDATE'+tmpTableName+' SET'+tmpUpdateUndeleteSetters+tmpWhere+';';\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// This is a no-op because the record can't be undeleted.\n\t\t\t// TODO: Should it throw instead?\n\t\t\treturn 'SELECT NULL;';\n\t\t}\n\t};\n\n\tvar Count = function(pParameters)\n\t{\n\t\tvar tmpFieldList = pParameters.distinct ? generateFieldList(pParameters, true) : '*';\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpJoin = generateJoins(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\t// here, we ignore the distinct keyword if no fields have been specified and\n\t\tif (pParameters.distinct && tmpFieldList.length < 1)\n\t\t{\n\t\t\tconsole.warn('Distinct requested but no field list or schema are available, so not honoring distinct for count query.');\n\t\t}\n\t\tconst tmpOptDistinct = pParameters.distinct && tmpFieldList.length > 0 ? 'DISTINCT' : '';\n\n\t\tif (pParameters.queryOverride)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tvar tmpQueryTemplate = _Fable.Utility.template(pParameters.queryOverride);\n\t\t\t\treturn tmpQueryTemplate({FieldList:[], TableName:tmpTableName, Where:tmpWhere, OrderBy:'', Limit:'', Distinct: tmpOptDistinct, _Params: pParameters});\n\t\t\t}\n\t\t\tcatch (pError)\n\t\t\t{\n\t\t\t\t// This pokemon is here to give us a convenient way of not throwing up totally if the query fails.\n\t\t\t\tconsole.log('Error with custom Count Query ['+pParameters.queryOverride+']: '+pError);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn `SELECT COUNT(${tmpOptDistinct}${tmpFieldList || '*'}) AS RowCount FROM${tmpTableName}${tmpJoin}${tmpWhere};`;\n\t};\n\n\tvar tmpDialect = ({\n\t\tCreate: Create,\n\t\tRead: Read,\n\t\tUpdate: Update,\n\t\tDelete: Delete,\n\t\tUndelete: Undelete,\n\t\tCount: Count\n\t});\n\n\t/**\n\t* Dialect Name\n\t*\n\t* @property name\n\t* @type string\n\t*/\n\tObject.defineProperty(tmpDialect, 'name',\n\t\t{\n\t\t\tget: function() { return 'MySQL'; },\n\t\t\tenumerable: true\n\t\t});\n\n\treturn tmpDialect;\n};\n\nmodule.exports = FoxHoundDialectMySQL;\n\n},{}]},{},[1])(1)\n});\n\n","getDialects = () =>\n{\n\tlet tmpDialects = {};\n\n\ttmpDialects.ALASQL = require('./dialects/ALASQL/FoxHound-Dialect-ALASQL.js');\n\ttmpDialects.English = require('./dialects/English/FoxHound-Dialect-English.js');\n\ttmpDialects.MeadowEndpoints = require('./dialects/MeadowEndpoints/FoxHound-Dialect-MeadowEndpoints.js');\n\ttmpDialects.MySQL = require('./dialects/MySQL/FoxHound-Dialect-MySQL.js');\n\n\ttmpDialects.default = tmpDialects.English;\n\n\treturn tmpDialects;\n}\n\nmodule.exports = getDialects();","/**\n* FoxHound Query Generation Library\n* @license MIT\n* @author Steven Velozo <steven@velozo.com>\n*/\n\n// Load our base parameters skeleton object\nconst baseParameters = require('./Parameters.js');\n\nvar FoxHound = function()\n{\n\tfunction createNew(pFable, pFromParameters)\n\t{\n\t\t// If a valid Fable object isn't passed in, return a constructor\n\t\tif ((typeof(pFable) !== 'object') || !('fable' in pFable))\n\t\t{\n\t\t\treturn {new: createNew};\n\t\t}\n\n\t\tvar _Fable = pFable;\n\n\t\t// The default parameters config object, used as a template for all new\n\t\t// queries created from this query.\n\t\tvar _DefaultParameters = (typeof(pFromParameters) === 'undefined') ? {} : pFromParameters;\n\n\t\t// The parameters config object for the current query. This is the only\n\t\t// piece of internal state that is important to operation.\n\t\tvar _Parameters = false;\n\n\t\tvar _Dialects = require('./Foxhound-Dialects.js');\n\n\t\t// The unique identifier for a query\n\t\tvar _UUID = _Fable.getUUID();\n\n\t\t// The log level, for debugging chattiness.\n\t\tvar _LogLevel = 0;\n\n\t\t// The dialect to use when generating queries\n\t\tvar _Dialect = false;\n\n\t\t/**\n\t\t* Clone the current FoxHound Query into a new Query object, copying all\n\t\t* parameters as the new default. Clone also copies the log level.\n\t\t*\n\t\t* @method clone\n\t\t* @return {Object} Returns a cloned Query. This is still chainable.\n\t\t*/\n\t\tvar clone = function()\n\t\t{\n\t\t\tvar tmpFoxHound = createNew(_Fable, baseParameters)\n\t\t\t\t.setScope(_Parameters.scope)\n\t\t\t\t.setBegin(_Parameters.begin)\n\t\t\t\t.setCap(_Parameters.cap);\n\n\t\t\t// Schema is the only part of a query that carries forward.\n\t\t\ttmpFoxHound.query.schema = _Parameters.query.schema;\n\n\t\t\tif (_Parameters.dataElements)\n\t\t\t{\n\t\t\t\ttmpFoxHound.parameters.dataElements = _Parameters.dataElements.slice(); // Copy the array of dataElements\n\t\t\t}\n\t\t\tif (_Parameters.sort)\n\t\t\t{\n\t\t\t\ttmpFoxHound.parameters.sort = _Parameters.sort.slice(); // Copy the sort array.\n\t\t\t\t// TODO: Fix the side affect nature of these being objects in the array .. they are technically clones of the previous.\n\t\t\t}\n\t\t\tif (_Parameters.filter)\n\t\t\t{\n\t\t\t\ttmpFoxHound.parameters.filter = _Parameters.filter.slice(); // Copy the filter array.\n\t\t\t\t// TODO: Fix the side affect nature of these being objects in the array .. they are technically clones of the previous.\n\t\t\t}\n\n\t\t\treturn tmpFoxHound;\n\t\t};\n\n\n\t\t/**\n\t\t* Reset the parameters of the FoxHound Query to the Default. Default\n\t\t* parameters were set during object construction.\n\t\t*\n\t\t* @method resetParameters\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar resetParameters = function()\n\t\t{\n\t\t\t_Parameters = _Fable.Utility.extend({}, baseParameters, _DefaultParameters);\n\t\t\t_Parameters.query = ({\n\t\t\t\tdisableAutoIdentity: false,\n\t\t\t\tdisableAutoDateStamp: false,\n\t\t\t\tdisableAutoUserStamp: false,\n\t\t\t\tdisableDeleteTracking: false,\n\t\t\t\tbody: false,\n\t\t\t\tschema: false, // The schema to intersect with our records\n\t\t\t\tIDUser: 0, // The user to stamp into records\n\t\t\t\tUUID: _Fable.getUUID(), // A UUID for this record\n\t\t\t\trecords: false, // The records to be created or changed\n\t\t\t\tparameters: {}\n\t\t\t});\n\n\t\t\t_Parameters.result = ({\n\t\t\t\texecuted: false, // True once we've run a query.\n\t\t\t\tvalue: false, // The return value of the last query run\n\t\t\t\t// Updated below due to changes in how Async.js responds to a false value here\n\t\t\t\terror: undefined // The error message of the last run query\n\t\t\t});\n\n\t\t\treturn this;\n\t\t};\n\t\tresetParameters();\n\n\t\t/**\n\t\t* Reset the parameters of the FoxHound Query to the Default. Default\n\t\t* parameters were set during object construction.\n\t\t*\n\t\t* @method mergeParameters\n\t\t* @param {Object} pFromParameters A Parameters Object to merge from\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar mergeParameters = function(pFromParameters)\n\t\t{\n\t\t\t_Parameters = _Fable.Utility.extend({}, _Parameters, pFromParameters);\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the the Logging level.\n\t\t*\n\t\t* The log levels are:\n\t\t* 0 - Don't log anything\n\t\t* 1 - Log queries\n\t\t* 2 - Log queries and non-parameterized queries\n\t\t* 3 - Log everything\n\t\t*\n\t\t* @method setLogLevel\n\t\t* @param {Number} pLogLevel The log level for our object\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setLogLevel = function(pLogLevel)\n\t\t{\n\t\t\tvar tmpLogLevel = 0;\n\n\t\t\tif (typeof(pLogLevel) === 'number' && (pLogLevel % 1) === 0)\n\t\t\t{\n\t\t\t\ttmpLogLevel = pLogLevel;\n\t\t\t}\n\n\t\t\t_LogLevel = tmpLogLevel;\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the Scope for the Query. *Scope* is the source for the data being\n\t\t* pulled. In TSQL this would be the _table_, whereas in MongoDB this\n\t\t* would be the _collection_.\n\t\t*\n\t\t* A scope can be either a string, or an array (for JOINs and such).\n\t\t*\n\t\t* @method setScope\n\t\t* @param {String} pScope A Scope for the Query.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setScope = function(pScope)\n\t\t{\n\t\t\tvar tmpScope = false;\n\n\t\t\tif (typeof(pScope) === 'string')\n\t\t\t{\n\t\t\t\ttmpScope = pScope;\n\t\t\t}\n\t\t\telse if (pScope !== false)\n\t\t\t{\n\t\t\t\t_Fable.log.error('Scope set failed. You must pass in a string or array.', {queryUUID:_UUID, parameters:_Parameters, invalidScope:pScope});\n\t\t\t}\n\n\t\t\t_Parameters.scope = tmpScope;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Scope set: '+tmpScope, {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\t\t/**\n\t\t* Set whether the query returns DISTINCT results.\n\t\t* For count queries, returns the distinct for the selected fields, or all fields in the base table by default.\n\t\t*\n\t\t* @method setDistinct\n\t\t* @param {Boolean} pDistinct True if the query should be distinct.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setDistinct = function(pDistinct)\n\t\t{\n\t\t\t_Parameters.distinct = !!pDistinct;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Distinct set: '+_Parameters.distinct, {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the Data Elements for the Query. *Data Elements* are the fields\n\t\t* being pulled by the query. In TSQL this would be the _columns_,\n\t\t* whereas in MongoDB this would be the _fields_.\n\t\t*\n\t\t* The passed values can be either a string, or an array.\n\t\t*\n\t\t* @method setDataElements\n\t\t* @param {String} pDataElements The Data Element(s) for the Query.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setDataElements = function(pDataElements)\n\t\t{\n\t\t\tvar tmpDataElements = false;\n\n\t\t\tif (Array.isArray(pDataElements))\n\t\t\t{\n\t\t\t\t// TODO: Check each entry of the array are all strings\n\t\t\t\ttmpDataElements = pDataElements;\n\t\t\t}\n\t\t\tif (typeof(pDataElements) === 'string')\n\t\t\t{\n\t\t\t\ttmpDataElements = [pDataElements];\n\t\t\t}\n\n\t\t\t_Parameters.dataElements = tmpDataElements;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Data Elements set', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the sort data element\n\t\t*\n\t\t* The passed values can be either a string, an object or an array of objects.\n\t\t*\n\t\t* The Sort object has two values:\n\t\t* {Column:'Birthday', Direction:'Ascending'}\n\t\t*\n\t\t* @method setSort\n\t\t* @param {String} pSort The sort criteria(s) for the Query.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setSort = function(pSort)\n\t\t{\n\t\t\tvar tmpSort = false;\n\n\t\t\tif (Array.isArray(pSort))\n\t\t\t{\n\t\t\t\t// TODO: Check each entry of the array are all conformant sort objects\n\t\t\t\ttmpSort = pSort;\n\t\t\t}\n\t\t\telse if (typeof(pSort) === 'string')\n\t\t\t{\n\t\t\t\t// Default to ascending\n\t\t\t\ttmpSort = [{Column:pSort, Direction:'Ascending'}];\n\t\t\t}\n\t\t\telse if (typeof(pSort) === 'object')\n\t\t\t{\n\t\t\t\t// TODO: Check that this sort entry conforms to a sort entry\n\t\t\t\ttmpSort = [pSort];\n\t\t\t}\n\n\t\t\t_Parameters.sort = tmpSort;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Sort set', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\t\t/**\n\t\t* Set the join data element\n\t\t*\n\t\t* The passed values can be either an object or an array of objects.\n\t\t*\n\t\t* The join object has four values:\n\t\t* {Type:'INNER JOIN', Table:'Test', From:'Test.ID', To:'Scope.IDItem'}\n\t\t*\n\t\t* @method setJoin\n\t\t* @param {Object} pJoin The join criteria(s) for the Query.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setJoin = function(pJoin)\n\t\t{\n\t\t\t_Parameters.join = [];\n\n\t\t\tif (Array.isArray(pJoin))\n\t\t\t{\n\t\t\t\tpJoin.forEach(function(join)\n\t\t\t\t{\n\t\t\t\t\taddJoin(join.Table, join.From, join.To, join.Type);\n\t\t\t\t});\n\t\t\t}\n\t\t\telse if (typeof(pJoin) === 'object')\n\t\t\t{\n\t\t\t\taddJoin(pJoin.Table, pJoin.From, pJoin.To, pJoin.Type);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Add a sort data element\n\t\t*\n\t\t* The passed values can be either a string, an object or an array of objects.\n\t\t*\n\t\t* The Sort object has two values:\n\t\t* {Column:'Birthday', Direction:'Ascending'}\n\t\t*\n\t\t* @method setSort\n\t\t* @param {String} pSort The sort criteria to add to the Query.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar addSort = function(pSort)\n\t\t{\n\t\t\tvar tmpSort = false;\n\n\t\t\tif (typeof(pSort) === 'string')\n\t\t\t{\n\t\t\t\t// Default to ascending\n\t\t\t\ttmpSort = {Column:pSort, Direction:'Ascending'};\n\t\t\t}\n\t\t\tif (typeof(pSort) === 'object')\n\t\t\t{\n\t\t\t\t// TODO: Check that this sort entry conforms to a sort entry\n\t\t\t\ttmpSort = pSort;\n\t\t\t}\n\n\t\t\tif (!_Parameters.sort)\n\t\t\t{\n\t\t\t\t_Parameters.sort = [];\n\t\t\t}\n\n\t\t\t_Parameters.sort.push(tmpSort);\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Sort set', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the the Begin index for the Query. *Begin* is the index at which\n\t\t* a query should start returning rows. In TSQL this would be the n\n\t\t* parameter of ```LIMIT 1,n```, whereas in MongoDB this would be the\n\t\t* n in ```skip(n)```.\n\t\t*\n\t\t* The passed value must be an Integer >= 0.\n\t\t*\n\t\t* @method setBegin\n\t\t* @param {Number} pBeginAmount The index to begin returning Query data.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setBegin = function(pBeginAmount)\n\t\t{\n\t\t\tvar tmpBegin = false;\n\n\t\t\t// Test if it is an integer > -1\n\t\t\t// http://jsperf.com/numbers-and-integers\n\t\t\tif (typeof(pBeginAmount) === 'number' && (pBeginAmount % 1) === 0 && pBeginAmount >= 0)\n\t\t\t{\n\t\t\t\ttmpBegin = pBeginAmount;\n\t\t\t}\n\t\t\telse if (pBeginAmount !== false)\n\t\t\t{\n\t\t\t\t_Fable.log.error('Begin set failed; non-positive or non-numeric argument.', {queryUUID:_UUID, parameters:_Parameters, invalidBeginAmount:pBeginAmount});\n\t\t\t}\n\n\t\t\t_Parameters.begin = tmpBegin;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Begin set: '+pBeginAmount, {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the the Cap for the Query. *Cap* is the maximum number of records\n\t\t* a Query should return in a set. In TSQL this would be the n\n\t\t* parameter of ```LIMIT n```, whereas in MongoDB this would be the\n\t\t* n in ```limit(n)```.\n\t\t*\n\t\t* The passed value must be an Integer >= 0.\n\t\t*\n\t\t* @method setCap\n\t\t* @param {Number} pCapAmount The maximum records for the Query set.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setCap = function(pCapAmount)\n\t\t{\n\t\t\tvar tmpCapAmount = false;\n\n\t\t\tif (typeof(pCapAmount) === 'number' && (pCapAmount % 1) === 0 && pCapAmount >= 0)\n\t\t\t{\n\t\t\t\ttmpCapAmount = pCapAmount;\n\t\t\t}\n\t\t\telse if (pCapAmount !== false)\n\t\t\t{\n\t\t\t\t_Fable.log.error('Cap set failed; non-positive or non-numeric argument.', {queryUUID:_UUID, parameters:_Parameters, invalidCapAmount:pCapAmount});\n\t\t\t}\n\n\n\t\t\t_Parameters.cap = tmpCapAmount;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Cap set to: '+tmpCapAmount, {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\t\t/**\n\t\t* Set the filter expression\n\t\t*\n\t\t* The passed values can be either an object or an array of objects.\n\t\t*\n\t\t* The Filter object has a minimum of two values (which expands to the following):\n\t\t* {Column:'Name', Value:'John'}\n\t\t* {Column:'Name', Operator:'EQ', Value:'John', Connector:'And', Parameter:'Name'}\n\t\t*\n\t\t* @method setFilter\n\t\t* @param {String} pFilter The filter(s) for the Query.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setFilter = function(pFilter)\n\t\t{\n\t\t\tvar tmpFilter = false;\n\n\t\t\tif (Array.isArray(pFilter))\n\t\t\t{\n\t\t\t\t// TODO: Check each entry of the array are all conformant Filter objects\n\t\t\t\ttmpFilter = pFilter;\n\t\t\t}\n\t\t\telse if (typeof(pFilter) === 'object')\n\t\t\t{\n\t\t\t\t// TODO: Check that this Filter entry conforms to a Filter entry\n\t\t\t\ttmpFilter = [pFilter];\n\t\t\t}\n\n\t\t\t_Parameters.filter = tmpFilter;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Filter set', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\n\t\t/**\n\t\t* Add a filter expression\n\t\t*\n\t\t* {Column:'Name', Operator:'EQ', Value:'John', Connector:'And', Parameter:'Name'}\n\t\t*\n\t\t* @method addFilter\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar addFilter = function(pColumn, pValue, pOperator, pConnector, pParameter)\n\t\t{\n\t\t\tif (typeof(pColumn) !== 'string')\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid query filter column', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tif (typeof(pValue) === 'undefined')\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid query filter value', {queryUUID:_UUID, parameters:_Parameters, invalidColumn:pColumn});\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tvar tmpOperator = (typeof(pOperator) === 'undefined') ? '=' : pOperator;\n\t\t\tvar tmpConnector = (typeof(pConnector) === 'undefined') ? 'AND' : pConnector;\n\t\t\tvar tmpParameter = (typeof(pParameter) === 'undefined') ? pColumn : pParameter;\n\n\t\t\t//support table.field notation (mysql2 requires this)\n\t\t\ttmpParameter = tmpParameter.replace('.', '_');\n\n\t\t\tvar tmpFilter = (\n\t\t\t\t{\n\t\t\t\t\tColumn: pColumn,\n\t\t\t\t\tOperator: tmpOperator,\n\t\t\t\t\tValue: pValue,\n\t\t\t\t\tConnector: tmpConnector,\n\t\t\t\t\tParameter: tmpParameter\n\t\t\t\t});\n\n\t\t\tif (!Array.isArray(_Parameters.filter))\n\t\t\t{\n\t\t\t\t_Parameters.filter = [tmpFilter];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_Parameters.filter.push(tmpFilter);\n\t\t\t}\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Added a filter', {queryUUID:_UUID, parameters:_Parameters, newFilter:tmpFilter});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\t\t/**\n\t\t* Add a join expression\n\t\t*\n\t\t* {Type:'INNER JOIN', Table:'Test', From:'Test.ID', To:'Scope.IDItem'}\n\t\t*\n\t\t* @method addJoin\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar addJoin = function(pTable, pFrom, pTo, pType)\n\t\t{\n\t\t\tif (typeof(pTable) !== 'string')\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid query join table', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tif (typeof(pFrom) === 'undefined' || typeof(pTo) === 'undefined')\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid query join field', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\t//sanity check the join fields\n\t\t\tif (pFrom.indexOf(pTable)!=0)\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid query join field, join must come FROM the join table!', {queryUUID:_UUID, parameters:_Parameters, invalidField:pFrom});\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tif (pTo.indexOf('.')<=0)\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid query join field, join must go TO a field on another table ([table].[field])!', {queryUUID:_UUID, parameters:_Parameters, invalidField:pTo});\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tvar tmpType = (typeof(pType) === 'undefined') ? 'INNER JOIN' : pType;\n\n\t\t\tvar tmpJoin = (\n\t\t\t\t{\n\t\t\t\t\tType: tmpType,\n\t\t\t\t\tTable: pTable,\n\t\t\t\t\tFrom: pFrom,\n\t\t\t\t\tTo: pTo\n\t\t\t\t});\n\n\t\t\tif (!Array.isArray(_Parameters.join))\n\t\t\t{\n\t\t\t\t_Parameters.join = [tmpJoin];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_Parameters.join.push(tmpJoin);\n\t\t\t}\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Added a join', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\n\t\t/**\n\t\t* Add a record (for UPDATE and INSERT)\n\t\t*\n\t\t*\n\t\t* @method addRecord\n\t\t* @param {Object} pRecord The record to add.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar addRecord = function(pRecord)\n\t\t{\n\t\t\tif (typeof(pRecord) !== 'object')\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Tried to add an invalid record to the query -- records must be an object', {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tif (!Array.isArray(_Parameters.query.records))\n\t\t\t{\n\t\t\t\t_Parameters.query.records = [pRecord];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_Parameters.query.records.push(pRecord);\n\t\t\t}\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('Added a record to the query', {queryUUID:_UUID, parameters:_Parameters, newRecord:pRecord});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\n\n\t\t/**\n\t\t* Set the Dialect for Query generation.\n\t\t*\n\t\t* This function expects a string, case sensitive, which matches both the\n\t\t* folder and filename\n\t\t*\n\t\t* @method setDialect\n\t\t* @param {String} pDialectName The dialect for query generation.\n\t\t* @return {Object} Returns the current Query for chaining.\n\t\t*/\n\t\tvar setDialect = function(pDialectName)\n\t\t{\n\n\t\t\tif (typeof(pDialectName) !== 'string')\n\t\t\t{\n\t\t\t\t_Fable.log.warn('Dialect set to English - invalid name', {queryUUID:_UUID, parameters:_Parameters, invalidDialect:pDialectName});\n\t\t\t\treturn setDialect('English');\n\t\t\t}\n\n\t\t\tif (_Dialects.hasOwnProperty(pDialectName))\n\t\t\t{\n\t\t\t\t_Dialect = _Dialects[pDialectName](_Fable);\n\t\t\t\tif (_LogLevel > 2)\n\t\t\t\t{\n\t\t\t\t\t_Fable.log.info('Dialog set to: '+pDialectName, {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_Fable.log.error('Dialect not set - unknown dialect \"'+pDialectName+\"'\", {queryUUID:_UUID, parameters:_Parameters, invalidDialect:pDialectName});\n\t\t\t\tsetDialect('English');\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\t\t/**\n\t\t* User to use for this query\n\t\t*\n\t\t* @method setIDUser\n\t\t*/\n\t\tvar setIDUser = function(pIDUser)\n\t\t{\n\n\t\t\tvar tmpUserID = 0;\n\n\t\t\tif (typeof(pIDUser) === 'number' && (pIDUser % 1) === 0 && pIDUser >= 0)\n\t\t\t{\n\t\t\t\ttmpUserID = pIDUser;\n\t\t\t}\n\t\t\telse if (pIDUser !== false)\n\t\t\t{\n\t\t\t\t_Fable.log.error('User set failed; non-positive or non-numeric argument.', {queryUUID:_UUID, parameters:_Parameters, invalidIDUser:pIDUser});\n\t\t\t}\n\n\n\t\t\t_Parameters.userID = tmpUserID;\n\t\t\t_Parameters.query.IDUser = tmpUserID;\n\n\t\t\tif (_LogLevel > 2)\n\t\t\t{\n\t\t\t\t_Fable.log.info('IDUser set to: '+tmpUserID, {queryUUID:_UUID, parameters:_Parameters});\n\t\t\t}\n\n\t\t\treturn this;\n\t\t};\n\n\t\t/**\n\t\t* Flag to disable auto identity\n\t\t*\n\t\t* @method setDisableAutoIdentity\n\t\t*/\n\t\tvar setDisableAutoIdentity = function(pFlag)\n\t\t{\n\t\t\t_Parameters.query.disableAutoIdentity = pFlag;\n\n\t\t\treturn this; //chainable\n\t\t};\n\n\t\t/**\n\t\t* Flag to disable auto datestamp\n\t\t*\n\t\t* @method setDisableAutoDateStamp\n\t\t*/\n\t\tvar setDisableAutoDateStamp = function(pFlag)\n\t\t{\n\t\t\t_Parameters.query.disableAutoDateStamp = pFlag;\n\n\t\t\treturn this; //chainable\n\t\t};\n\n\t\t/**\n\t\t* Flag to disable auto userstamp\n\t\t*\n\t\t* @method setDisableAutoUserStamp\n\t\t*/\n\t\tvar setDisableAutoUserStamp = function(pFlag)\n\t\t{\n\t\t\t_Parameters.query.disableAutoUserStamp = pFlag;\n\n\t\t\treturn this; //chainable\n\t\t};\n\n\t\t/**\n\t\t* Flag to disable delete tracking\n\t\t*\n\t\t* @method setDisableDeleteTracking\n\t\t*/\n\t\tvar setDisableDeleteTracking = function(pFlag)\n\t\t{\n\t\t\t_Parameters.query.disableDeleteTracking = pFlag;\n\n\t\t\treturn this; //chainable\n\t\t};\n\n\t\t/**\n\t\t* Check that a valid Dialect has been set\n\t\t*\n\t\t* If there has not been a dialect set, it defaults to English.\n\t\t* TODO: Have the json configuration define a \"default\" dialect.\n\t\t*\n\t\t* @method checkDialect\n\t\t*/\n\t\tvar checkDialect = function()\n\t\t{\n\t\t\tif (_Dialect === false)\n\t\t\t{\n\t\t\t\tsetDialect('English');\n\t\t\t}\n\t\t};\n\n\n\t\tvar buildCreateQuery = function()\n\t\t{\n\t\t\tcheckDialect();\n\t\t\t_Parameters.query.body = _Dialect.Create(_Parameters);\n\t\t\treturn this;\n\t\t};\n\n\t\tvar buildReadQuery = function()\n\t\t{\n\t\t\tcheckDialect();\n\t\t\t_Parameters.query.body = _Dialect.Read(_Parameters);\n\t\t\treturn this;\n\t\t};\n\n\t\tvar buildUpdateQuery = function()\n\t\t{\n\t\t\tcheckDialect();\n\t\t\t_Parameters.query.body = _Dialect.Update(_Parameters);\n\t\t\treturn this;\n\t\t};\n\n\t\tvar buildDeleteQuery = function()\n\t\t{\n\t\t\tcheckDialect();\n\t\t\t_Parameters.query.body = _Dialect.Delete(_Parameters);\n\t\t\treturn this;\n\t\t};\n\n\t\tvar buildUndeleteQuery = function()\n\t\t{\n\t\t\tcheckDialect();\n\t\t\t_Parameters.query.body = _Dialect.Undelete(_Parameters);\n\t\t\treturn this;\n\t\t};\n\n\t\tvar buildCountQuery = function()\n\t\t{\n\t\t\tcheckDialect();\n\t\t\t_Parameters.query.body = _Dialect.Count(_Parameters);\n\t\t\treturn this;\n\t\t};\n\n\t\t/**\n\t\t* Container Object for our Factory Pattern\n\t\t*/\n\t\tvar tmpNewFoxHoundObject = (\n\t\t{\n\t\t\tresetParameters: resetParameters,\n\t\t\tmergeParameters: mergeParameters,\n\n\t\t\tsetLogLevel: setLogLevel,\n\n\t\t\tsetScope: setScope,\n\t\t\tsetDistinct: setDistinct,\n\t\t\tsetIDUser: setIDUser,\n\t\t\tsetDataElements: setDataElements,\n\t\t\tsetBegin: setBegin,\n\t\t\tsetCap: setCap,\n\t\t\tsetFilter: setFilter,\n\t\t\taddFilter: addFilter,\n\t\t\tsetSort: setSort,\n\t\t\taddSort: addSort,\n\t\t\tsetJoin: setJoin,\n\t\t\taddJoin: addJoin,\n\n\t\t\taddRecord: addRecord,\n\t\t\tsetDisableAutoIdentity: setDisableAutoIdentity,\n\t\t\tsetDisableAutoDateStamp: setDisableAutoDateStamp,\n\t\t\tsetDisableAutoUserStamp: setDisableAutoUserStamp,\n\t\t\tsetDisableDeleteTracking: setDisableDeleteTracking,\n\n\t\t\tsetDialect: setDialect,\n\n\t\t\tbuildCreateQuery: buildCreateQuery,\n\t\t\tbuildReadQuery: buildReadQuery,\n\t\t\tbuildUpdateQuery: buildUpdateQuery,\n\t\t\tbuildDeleteQuery: buildDeleteQuery,\n\t\t\tbuildUndeleteQuery: buildUndeleteQuery,\n\t\t\tbuildCountQuery: buildCountQuery,\n\n\t\t\tclone: clone,\n\t\t\tnew: createNew\n\t\t});\n\n\t\t/**\n\t\t * Query\n\t\t *\n\t\t * @property query\n\t\t * @type Object\n\t\t */\n\t\tObject.defineProperty(tmpNewFoxHoundObject, 'query',\n\t\t\t{\n\t\t\t\tget: function() { return _Parameters.query; },\n\t\t\t\tset: function(pQuery) { _Parameters.query = pQuery; },\n\t\t\t\tenumerable: true\n\t\t\t});\n\n\t\t/**\n\t\t * Result\n\t\t *\n\t\t * @property result\n\t\t * @type Object\n\t\t */\n\t\tObject.defineProperty(tmpNewFoxHoundObject, 'result',\n\t\t\t{\n\t\t\t\tget: function() { return _Parameters.result; },\n\t\t\t\tset: function(pResult) { _Parameters.result = pResult; },\n\t\t\t\tenumerable: true\n\t\t\t});\n\n\t\t/**\n\t\t * Query Parameters\n\t\t *\n\t\t * @property parameters\n\t\t * @type Object\n\t\t */\n\t\tObject.defineProperty(tmpNewFoxHoundObject, 'parameters',\n\t\t\t{\n\t\t\t\tget: function() { return _Parameters; },\n\t\t\t\tset: function(pParameters) { _Parameters = pParameters; },\n\t\t\t\tenumerable: true\n\t\t\t});\n\n\t\t/**\n\t\t * Dialect\n\t\t *\n\t\t * @property dialect\n\t\t * @type Object\n\t\t */\n\t\tObject.defineProperty(tmpNewFoxHoundObject, 'dialect',\n\t\t\t{\n\t\t\t\tget: function() { return _Dialect; },\n\t\t\t\tenumerable: true\n\t\t\t});\n\n\t\t/**\n\t\t * Universally Unique Identifier\n\t\t *\n\t\t * @property uuid\n\t\t * @type String\n\t\t */\n\t\tObject.defineProperty(tmpNewFoxHoundObject, 'uuid',\n\t\t\t{\n\t\t\t\tget: function() { return _UUID; },\n\t\t\t\tenumerable: true\n\t\t\t});\n\n\t\t/**\n\t\t * Log Level\n\t\t *\n\t\t * @property logLevel\n\t\t * @type Integer\n\t\t */\n\t\tObject.defineProperty(tmpNewFoxHoundObject, 'logLevel',\n\t\t\t{\n\t\t\t\tget: function() { return _LogLevel; },\n\t\t\t\tenumerable: true\n\t\t\t});\n\n\t\treturn tmpNewFoxHoundObject;\n\t}\n\n\treturn createNew();\n};\n\nmodule.exports = FoxHound();\n","/**\n* Query Parameters Object\n*\n* @class FoxHoundQueryParameters\n* @constructor\n*/\nvar FoxHoundQueryParameters = (\n{\n\t\tscope: false, // STR: The scope of the data\n\t\t\t\t\t\t\t\t// TSQL: the \"Table\" or \"View\"\n\t\t\t\t\t\t\t\t// MongoDB: the \"Collection\"\n\n\t\tdataElements: false, // ARR of STR: The data elements to return\n\t\t\t\t\t\t\t\t// TSQL: the \"Columns\"\n\t\t\t\t\t\t\t\t// MongoDB: the \"Fields\"\n\n\t\tbegin: false, // INT: Record index to start at\n\t\t\t\t\t\t\t\t// TSQL: n in LIMIT 1,n\n\t\t\t\t\t\t\t\t// MongoDB: n in Skip(n)\n\n\t\tcap: false, // INT: Maximum number of records to return\n\t\t\t\t\t\t\t\t// TSQL: n in LIMIT n\n\t\t\t\t\t\t\t\t// MongoDB: n in limit(n)\n\n\t\t// Serialization example for a query:\n\t\t// Take the filter and return an array of filter instructions\n\t\t// Basic instruction anatomy:\n\t\t// INSTRUCTION~FIELD~OPERATOR~VALUE\n\t\t// FOP - Filter Open Paren\n\t\t// FOP~~(~\n\t\t// FCP - Filter Close Paren\n\t\t// FCP~~)~\n\t\t// FBV - Filter By Value\n\t\t// FBV~Category~EQ~Books\n\t\t// Possible comparisons:\n\t\t// * EQ - Equals To (=)\n\t\t// * NE - Not Equals To (!=)\n\t\t// * GT - Greater Than (>)\n\t\t// * GE - Greater Than or Equals To (>=)\n\t\t// * LT - Less Than (<)\n\t\t// * LE - Less Than or Equals To (<=)\n\t\t// * LK - Like (Like)\n\t\t// FBL - Filter By List (value list, separated by commas)\n\t\t// FBL~Category~EQ~Books,Movies\n\t\t// FSF - Filter Sort Field\n\t\t// FSF~Category~ASC~0\n\t\t// FSF~Category~DESC~0\n\t\t// FCC - Filter Constraint Cap (the limit of what is returned)\n\t\t// FCC~~10~\n\t\t// FCB - Filter Constraint Begin (the zero-based start index of what is returned)\n\t\t// FCB~~10~\n\t\t//\n\t\t// This means: FBV~Category~EQ~Books~FBV~PublishedYear~GT~2000~FSF~PublishedYear~DESC~0\n\t\t// Filters down to ALL BOOKS PUBLISHED AFTER 2000 IN DESCENDING ORDER\n\t\tfilter: false, // ARR of OBJ: Data filter expression list {Column:'Name', Operator:'EQ', Value:'John', Connector:'And', Parameter:'Name'}\n\t\t\t\t\t\t\t\t// TSQL: the WHERE clause\n\t\t\t\t\t\t\t\t// MongoDB: a find() expression\n\n\t\tsort: false, // ARR of OBJ: The sort order {Column:'Birthday', Direction:'Ascending'}\n\t\t\t\t\t\t\t\t// TSQL: ORDER BY\n\t\t\t\t\t\t\t\t// MongoDB: sort()\n\n\t\tjoin: false, // ARR of OBJ: The join tables {Type:'INNER JOIN', Table:'test', From: 'Test.ID', To: 'Scope.IDItem' }\n\t\t\t\t\t\t\t\t// TSQL: JOIN\n\n\t\t// Force a specific query to run regardless of above ... this is used to override the query generator.\n\t\tqueryOverride: false,\n\n\t\t// Where the generated query goes\n\t\tquery: false,\n\t\t/*\n\t\t\t{\n\t\t\t\tbody: false,\n\t\t\t\tschema: false, // The schema to intersect with our records\n\t\t\t\tIDUser: 0, // The User ID to stamp into records\n\t\t\t\tUUID: A_UUID, // Some globally unique record id, different per cloned query.\n\t\t\t\trecords: false, // The records to be created or changed\n\t\t\t\tparameters: {}\n\t\t\t}\n\t\t*/\n\t\t\n\t\t// Who is making the query\n\t\tuserID: 0,\n\n\t\t// Where the query results are stuck\n\t\tresult: false\n\t\t/*\n\t\t\t{\n\t\t\t\texecuted: false, // True once we've run a query.\n\t\t\t\tvalue: false, // The return value of the last query run\n\t\t\t\terror: false // The error message of the last run query\n\t\t\t}\n\t\t*/\n});\n\nmodule.exports = FoxHoundQueryParameters;","/**\n* FoxHound ALASQL Dialect\n*\n* @license MIT\n*\n* For an ALASQL query override:\n// An underscore template with the following values:\n// <%= DataElements %> = Field1, Field2, Field3, Field4\n// <%= Begin %> = 0\n// <%= Cap %> = 10\n// <%= Filter %> = WHERE StartDate > :MyStartDate\n// <%= Sort %> = ORDER BY Field1\n// The values are empty strings if they aren't set.\n*\n* @author Steven Velozo <steven@velozo.com>\n* @class FoxHoundDialectALASQL\n*/\n\nvar FoxHoundDialectALASQL = function(pFable)\n{\n\t//Request time from SQL server with microseconds resolution\n\tconst SQL_NOW = \"NOW(3)\";\n\n\t_Fable = pFable;\n\n\t/**\n\t* Generate a table name from the scope.\n\t*\n\t* Because ALASQL is all in-memory, and can be run in two modes (anonymous\n\t* working on arrays or table-based) we are going to make this a programmable\n\t* value. Then we can share the code across both providers.\n\t*\n\t* @method: generateTableName\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateTableName = function(pParameters)\n\t{\n\t\treturn ' '+pParameters.scope;\n\t};\n\n\t/**\n\t* Escape columns, because ALASQL has more reserved KWs than most SQL dialects\n\t*/\n\tvar escapeColumn = (pColumn, pParameters) =>\n\t{\n\t\tif (pColumn.indexOf('.') < 0)\n\t\t{\n\t\t\treturn '`'+pColumn+'`';\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// This could suck if the scope is not the same\n\t\t\tvar tmpTableName = pParameters.scope;\n\t\t\tif (pColumn.indexOf(tmpTableName+'.') > -1)\n\t\t\t{\n\t\t\t\treturn '`'+pColumn.replace(tmpTableName+'.', '')+'`';\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// This doesn't work well but we'll try it.\n\t\t\t\treturn '`'+pColumn+'`';\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t* Generate a field list from the array of dataElements\n\t*\n\t* Each entry in the dataElements is a simple string\n\t*\n\t* @method: generateFieldList\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @param {Boolean} pIsForCountClause (optional) If true, generate fields for use within a count clause.\n\t* @return: {String} Returns the field list clause, or empty string if explicit fields are requested but cannot be fulfilled\n\t* due to missing schema.\n\t*/\n\tvar generateFieldList = function(pParameters, pIsForCountClause)\n\t{\n\t\tvar tmpDataElements = pParameters.dataElements;\n\t\tif (!Array.isArray(tmpDataElements) || tmpDataElements.length < 1)\n\t\t{\n\t\t\tif (!pIsForCountClause)\n\t\t\t{\n\t\t\t\treturn ' *';\n\t\t\t}\n\t\t\t// we need to list all of the table fields explicitly; get them from the schema\n\t\t\tconst tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\t\t\tif (tmpSchema.length < 1)\n\t\t\t{\n\t\t\t\t// this means we have no schema; returning an empty string here signals the calling code to handle this case\n\t\t\t\treturn '';\n\t\t\t}\n\t\t\tconst idColumn = tmpSchema.find((entry) => entry.Type === 'AutoIdentity');\n\t\t\tif (!idColumn)\n\t\t\t{\n\t\t\t\t// this means there is no autoincrementing unique ID column; treat as above\n\t\t\t\treturn '';\n\t\t\t}\n\t\t\treturn ` ${idColumn.Column}`;\n\t\t}\n\n\t\tvar tmpFieldList = ' ';\n\t\tfor (var i = 0; i < tmpDataElements.length; i++)\n\t\t{\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\ttmpFieldList += ', ';\n\t\t\t}\n\t\t\ttmpFieldList += escapeColumn(tmpDataElements[i], pParameters);\n\t\t}\n\t\treturn tmpFieldList;\n\t};\n\n\t/**\n\t* Generate a query from the array of where clauses\n\t*\n\t* Each clause is an object like:\n\t\t{\n\t\t\tColumn:'Name',\n\t\t\tOperator:'EQ',\n\t\t\tValue:'John',\n\t\t\tConnector:'And',\n\t\t\tParameter:'Name'\n\t\t}\n\t*\n\t* @method: generateWhere\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the WHERE clause prefixed with WHERE, or an empty string if unnecessary\n\t*/\n\tvar generateWhere = function(pParameters)\n\t{\n\t\tvar tmpFilter = Array.isArray(pParameters.filter) ? pParameters.filter : [];\n\t\tvar tmpTableName = generateTableName(pParameters).trim();\n\n\t\tif (!pParameters.query.disableDeleteTracking)\n\t\t{\n\t\t\t// Check if there is a Deleted column on the Schema. If so, we add this to the filters automatically (if not already present)\n\t\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\tvar tmpSchemaEntry = tmpSchema[i];\n\n\t\t\t\tif (tmpSchemaEntry.Type === 'Deleted')\n\t\t\t\t{\n\t\t\t\t\tvar tmpHasDeletedParameter = false;\n\n\t\t\t\t\t//first, check to see if filters are already looking for Deleted column\n\t\t\t\t\tif (tmpFilter.length > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (var x = 0; x < tmpFilter.length; x++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (tmpFilter[x].Column === tmpSchemaEntry.Column)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttmpHasDeletedParameter = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (!tmpHasDeletedParameter)\n\t\t\t\t\t{\n\t\t\t\t\t\t//if not, we need to add it\n\t\t\t\t\t\ttmpFilter.push(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tColumn: tmpTableName + '.' + tmpSchemaEntry.Column,\n\t\t\t\t\t\t\tOperator: '=',\n\t\t\t\t\t\t\tValue: 0,\n\t\t\t\t\t\t\tConnector: 'AND',\n\t\t\t\t\t\t\tParameter: 'Deleted'\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (tmpFilter.length < 1)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpWhere = ' WHERE';\n\n\t\t// This is used to disable the connectors for subsequent queries.\n\t\t// Only the open parenthesis operator uses this, currently.\n\t\tvar tmpLastOperatorNoConnector = false;\n\n\t\tfor (var i = 0; i < tmpFilter.length; i++)\n\t\t{\n\t\t\tif ((tmpFilter[i].Connector != 'NONE') && (tmpFilter[i].Operator != ')') && (tmpWhere != ' WHERE') && (tmpLastOperatorNoConnector == false))\n\t\t\t{\n\t\t\t\ttmpWhere += ' '+tmpFilter[i].Connector;\n\t\t\t}\n\n\t\t\ttmpLastOperatorNoConnector = false;\n\n\t\t\tvar tmpColumnParameter;\n\n\t\t\tif (tmpFilter[i].Operator === '(')\n\t\t\t{\n\t\t\t\t// Open a logical grouping\n\t\t\t\ttmpWhere += ' (';\n\t\t\t\ttmpLastOperatorNoConnector = true;\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === ')')\n\t\t\t{\n\t\t\t\t// Close a logical grouping\n\t\t\t\ttmpWhere += ' )';\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IN')\n\t\t\t{\n\t\t\t\ttmpColumnParameter = tmpFilter[i].Parameter+'_w'+i;\n\t\t\t\t// Add the column name, operator and parameter name to the list of where value parenthetical\n\t\t\t\ttmpWhere += ' '+escapeColumn(tmpFilter[i].Column, pParameters)+' '+tmpFilter[i].Operator+' ( :'+tmpColumnParameter+' )';\n\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = tmpFilter[i].Value;\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IS NOT NULL')\n\t\t\t{\n\t\t\t\t// IS NOT NULL is a special operator which doesn't require a value, or parameter\n\t\t\t\ttmpWhere += ' '+escapeColumn(tmpFilter[i].Column, pParameters)+' '+tmpFilter[i].Operator;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpColumnParameter = tmpFilter[i].Parameter+'_w'+i;\n\t\t\t\t// Add the column name, operator and parameter name to the list of where value parenthetical\n\t\t\t\ttmpWhere += ' '+escapeColumn(tmpFilter[i].Column, pParameters)+' '+tmpFilter[i].Operator+' :'+tmpColumnParameter;\n\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = tmpFilter[i].Value;\n\t\t\t}\n\t\t}\n\n\t\treturn tmpWhere;\n\t};\n\n\t/**\n\t* Generate an ORDER BY clause from the sort array\n\t*\n\t* Each entry in the sort is an object like:\n\t* {Column:'Color',Direction:'Descending'}\n\t*\n\t* @method: generateOrderBy\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the field list clause\n\t*/\n\tvar generateOrderBy = function(pParameters)\n\t{\n\t\tvar tmpOrderBy = pParameters.sort;\n\t\tif (!Array.isArray(tmpOrderBy) || tmpOrderBy.length < 1)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpOrderClause = ' ORDER BY';\n\t\tfor (var i = 0; i < tmpOrderBy.length; i++)\n\t\t{\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\ttmpOrderClause += ',';\n\t\t\t}\n\t\t\ttmpOrderClause += ' '+escapeColumn(tmpOrderBy[i].Column, pParameters);\n\n\t\t\tif (tmpOrderBy[i].Direction == 'Descending')\n\t\t\t{\n\t\t\t\ttmpOrderClause += ' DESC';\n\t\t\t}\n\t\t}\n\t\treturn tmpOrderClause;\n\t};\n\n\t/**\n\t* Generate the limit clause\n\t*\n\t* @method: generateLimit\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateLimit = function(pParameters)\n\t{\n\t\tif (!pParameters.cap)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpLimit = ' LIMIT';\n\t\t// Cap is required for a limit clause.\n\t\ttmpLimit += ' ' + pParameters.cap;\n\n\t\t// If there is a begin record, we'll pass that in as well.\n\t\tif (pParameters.begin !== false)\n\t\t{\n\t\t\ttmpLimit += ' FETCH ' + pParameters.begin;\n\t\t}\n\n\t\treturn tmpLimit;\n\t};\n\n\t/**\n\t* Generate the update SET clause\n\t*\n\t* @method: generateUpdateSetters\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateUpdateSetters = function(pParameters)\n\t{\n\t\tvar tmpRecords = pParameters.query.records;\n\t\t// We need to tell the query not to generate improperly if there are no values to set.\n\t\tif (!Array.isArray(tmpRecords) || tmpRecords.length < 1)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpUpdate = '';\n\t\t// If there is more than one record in records, we are going to ignore them for now.\n\t\tvar tmpCurrentColumn = 0;\n\t\tfor(var tmpColumn in tmpRecords[0])\n\t\t{\n\t\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\t\tvar tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\tif (tmpColumn == tmpSchema[i].Column)\n\t\t\t\t{\n\t\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\t\ttmpSchemaEntry = tmpSchema[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (pParameters.query.disableAutoDateStamp &&\n\t\t\t\ttmpSchemaEntry.Type === 'UpdateDate')\n\t\t\t{\n\t\t\t\t// This is ignored if flag is set\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (pParameters.query.disableAutoUserStamp &&\n\t\t\t\ttmpSchemaEntry.Type === 'UpdateIDUser')\n\t\t\t{\n\t\t\t\t// This is ignored if flag is set\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'AutoIdentity':\n\t\t\t\tcase 'CreateDate':\n\t\t\t\tcase 'CreateIDUser':\n\t\t\t\tcase 'DeleteDate':\n\t\t\t\tcase 'DeleteIDUser':\n\t\t\t\t\t// These are all ignored on update\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpUpdate += ',';\n\t\t\t}\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\ttmpUpdate += ' '+escapeColumn(tmpColumn, pParameters)+' = NOW()';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateIDUser':\n\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\tvar tmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdate += ' '+escapeColumn(tmpColumn, pParameters)+' = :'+tmpColumnParameter;\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tvar tmpColumnDefaultParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdate += ' '+escapeColumn(tmpColumn, pParameters)+' = :'+tmpColumnDefaultParameter;\n\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnDefaultParameter] = tmpRecords[0][tmpColumn];\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// We use a number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (tmpUpdate === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpUpdate;\n\t};\n\n\t/**\n\t* Generate the update-delete SET clause\n\t*\n\t* @method: generateUpdateDeleteSetters\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateUpdateDeleteSetters = function(pParameters)\n\t{\n\t\tif (pParameters.query.disableDeleteTracking)\n\t\t{\n\t\t\t//Don't generate an UPDATE query if Delete tracking is disabled\n\t\t\treturn false;\n\t\t}\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpCurrentColumn = 0;\n\t\tvar tmpHasDeletedField = false;\n\t\tvar tmpUpdate = '';\n\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\tvar tmpSchemaEntry = {Type:'Default'};\n\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t{\n\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\ttmpSchemaEntry = tmpSchema[i];\n\n\t\t\tvar tmpUpdateSql = null;\n\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'Deleted':\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = 1';\n\t\t\t\t\ttmpHasDeletedField = true; //this field is required in order for query to be built\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'DeleteDate':\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = NOW()';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\t\t// Delete operation is an Update, so we should stamp the update time\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = NOW()';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'DeleteIDUser':\n\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\tvar tmpColumnParameter = tmpSchemaEntry.Column+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = :'+tmpColumnParameter;\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t//DON'T allow update of other fields in this query\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpUpdate += ',';\n\t\t\t}\n\n\t\t\ttmpUpdate += tmpUpdateSql;\n\n\t\t\t// We use a number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (!tmpHasDeletedField ||\n\t\t\ttmpUpdate === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpUpdate;\n\t};\n\n\t/**\n\t* Generate the update-delete SET clause\n\t*\n\t* @method: generateUpdateDeleteSetters\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateUpdateUndeleteSetters = function(pParameters)\n\t{\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpCurrentColumn = 0;\n\t\tvar tmpHasDeletedField = false;\n\t\tvar tmpUpdate = '';\n\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\tvar tmpSchemaEntry = {Type:'Default'};\n\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t{\n\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\ttmpSchemaEntry = tmpSchema[i];\n\n\t\t\tvar tmpUpdateSql = null;\n\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'Deleted':\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = 0';\n\t\t\t\t\ttmpHasDeletedField = true; //this field is required in order for query to be built\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\t\t// Delete operation is an Update, so we should stamp the update time\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = NOW()';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateIDUser':\n\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\tvar tmpColumnParameter = tmpSchemaEntry.Column+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdateSql = ' '+escapeColumn(tmpSchemaEntry.Column, pParameters)+' = :'+tmpColumnParameter;\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t//DON'T allow update of other fields in this query\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpUpdate += ',';\n\t\t\t}\n\n\t\t\ttmpUpdate += tmpUpdateSql;\n\n\t\t\t// We use a number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (!tmpHasDeletedField ||\n\t\t\ttmpUpdate === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpUpdate;\n\t};\n\n\t/**\n\t* Generate the create SET clause\n\t*\n\t* @method: generateCreateSetList\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateCreateSetValues = function(pParameters)\n\t{\n\t\tvar tmpRecords = pParameters.query.records;\n\t\t// We need to tell the query not to generate improperly if there are no values to set.\n\t\tif (!Array.isArray(tmpRecords) || tmpRecords.length < 1)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\n\t\tvar tmpCreateSet = '';\n\t\t// If there is more than one record in records, we are going to ignore them for now.\n\t\tvar tmpCurrentColumn = 0;\n\t\tfor(var tmpColumn in tmpRecords[0])\n\t\t{\n\t\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\t\tvar tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\tif (tmpColumn == tmpSchema[i].Column)\n\t\t\t\t{\n\t\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\t\ttmpSchemaEntry = tmpSchema[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!pParameters.query.disableDeleteTracking)\n\t\t\t{\n\t\t\t\tif (tmpSchemaEntry.Type === 'DeleteDate' ||\n\t\t\t\t\ttmpSchemaEntry.Type === 'DeleteIDUser')\n\t\t\t\t{\n\t\t\t\t\t// These are all ignored on insert (if delete tracking is enabled as normal)\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpCreateSet += ',';\n\t\t\t}\n\n\t\t\t//define a re-usable method for setting up field definitions in a default pattern\n\t\t\tvar buildDefaultDefinition = function()\n\t\t\t{\n\t\t\t\tvar tmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\ttmpCreateSet += ' :'+tmpColumnParameter;\n\t\t\t\t// Set the query parameter\n\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = tmpRecords[0][tmpColumn];\n\t\t\t};\n\n\t\t\tvar tmpColumnParameter;\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'AutoIdentity':\n\t\t\t\t\tif (pParameters.query.disableAutoIdentity)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\t\ttmpCreateSet += ' NULL';\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'AutoGUID':\n\t\t\t\t\tif (pParameters.query.disableAutoIdentity)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse if (tmpRecords[0][tmpColumn] &&\n\t\t\t\t\t\t\ttmpRecords[0][tmpColumn].length >= 5 &&\n\t\t\t\t\t\t\ttmpRecords[0][tmpColumn] !== '0x0000000000000000') //stricture default\n\t\t\t\t\t{\n\t\t\t\t\t\t// Allow consumer to override AutoGUID\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\t\ttmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\t\ttmpCreateSet += ' :'+tmpColumnParameter;\n\t\t\t\t\t\t// Set the query parameter\n\t\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.UUID;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\tcase 'CreateDate':\n\t\t\t\tcase 'DeleteDate':\n\t\t\t\t\tif (pParameters.query.disableAutoDateStamp)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\t\ttmpCreateSet += ' NOW()';\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateIDUser':\n\t\t\t\tcase 'CreateIDUser':\n\t\t\t\tcase 'DeleteIDUser':\n\t\t\t\t\tif (pParameters.query.disableAutoUserStamp)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\t\ttmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\t\ttmpCreateSet += ' :'+tmpColumnParameter;\n\t\t\t\t\t\t// Set the query parameter\n\t\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// We use an appended number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (tmpCreateSet === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpCreateSet;\n\t};\n\n\t/**\n\t* Generate the create SET clause\n\t*\n\t* @method: generateCreateSetList\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateCreateSetList = function(pParameters)\n\t{\n\t\t// The records were already validated by generateCreateSetValues\n\t\tvar tmpRecords = pParameters.query.records;\n\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpCreateSet = '';\n\t\t// If there is more than one record in records, we are going to ignore them for now.\n\t\tfor(var tmpColumn in tmpRecords[0])\n\t\t{\n\t\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\t\tvar tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\tif (tmpColumn == tmpSchema[i].Column)\n\t\t\t\t{\n\t\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\t\ttmpSchemaEntry = tmpSchema[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!pParameters.query.disableDeleteTracking)\n\t\t\t{\n\t\t\t\tif (tmpSchemaEntry.Type === 'DeleteDate' ||\n\t\t\t\t\ttmpSchemaEntry.Type === 'DeleteIDUser')\n\t\t\t\t{\n\t\t\t\t\t// These are all ignored on insert (if delete tracking is enabled as normal)\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tdefault:\n\t\t\t\t\tif (tmpCreateSet != '')\n\t\t\t\t\t{\n\t\t\t\t\t\ttmpCreateSet += ',';\n\t\t\t\t\t}\n\t\t\t\t\ttmpCreateSet += ' '+escapeColumn(tmpColumn, pParameters);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn tmpCreateSet;\n\t};\n\n\n\tvar Create = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpCreateSetList = generateCreateSetList(pParameters);\n\t\tvar tmpCreateSetValues = generateCreateSetValues(pParameters);\n\n\t\tif (!tmpCreateSetValues)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn 'INSERT INTO'+tmpTableName+' ('+tmpCreateSetList+') VALUES ('+tmpCreateSetValues+');';\n\t};\n\n\n\t/**\n\t* Read one or many records\n\t*\n\t* Some examples:\n\t* SELECT * FROM WIDGETS;\n\t* SELECT * FROM WIDGETS LIMIT 0, 20;\n\t* SELECT * FROM WIDGETS LIMIT 5, 20;\n\t* SELECT ID, Name, Cost FROM WIDGETS LIMIT 5, 20;\n\t* SELECT ID, Name, Cost FROM WIDGETS LIMIT 5, 20 WHERE LastName = 'Smith';\n\t*\n\t* @method Read\n\t* @param {Object} pParameters SQL Query parameters\n\t* @return {String} Returns the current Query for chaining.\n\t*/\n\tvar Read = function(pParameters)\n\t{\n\t\tvar tmpFieldList = generateFieldList(pParameters);\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpOrderBy = generateOrderBy(pParameters);\n\t\tvar tmpLimit = generateLimit(pParameters);\n\t\tconst tmpOptDistinct = pParameters.distinct ? ' DISTINCT' : '';\n\n\t\tif (pParameters.queryOverride)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tvar tmpQueryTemplate = _Fable.Utility.template(pParameters.queryOverride);\n\t\t\t\treturn tmpQueryTemplate({FieldList:tmpFieldList, TableName:tmpTableName, Where:tmpWhere, OrderBy:tmpOrderBy, Limit:tmpLimit, Distinct: tmpOptDistinct, _Params: pParameters});\n\t\t\t}\n\t\t\tcatch (pError)\n\t\t\t{\n\t\t\t\t// This pokemon is here to give us a convenient way of not throwing up totally if the query fails.\n\t\t\t\tconsole.log('Error with custom Read Query ['+pParameters.queryOverride+']: '+pError);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn `SELECT${tmpOptDistinct}${tmpFieldList} FROM${tmpTableName}${tmpWhere}${tmpOrderBy}${tmpLimit};`;\n\t};\n\n\tvar Update = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpUpdateSetters = generateUpdateSetters(pParameters);\n\n\t\tif (!tmpUpdateSetters)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn 'UPDATE'+tmpTableName+' SET'+tmpUpdateSetters+tmpWhere+';';\n\t};\n\n\tvar Delete = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpUpdateDeleteSetters = generateUpdateDeleteSetters(pParameters);\n\n\t\tif (tmpUpdateDeleteSetters)\n\t\t{\n\t\t\t//If it has a deleted bit, update it instead of actually deleting the record\n\t\t\treturn 'UPDATE'+tmpTableName+' SET'+tmpUpdateDeleteSetters+tmpWhere+';';\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn 'DELETE FROM'+tmpTableName+tmpWhere+';';\n\t\t}\n\t};\n\n\tvar Undelete = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tlet tmpDeleteTrackingState = pParameters.query.disableDeleteTracking;\n\t\tpParameters.query.disableDeleteTracking = true;\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpUpdateUndeleteSetters = generateUpdateUndeleteSetters(pParameters);\n\t\tpParameters.query.disableDeleteTracking = tmpDeleteTrackingState;\n\n\t\tif (tmpUpdateUndeleteSetters)\n\t\t{\n\t\t\t//If it has a deleted bit, update it instead of actually deleting the record\n\t\t\treturn 'UPDATE'+tmpTableName+' SET'+tmpUpdateUndeleteSetters+tmpWhere+';';\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn 'SELECT NULL;';\n\t\t}\n\t};\n\n\tvar Count = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tconst tmpFieldList = pParameters.distinct ? generateFieldList(pParameters, true) : '*';\n\n\t\t// here, we ignore the distinct keyword if no fields have been specified and\n\t\tif (pParameters.distinct && tmpFieldList.length < 1)\n\t\t{\n\t\t\tconsole.warn('Distinct requested but no field list or schema are available, so not honoring distinct for count query.');\n\t\t}\n\t\tconst tmpOptDistinct = pParameters.distinct && tmpFieldList.length > 0 ? 'DISTINCT' : '';\n\t\tif (pParameters.queryOverride)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tvar tmpQueryTemplate = _Fable.Utility.template(pParameters.queryOverride);\n\t\t\t\treturn tmpQueryTemplate({FieldList:[], TableName:tmpTableName, Where:tmpWhere, OrderBy:'', Limit:'', Distinct: tmpOptDistinct, _Params: pParameters});\n\t\t\t}\n\t\t\tcatch (pError)\n\t\t\t{\n\t\t\t\t// This pokemon is here to give us a convenient way of not throwing up totally if the query fails.\n\t\t\t\tconsole.log('Error with custom Count Query ['+pParameters.queryOverride+']: '+pError);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn `SELECT COUNT(${tmpOptDistinct}${tmpFieldList || '*'}) AS RowCount FROM${tmpTableName}${tmpWhere};`;\n\t};\n\n\tvar tmpDialect = ({\n\t\tCreate: Create,\n\t\tRead: Read,\n\t\tUpdate: Update,\n\t\tDelete: Delete,\n\t\tUndelete: Undelete,\n\t\tCount: Count\n\t});\n\n\t/**\n\t* Dialect Name\n\t*\n\t* @property name\n\t* @type string\n\t*/\n\tObject.defineProperty(tmpDialect, 'name',\n\t\t{\n\t\t\tget: function() { return 'ALASQL'; },\n\t\t\tenumerable: true\n\t\t});\n\n\treturn tmpDialect;\n};\n\nmodule.exports = FoxHoundDialectALASQL;\n","/**\n* FoxHound English Dialect\n*\n* Because if I can't ask for it in my native tongue, how am I going to ask a\n* complicated server for it?\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n* @class FoxHoundDialectEnglish\n*/\nvar FoxHoundDialectEnglish = function()\n{\n\tvar Create = function(pParameters)\n\t{\n\t\tvar tmpScope = pParameters.scope;\n\n\t\treturn 'Here is a '+tmpScope+'.';\n\t};\n\n\t/**\n\t* Read one or many records\n\t*\n\t* Some examples:\n\t* Please give me all your Widget records. Thanks.\n\t* Please give me 20 Widget records. Thanks.\n\t* Please give me 20 Widget records starting with record 5. Thanks.\n\t* Please give me the ID, Name and Cost of 20 Widget records starting with record 5. Thanks.\n\t* Please give me the ID and Name of 20 Widget records starting with record 5, when LastName equals \"Smith\". Thanks.\n\t*\n\t* @method Read\n\t* @param {Number} pLogLevel The log level for our object\n\t* @return {String} Returns the current Query for chaining.\n\t*/\n\tvar Read = function(pParameters)\n\t{\n\t\tvar tmpScope = pParameters.scope;\n\t\tconst tmpDistinct = pParameters.distinct ? 'unique ' : '';\n\n\t\treturn `Please give me all your ${tmpDistinct}${tmpScope} records. Thanks.`;\n\t};\n\n\tvar Update = function(pParameters)\n\t{\n\t\tvar tmpScope = pParameters.scope;\n\n\t\treturn 'I am changing your '+tmpScope+'.';\n\t};\n\n\tvar Delete = function(pParameters)\n\t{\n\t\tvar tmpScope = pParameters.scope;\n\n\t\treturn 'I am deleting your '+tmpScope+'.';\n\t};\n\n\tvar Undelete = function(pParameters)\n\t{\n\t\tvar tmpScope = pParameters.scope;\n\n\t\treturn 'I am undeleting your '+tmpScope+'.';\n\t};\n\n\tvar Count = function(pParameters)\n\t{\n\t\tvar tmpScope = pParameters.scope;\n\t\tconst tmpDistinct = pParameters.distinct ? 'unique ' : '';\n\n\t\treturn `Count your ${tmpDistinct}${tmpScope}.`;\n\t};\n\n\tvar tmpDialect = ({\n\t\tCreate: Create,\n\t\tRead: Read,\n\t\tUpdate: Update,\n\t\tDelete: Delete,\n\t\tUndelete: Undelete,\n\t\tCount: Count\n\t});\n\n\t/**\n\t * Dialect Name\n\t *\n\t * @property name\n\t * @type string\n\t */\n\tObject.defineProperty(tmpDialect, 'name',\n\t\t{\n\t\t\tget: function() { return 'English'; },\n\t\t\tenumerable: true\n\t\t});\n\n\treturn tmpDialect;\n};\n\nmodule.exports = FoxHoundDialectEnglish;\n","/**\n* FoxHound Meadow Endpoints Dialect\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n* @class FoxHoundDialectMeadowEndpoints\n*/\n\nvar FoxHoundDialectMeadowEndpoints = function()\n{\n\t/**\n\t * Generate a table name from the scope\n\t *\n\t * @method: generateTableName\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Returns the table name clause\n\t */\n\tvar generateTableName = function(pParameters)\n\t{\n\t\treturn pParameters.scope;\n\t};\n\n\t/**\n\t * Generate the Identity column from the schema or scope\n\t * \n\t * @method: generateIdentityColumnName\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Returns the table name clause\n\t */\n\tvar generateIdentityColumnName = function(pParameters)\n\t{\n\t\t// TODO: See about using the Schema or the Schemata for this\n\t\treturn `ID${pParameters.scope}`;\n\t};\n\n\t/**\n\t * Generate a field list from the array of dataElements\n\t *\n\t * Each entry in the dataElements is a simple string\n\t *\n\t * @method: generateFieldList\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Returns the field list clause\n\t */\n\tvar generateFieldList = function(pParameters)\n\t{\n\t\tvar tmpDataElements = pParameters.dataElements;\n\t\tif (!Array.isArray(tmpDataElements) || tmpDataElements.length < 1)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpFieldList = '';\n\t\tfor (var i = 0; i < tmpDataElements.length; i++)\n\t\t{\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\ttmpFieldList += ',';\n\t\t\t}\n\n tmpFieldList += tmpDataElements[i];\n\t\t}\n\t\treturn tmpFieldList;\n\t};\n\n\t/**\n\t * Generate a query from the array of where clauses\n\t *\n\t * Each clause is an object like:\n\t\t{\n\t\t\tColumn:'Name', \n\t\t\tOperator:'EQ', \n\t\t\tValue:'John', \n\t\t\tConnector:'And', \n\t\t\tParameter:'Name'\n\t\t}\n\t *\n\t * @method: generateWhere\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Returns the WHERE clause prefixed with WHERE, or an empty string if unnecessary\n\t */\n\tvar generateWhere = function(pParameters)\n\t{\n\t\tvar tmpFilter = Array.isArray(pParameters.filter) ? pParameters.filter : [];\n\t\tvar tmpTableName = generateTableName(pParameters);\n \n var tmpURL = '';\n\n let tmpfAddFilter = (pFilterCommand, pFilterParameters) =>\n {\n if (tmpURL.length > 0)\n {\n tmpURL += '~';\n }\n \n tmpURL += `${pFilterCommand}~${pFilterParameters[0]}~${pFilterParameters[1]}~${pFilterParameters[2]}`;\n };\n\n let tmpfTranslateOperator = (pOperator) =>\n {\n tmpNewOperator = 'EQ';\n switch(pOperator.toUpperCase())\n {\n case '!=':\n tmpNewOperator = 'NE';\n break;\n case '>':\n tmpNewOperator = 'GT';\n break;\n case '>=':\n tmpNewOperator = 'GE';\n break;\n case '<=':\n tmpNewOperator = 'LE';\n break;\n case '<':\n tmpNewOperator = 'LT';\n break;\n case 'LIKE':\n tmpNewOperator = 'LK';\n break;\n case 'IN':\n tmpNewOperator = 'INN';\n break;\n case 'NOT IN':\n tmpNewOperator = 'NI';\n break;\n }\n return tmpNewOperator;\n }\n\n // Translating Delete Tracking bit on query to a query with automagic\n // This will eventually deprecate this as part of the necessary query\n if (pParameters.query.disableDeleteTracking)\n {\n tmpfAddFilter('FBV',['Deleted','GE','0'])\n }\n\n\t\tfor (var i = 0; i < tmpFilter.length; i++)\n\t\t{\n\t\t\tif (tmpFilter[i].Operator === '(')\n\t\t\t{\n tmpfAddFilter('FOP',['0','(','0']);\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === ')')\n\t\t\t{\n\t\t\t\t// Close a logical grouping\n tmpfAddFilter('FCP',['0',')','0']);\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IN' || tmpFilter[i].Operator === \"NOT IN\")\n\t\t\t{\n let tmpFilterCommand = 'FBV';\n if (tmpFilter[i].Connector == 'OR')\n {\n tmpFilterCommand = 'FBVOR';\n }\n\t\t\t\t// Add the column name, operator and parameter name to the list of where value parenthetical\n tmpfAddFilter(tmpFilterCommand, [tmpFilter[i].Column, tmpfTranslateOperator(tmpFilter[i].Operator), tmpFilter[i].Value.map(encodeURIComponent).join(',')])\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IS NULL')\n\t\t\t{\n\t\t\t\t// IS NULL is a special operator which doesn't require a value, or parameter\n tmpfAddFilter('FBV', [tmpFilter[i].Column, 'IN', '0']);\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IS NOT NULL')\n\t\t\t{\n\t\t\t\t// IS NOT NULL is a special operator which doesn't require a value, or parameter\n tmpfAddFilter('FBV', [tmpFilter[i].Column, 'NN', '0']);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n let tmpFilterCommand = 'FBV';\n if (tmpFilter[i].Connector == 'OR')\n {\n tmpFilterCommand = 'FBVOR';\n }\n\t\t\t\t// Add the column name, operator and parameter name to the list of where value parenthetical\n tmpfAddFilter(tmpFilterCommand, [tmpFilter[i].Column, tmpfTranslateOperator(tmpFilter[i].Operator), encodeURIComponent(tmpFilter[i].Value)]);\n\t\t\t}\n\t\t}\n\n let tmpOrderBy = generateOrderBy(pParameters);\n if (tmpOrderBy)\n {\n if (tmpURL)\n {\n tmpURL += '~';\n }\n tmpURL += tmpOrderBy;\n }\n\n\t\treturn tmpURL;\n\t};\n\n /**\n\t * Get the flags for the request\n * \n * These are usually passed in for Update and Create when extra tracking is disabled.\n\t *\n\t * @method: generateFlags\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Flags to be sent, if any.\n\t */\n function generateFlags(pParameters)\n {\n let tmpDisableAutoDateStamp = pParameters.query.disableAutoDateStamp;\n let tmpDisableDeleteTracking = pParameters.query.disableDeleteTracking;\n let tmpDisableAutoIdentity = pParameters.query.disableAutoIdentity;\n let tmpDisableAutoUserStamp = pParameters.query.disableAutoUserStamp;\n\n let tmpFlags = '';\n\n let fAddFlag = (pFlagSet, pFlag) =>\n {\n if (pFlagSet)\n {\n if (tmpFlags.length > 0)\n {\n tmpFlags += ',';\n }\n tmpFlags += pFlag;\n }\n };\n\n fAddFlag(tmpDisableAutoDateStamp, 'DisableAutoDateStamp');\n fAddFlag(tmpDisableDeleteTracking, 'DisableDeleteTracking');\n fAddFlag(tmpDisableAutoIdentity, 'DisableAutoIdentity');\n fAddFlag(tmpDisableAutoUserStamp, 'DisableAutoUserStamp');\n\n return tmpFlags;\n };\n\n /**\n\t * Get the ID for the record, to be used in URIs\n\t *\n\t * @method: getIDRecord\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} ID of the record in string form for the URI\n\t */\n\tvar getIDRecord = function(pParameters)\n\t{\n var tmpFilter = Array.isArray(pParameters.filter) ? pParameters.filter : [];\n\n\t\tvar tmpIDRecord = false;\n\n if (tmpFilter.length < 1)\n\t\t{\n\t\t\treturn tmpIDRecord;\n\t\t}\n\n\t\tfor (var i = 0; i < tmpFilter.length; i++)\n\t\t{\n // Check Schema Entry Type\n var tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\t\t\tvar tmpSchemaEntry = {Column:tmpFilter[i].Column, Type:'Default'};\n\t\t\tfor (var j = 0; j < tmpSchema.length; j++)\n\t\t\t{\n // If this column is the AutoIdentity, set it.\n\t\t\t\tif ((tmpFilter[i].Column == tmpSchema[j].Column) &&\n (tmpSchema[j].Type == 'AutoIdentity'))\n\t\t\t\t{\n tmpIDRecord = tmpFilter[i].Value;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn tmpIDRecord;\n }\n\t\n /**\n\t * Generate an ORDER BY clause from the sort array\n\t *\n\t * Each entry in the sort is an object like:\n\t * {Column:'Color',Direction:'Descending'}\n\t *\n\t * @method: generateOrderBy\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Returns the field list clause\n\t */\n\tvar generateOrderBy = function(pParameters)\n\t{\n\t\tvar tmpOrderBy = pParameters.sort;\n\t\tvar tmpOrderClause = false;\n\n if (!Array.isArray(tmpOrderBy) || tmpOrderBy.length < 1)\n\t\t{\n\t\t\treturn tmpOrderClause;\n\t\t}\n\n tmpOrderClause = '';\n\n for (var i = 0; i < tmpOrderBy.length; i++)\n\t\t{\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\ttmpOrderClause += '~';\n\t\t\t}\n\t\t\ttmpOrderClause += `FSF~${tmpOrderBy[i].Column}~`;\n\n\t\t\tif (tmpOrderBy[i].Direction == 'Descending')\n\t\t\t{\n\t\t\t\ttmpOrderClause += 'DESC~0';\n\t\t\t}\n else\n {\n tmpOrderClause += 'ASC~0'\n }\n\t\t}\n\t\treturn tmpOrderClause;\n\t};\n\n\t/**\n\t * Generate the limit clause\n\t *\n\t * @method: generateLimit\n\t * @param: {Object} pParameters SQL Query Parameters\n\t * @return: {String} Returns the table name clause\n\t */\n\tvar generateLimit = function(pParameters)\n\t{\n\t\tif (!pParameters.cap)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n let tmpBegin = (pParameters.begin !== false) ? pParameters.begin : 0;\n\n return `${tmpBegin}/${pParameters.cap}`;\n\t};\n\n\tvar Create = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n var tmpFlags = generateFlags(pParameters);\n\n if (tmpTableName)\n {\n let tmpURL = tmpTableName;\n if (tmpFlags)\n {\n tmpURL = `${tmpURL}/WithFlags/${tmpFlags}`\n }\n return tmpURL;\n }\n else\n {\n return false;\n }\n\t};\n\n\n\t/**\n\t* Read one or many records\n\t*\n\t* @method Read\n\t* @param {Object} pParameters SQL Query parameters\n\t* @return {String} Returns the current Query for chaining.\n\t*/\n\tvar Read = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpFieldList = generateFieldList(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpLimit = generateLimit(pParameters);\n\n\t\tvar tmpURL = `${tmpTableName}`;\n\t\t// In the case that there is only a single query parameter, and the parameter is a single identity, \n\t\t// we will cast it to the READ endpoint rather than READS.\n\t\tif ((pParameters.filter)\n\t\t\t && (pParameters.filter.length == 1)\n // If there is exactly one query filter parameter\n\t\t\t && (pParameters.filter[0].Column === generateIdentityColumnName(pParameters))\n\t\t\t // AND It is the Identity column\n\t\t\t && (pParameters.filter[0].Operator === '=')\n\t\t\t // AND The comparators is a simple equals \n\t\t\t && (tmpLimit == '') && (tmpFieldList == '')\n\t\t\t // AND There is no limit or field list set\n\t\t\t && (!pParameters.sort))\n\t\t\t // AND There is no sort clause\n\t\t{\n\t\t\t// THEN This is a SINGLE READ by presumption.\n\t\t\t// There are some bad side affects this could cause with chaining and overridden behaviors, if \n\t\t\t// we are requesting a filtered list of 1 record.\n\t\t\ttmpURL = `${tmpURL}/${pParameters.filter[0].Value}`;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttmpURL = `${tmpURL}s`;\n\t\t\tif (tmpFieldList)\n\t\t\t{\n\t\t\t\ttmpURL = `${tmpURL}/LiteExtended/${tmpFieldList}`\n\t\t\t}\n\t\t\tif (tmpWhere)\n\t\t\t{\n\t\t\t\ttmpURL = `${tmpURL}/FilteredTo/${tmpWhere}`;\n\t\t\t}\n\t\t\tif (tmpLimit)\n\t\t\t{\n\t\t\t\ttmpURL = `${tmpURL}/${tmpLimit}`;\n\t\t\t}\n\t\t}\n\n\t\treturn tmpURL;\n\t};\n\n\tvar Update = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n var tmpFlags = generateFlags(pParameters);\n\n if (tmpTableName)\n {\n let tmpURL = tmpTableName;\n if (tmpFlags)\n {\n tmpURL = `${tmpURL}/WithFlags/${tmpFlags}`\n }\n return tmpURL;\n }\n else\n {\n return false;\n }\n\t};\n\n\tvar Delete = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpIDRecord = getIDRecord(pParameters);\n\n if (!tmpIDRecord)\n {\n return false;\n }\n\n\t\treturn `${tmpTableName}/${tmpIDRecord}`;\n\t};\n\n\tvar Count = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\n let tmpCountQuery = `${tmpTableName}s/Count`;\n\n if (tmpWhere)\n {\n return `${tmpTableName}s/Count/FilteredTo/${tmpWhere}`;\n }\n\n return tmpCountQuery;\n\t};\n\n\tvar tmpDialect = ({\n\t\tCreate: Create,\n\t\tRead: Read,\n\t\tUpdate: Update,\n\t\tDelete: Delete,\n\t\tCount: Count\n\t});\n\n\t/**\n\t * Dialect Name\n\t *\n\t * @property name\n\t * @type string\n\t */\n\tObject.defineProperty(tmpDialect, 'name',\n\t\t{\n\t\t\tget: function() { return 'MeadowEndpoints'; },\n\t\t\tenumerable: true\n\t\t});\n\n\treturn tmpDialect;\n};\n\nmodule.exports = FoxHoundDialectMeadowEndpoints;\n","/**\n* FoxHound MySQL Dialect\n*\n* @license MIT\n*\n* For a MySQL query override:\n// An underscore template with the following values:\n// <%= DataElements %> = Field1, Field2, Field3, Field4\n// <%= Begin %> = 0\n// <%= Cap %> = 10\n// <%= Filter %> = WHERE StartDate > :MyStartDate\n// <%= Sort %> = ORDER BY Field1\n// The values are empty strings if they aren't set.\n*\n* @author Steven Velozo <steven@velozo.com>\n* @class FoxHoundDialectMySQL\n*/\n\nvar FoxHoundDialectMySQL = function(pFable)\n{\n\t//Request time from SQL server with microseconds resolution\n\tconst SQL_NOW = \"NOW(3)\";\n\n\t_Fable = pFable;\n\n\t/**\n\t* Generate a table name from the scope\n\t*\n\t* @method: generateTableName\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateTableName = function(pParameters)\n\t{\n\t\tif (pParameters.scope && pParameters.scope.indexOf('`') >= 0)\n\t\t\treturn ' '+pParameters.scope+'';\n\t\telse\n\t\t\treturn ' `'+pParameters.scope+'`';\n\t};\n\n\t/**\n\t* Generate a field list from the array of dataElements\n\t*\n\t* Each entry in the dataElements is a simple string\n\t*\n\t* @method: generateFieldList\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @param {Boolean} pIsForCountClause (optional) If true, generate fields for use within a count clause.\n\t* @return: {String} Returns the field list clause, or empty string if explicit fields are requested but cannot be fulfilled\n\t* due to missing schema.\n\t*/\n\tvar generateFieldList = function(pParameters, pIsForCountClause)\n\t{\n\t\tvar tmpDataElements = pParameters.dataElements;\n\t\tif (!Array.isArray(tmpDataElements) || tmpDataElements.length < 1)\n\t\t{\n\t\t\tconst tmpTableName = generateTableName(pParameters);\n\t\t\tif (!pIsForCountClause)\n\t\t\t{\n\t\t\t\treturn tmpTableName + '.*';\n\t\t\t}\n\t\t\t// we need to list all of the table fields explicitly; get them from the schema\n\t\t\tconst tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\t\t\tif (tmpSchema.length < 1)\n\t\t\t{\n\t\t\t\t// this means we have no schema; returning an empty string here signals the calling code to handle this case\n\t\t\t\treturn '';\n\t\t\t}\n\t\t\tconst idColumn = tmpSchema.find((entry) => entry.Type === 'AutoIdentity');\n\t\t\tif (!idColumn)\n\t\t\t{\n\t\t\t\t// this means there is no autoincrementing unique ID column; treat as above\n\t\t\t\treturn '';\n\t\t\t}\n\t\t\tconst qualifiedIDColumn = `${tmpTableName}.${idColumn.Column}`;\n\t\t\treturn ` ${generateSafeFieldName(qualifiedIDColumn)}`;\n\t\t}\n\n\t\tvar tmpFieldList = ' ';\n\t\tfor (var i = 0; i < tmpDataElements.length; i++)\n\t\t{\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\ttmpFieldList += ', ';\n\t\t\t}\n\t\t\tif (Array.isArray(tmpDataElements[i]))\n\t\t\t{\n\t\t\t\ttmpFieldList += generateSafeFieldName(tmpDataElements[i][0]);\n\t\t\t\tif (tmpDataElements[i].length > 1 && tmpDataElements[i][1])\n\t\t\t\t{\n\t\t\t\t\ttmpFieldList += \" AS \" + generateSafeFieldName(tmpDataElements[i][1]);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpFieldList += generateSafeFieldName(tmpDataElements[i]);\n\t\t\t}\n\t\t}\n\t\treturn tmpFieldList;\n\t};\n\n\tconst SURROUNDING_QUOTES_AND_WHITESPACE_REGEX = /^[` ]+|[` ]+$/g;\n\n\tconst cleanseQuoting = (str) =>\n\t{\n\t\treturn str.replace(SURROUNDING_QUOTES_AND_WHITESPACE_REGEX, '');\n\t};\n\n\t/**\n\t* Ensure a field name is properly escaped.\n\t*/\n\tvar generateSafeFieldName = function(pFieldName)\n\t{\n\t\tlet pFieldNames = pFieldName.split('.');\n\t\tif (pFieldNames.length > 1)\n\t\t{\n\t\t\tconst cleansedFieldName = cleanseQuoting(pFieldNames[1]);\n\t\t\tif (cleansedFieldName === '*')\n\t\t\t{\n\t\t\t\t// do not put * as `*`\n\t\t\t\treturn \"`\" + cleanseQuoting(pFieldNames[0]) + \"`.*\";\n\t\t\t}\n\t\t\treturn \"`\" + cleanseQuoting(pFieldNames[0]) + \"`.`\" + cleansedFieldName + \"`\";\n\t\t}\n\t\tconst cleansedFieldName = cleanseQuoting(pFieldNames[0]);\n\t\tif (cleansedFieldName === '*')\n\t\t{\n\t\t\t// do not put * as `*`\n\t\t\treturn '*';\n\t\t}\n\t\treturn \"`\" + cleanseQuoting(pFieldNames[0]) + \"`\";\n\t}\n\n\t/**\n\t* Generate a query from the array of where clauses\n\t*\n\t* Each clause is an object like:\n\t\t{\n\t\t\tColumn:'Name',\n\t\t\tOperator:'EQ',\n\t\t\tValue:'John',\n\t\t\tConnector:'And',\n\t\t\tParameter:'Name'\n\t\t}\n\t*\n\t* @method: generateWhere\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the WHERE clause prefixed with WHERE, or an empty string if unnecessary\n\t*/\n\tvar generateWhere = function(pParameters)\n\t{\n\t\tvar tmpFilter = Array.isArray(pParameters.filter) ? pParameters.filter : [];\n\t\tvar tmpTableName = generateTableName(pParameters);\n\n\t\tif (!pParameters.query.disableDeleteTracking)\n\t\t{\n\t\t\t// Check if there is a Deleted column on the Schema. If so, we add this to the filters automatically (if not already present)\n\t\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\tvar tmpSchemaEntry = tmpSchema[i];\n\n\t\t\t\tif (tmpSchemaEntry.Type === 'Deleted')\n\t\t\t\t{\n\t\t\t\t\tvar tmpHasDeletedParameter = false;\n\n\t\t\t\t\t//first, check to see if filters are already looking for Deleted column\n\t\t\t\t\tif (tmpFilter.length > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (var x = 0; x < tmpFilter.length; x++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (tmpFilter[x].Column === tmpSchemaEntry.Column)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttmpHasDeletedParameter = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (!tmpHasDeletedParameter)\n\t\t\t\t\t{\n\t\t\t\t\t\t//if not, we need to add it\n\t\t\t\t\t\ttmpFilter.push(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tColumn: tmpTableName + '.' + tmpSchemaEntry.Column,\n\t\t\t\t\t\t\tOperator: '=',\n\t\t\t\t\t\t\tValue: 0,\n\t\t\t\t\t\t\tConnector: 'AND',\n\t\t\t\t\t\t\tParameter: 'Deleted'\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (tmpFilter.length < 1)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpWhere = ' WHERE';\n\n\t\t// This is used to disable the connectors for subsequent queries.\n\t\t// Only the open parenthesis operator uses this, currently.\n\t\tvar tmpLastOperatorNoConnector = false;\n\n\t\tfor (var i = 0; i < tmpFilter.length; i++)\n\t\t{\n\t\t\tif ((tmpFilter[i].Connector != 'NONE') && (tmpFilter[i].Operator != ')') && (tmpWhere != ' WHERE') && (tmpLastOperatorNoConnector == false))\n\t\t\t{\n\t\t\t\ttmpWhere += ' '+tmpFilter[i].Connector;\n\t\t\t}\n\n\t\t\ttmpLastOperatorNoConnector = false;\n\n\t\t\tvar tmpColumnParameter;\n\n\t\t\tif (tmpFilter[i].Operator === '(')\n\t\t\t{\n\t\t\t\t// Open a logical grouping\n\t\t\t\ttmpWhere += ' (';\n\t\t\t\ttmpLastOperatorNoConnector = true;\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === ')')\n\t\t\t{\n\t\t\t\t// Close a logical grouping\n\t\t\t\ttmpWhere += ' )';\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IN' || tmpFilter[i].Operator === \"NOT IN\")\n\t\t\t{\n\t\t\t\ttmpColumnParameter = tmpFilter[i].Parameter+'_w'+i;\n\t\t\t\t// Add the column name, operator and parameter name to the list of where value parenthetical\n\t\t\t\ttmpWhere += ' '+tmpFilter[i].Column+' '+tmpFilter[i].Operator+' ( :'+tmpColumnParameter+' )';\n\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = tmpFilter[i].Value;\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IS NULL')\n\t\t\t{\n\t\t\t\t// IS NULL is a special operator which doesn't require a value, or parameter\n\t\t\t\ttmpWhere += ' '+tmpFilter[i].Column+' '+tmpFilter[i].Operator;\n\t\t\t}\n\t\t\telse if (tmpFilter[i].Operator === 'IS NOT NULL')\n\t\t\t{\n\t\t\t\t// IS NOT NULL is a special operator which doesn't require a value, or parameter\n\t\t\t\ttmpWhere += ' '+tmpFilter[i].Column+' '+tmpFilter[i].Operator;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmpColumnParameter = tmpFilter[i].Parameter+'_w'+i;\n\t\t\t\t// Add the column name, operator and parameter name to the list of where value parenthetical\n\t\t\t\ttmpWhere += ' '+tmpFilter[i].Column+' '+tmpFilter[i].Operator+' :'+tmpColumnParameter;\n\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = tmpFilter[i].Value;\n\t\t\t}\n\t\t}\n\n\t\treturn tmpWhere;\n\t};\n\n\t/**\n\t* Generate an ORDER BY clause from the sort array\n\t*\n\t* Each entry in the sort is an object like:\n\t* {Column:'Color',Direction:'Descending'}\n\t*\n\t* @method: generateOrderBy\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the field list clause\n\t*/\n\tvar generateOrderBy = function(pParameters)\n\t{\n\t\tvar tmpOrderBy = pParameters.sort;\n\t\tif (!Array.isArray(tmpOrderBy) || tmpOrderBy.length < 1)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpOrderClause = ' ORDER BY';\n\t\tfor (var i = 0; i < tmpOrderBy.length; i++)\n\t\t{\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\ttmpOrderClause += ',';\n\t\t\t}\n\t\t\ttmpOrderClause += ' '+tmpOrderBy[i].Column;\n\n\t\t\tif (tmpOrderBy[i].Direction == 'Descending')\n\t\t\t{\n\t\t\t\ttmpOrderClause += ' DESC';\n\t\t\t}\n\t\t}\n\t\treturn tmpOrderClause;\n\t};\n\n\t/**\n\t* Generate the limit clause\n\t*\n\t* @method: generateLimit\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateLimit = function(pParameters)\n\t{\n\t\tif (!pParameters.cap)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpLimit = ' LIMIT';\n\t\t// If there is a begin record, we'll pass that in as well.\n\t\tif (pParameters.begin !== false)\n\t\t{\n\t\t\ttmpLimit += ' ' + pParameters.begin + ',';\n\t\t}\n\t\t// Cap is required for a limit clause.\n\t\ttmpLimit += ' ' + pParameters.cap;\n\n\t\treturn tmpLimit;\n\t};\n\n\t/**\n\t* Generate the join clause\n\t*\n\t* @method: generateJoins\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the join clause\n\t*/\n\tvar generateJoins = function(pParameters)\n\t{\n\t\tvar tmpJoins = pParameters.join;\n\t\tif (!Array.isArray(tmpJoins) || tmpJoins.length < 1)\n\t\t{\n\t\t\treturn '';\n\t\t}\n\n\t\tvar tmpJoinClause = ''; //ex. ' INNER JOIN';\n\t\tfor (var i = 0; i < tmpJoins.length; i++)\n\t\t{\n\t\t\tvar join = tmpJoins[i];\n\t\t\t//verify that all required fields are valid\n\t\t\tif (join.Type && join.Table && join.From && join.To)\n\t\t\t{\n\t\t\t\ttmpJoinClause += ` ${join.Type} ${join.Table} ON ${join.From} = ${join.To}`;\n\t\t\t}\n\t\t}\n\n\t\treturn tmpJoinClause;\n\t}\n\n\t/**\n\t* Generate the update SET clause\n\t*\n\t* @method: generateUpdateSetters\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateUpdateSetters = function(pParameters)\n\t{\n\t\tvar tmpRecords = pParameters.query.records;\n\t\t// We need to tell the query not to generate improperly if there are no values to set.\n\t\tif (!Array.isArray(tmpRecords) || tmpRecords.length < 1)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpUpdate = '';\n\t\t// If there is more than one record in records, we are going to ignore them for now.\n\t\tvar tmpCurrentColumn = 0;\n\t\tfor(var tmpColumn in tmpRecords[0])\n\t\t{\n\t\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\t\tvar tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\tif (tmpColumn == tmpSchema[i].Column)\n\t\t\t\t{\n\t\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\t\ttmpSchemaEntry = tmpSchema[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (pParameters.query.disableAutoDateStamp &&\n\t\t\t\ttmpSchemaEntry.Type === 'UpdateDate')\n\t\t\t{\n\t\t\t\t// This is ignored if flag is set\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (pParameters.query.disableAutoUserStamp &&\n\t\t\t\ttmpSchemaEntry.Type === 'UpdateIDUser')\n\t\t\t{\n\t\t\t\t// This is ignored if flag is set\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'AutoIdentity':\n\t\t\t\tcase 'CreateDate':\n\t\t\t\tcase 'CreateIDUser':\n\t\t\t\tcase 'DeleteDate':\n\t\t\t\tcase 'DeleteIDUser':\n\t\t\t\t\t// These are all ignored on update\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpUpdate += ',';\n\t\t\t}\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\ttmpUpdate += ' '+tmpColumn+' = ' + SQL_NOW;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateIDUser':\n\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\tvar tmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdate += ' '+tmpColumn+' = :'+tmpColumnParameter;\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tvar tmpColumnDefaultParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdate += ' '+tmpColumn+' = :'+tmpColumnDefaultParameter;\n\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnDefaultParameter] = tmpRecords[0][tmpColumn];\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// We use a number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (tmpUpdate === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpUpdate;\n\t};\n\n\t/**\n\t* Generate the update-delete SET clause\n\t*\n\t* @method: generateUpdateDeleteSetters\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateUpdateDeleteSetters = function(pParameters)\n\t{\n\t\tif (pParameters.query.disableDeleteTracking)\n\t\t{\n\t\t\t//Don't generate an UPDATE query if Delete tracking is disabled\n\t\t\treturn false;\n\t\t}\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpCurrentColumn = 0;\n\t\tvar tmpHasDeletedField = false;\n\t\tvar tmpUpdate = '';\n\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\tvar tmpSchemaEntry = {Type:'Default'};\n\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t{\n\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\ttmpSchemaEntry = tmpSchema[i];\n\n\t\t\tvar tmpUpdateSql = null;\n\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'Deleted':\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = 1';\n\t\t\t\t\ttmpHasDeletedField = true; //this field is required in order for query to be built\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'DeleteDate':\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = ' + SQL_NOW;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\t\t// Delete operation is an Update, so we should stamp the update time\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = ' + SQL_NOW;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'DeleteIDUser':\n\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\tvar tmpColumnParameter = tmpSchemaEntry.Column+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = :'+tmpColumnParameter;\n\t\t\t\t\t// Set the query parameter\n\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t//DON'T allow update of other fields in this query\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpUpdate += ',';\n\t\t\t}\n\n\t\t\ttmpUpdate += tmpUpdateSql;\n\n\t\t\t// We use a number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (!tmpHasDeletedField ||\n\t\t\ttmpUpdate === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpUpdate;\n\t};\n\n\t/**\n\t* Generate the update-undelete SET clause\n\t*\n\t* @method: generateUpdateUndeleteSetters\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateUpdateUndeleteSetters = function(pParameters)\n\t{\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpCurrentColumn = 0;\n\t\tvar tmpHasDeletedField = false;\n\t\tvar tmpUpdate = '';\n\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\tvar tmpSchemaEntry = {Type:'Default'};\n\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t{\n\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\ttmpSchemaEntry = tmpSchema[i];\n\n\t\t\tvar tmpUpdateSql = null;\n\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'Deleted':\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = 0';\n\t\t\t\t\ttmpHasDeletedField = true; //this field is required in order for query to be built\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\t\t// The undelete operation is an Update, so we should stamp the update time\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = ' + SQL_NOW;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateIDUser':\n\t\t\t\t\tvar tmpColumnParameter = tmpSchemaEntry.Column+'_'+tmpCurrentColumn;\n\t\t\t\t\ttmpUpdateSql = ' '+tmpSchemaEntry.Column+' = :'+tmpColumnParameter;\n\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t//DON'T allow update of other fields in this query\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpUpdate += ',';\n\t\t\t}\n\n\t\t\ttmpUpdate += tmpUpdateSql;\n\n\t\t\t// We use a number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (!tmpHasDeletedField ||\n\t\t\ttmpUpdate === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpUpdate;\n\t};\n\n\t/**\n\t* Generate the create SET clause\n\t*\n\t* @method: generateCreateSetList\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateCreateSetValues = function(pParameters)\n\t{\n\t\tvar tmpRecords = pParameters.query.records;\n\t\t// We need to tell the query not to generate improperly if there are no values to set.\n\t\tif (!Array.isArray(tmpRecords) || tmpRecords.length < 1)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\n\t\tvar tmpCreateSet = '';\n\t\t// If there is more than one record in records, we are going to ignore them for now.\n\t\tvar tmpCurrentColumn = 0;\n\t\tfor(var tmpColumn in tmpRecords[0])\n\t\t{\n\t\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\t\tvar tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\tif (tmpColumn == tmpSchema[i].Column)\n\t\t\t\t{\n\t\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\t\ttmpSchemaEntry = tmpSchema[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!pParameters.query.disableDeleteTracking)\n\t\t\t{\n\t\t\t\tif (tmpSchemaEntry.Type === 'DeleteDate' ||\n\t\t\t\t\ttmpSchemaEntry.Type === 'DeleteIDUser')\n\t\t\t\t{\n\t\t\t\t\t// These are all ignored on insert (if delete tracking is enabled as normal)\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (tmpCurrentColumn > 0)\n\t\t\t{\n\t\t\t\ttmpCreateSet += ',';\n\t\t\t}\n\n\t\t\t//define a re-usable method for setting up field definitions in a default pattern\n\t\t\tvar buildDefaultDefinition = function()\n\t\t\t{\n\t\t\t\tvar tmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\ttmpCreateSet += ' :'+tmpColumnParameter;\n\t\t\t\t// Set the query parameter\n\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = tmpRecords[0][tmpColumn];\n\t\t\t};\n\n\t\t\tvar tmpColumnParameter;\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tcase 'AutoIdentity':\n\t\t\t\t\tif (pParameters.query.disableAutoIdentity)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\t\ttmpCreateSet += ' NULL';\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'AutoGUID':\n\t\t\t\t\tif (pParameters.query.disableAutoIdentity)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse if (tmpRecords[0][tmpColumn] &&\n\t\t\t\t\t\t\ttmpRecords[0][tmpColumn].length >= 5 &&\n\t\t\t\t\t\t\ttmpRecords[0][tmpColumn] !== '0x0000000000000000') //stricture default\n\t\t\t\t\t{\n\t\t\t\t\t\t// Allow consumer to override AutoGUID\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\t\ttmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\t\ttmpCreateSet += ' :'+tmpColumnParameter;\n\t\t\t\t\t\t// Set the query parameter\n\t\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.UUID;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'UpdateDate':\n\t\t\t\tcase 'CreateDate':\n\t\t\t\tcase 'DeleteDate':\n\t\t\t\t\tif (pParameters.query.disableAutoDateStamp)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is an autoidentity, so we don't parameterize it and just pass in NULL\n\t\t\t\t\t\ttmpCreateSet += ' ' + SQL_NOW;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'DeleteIDUser':\n\t\t\t\tcase 'UpdateIDUser':\n\t\t\t\tcase 'CreateIDUser':\n\t\t\t\t\tif (pParameters.query.disableAutoUserStamp)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This is the user ID, which we hope is in the query.\n\t\t\t\t\t\t// This is how to deal with a normal column\n\t\t\t\t\t\ttmpColumnParameter = tmpColumn+'_'+tmpCurrentColumn;\n\t\t\t\t\t\ttmpCreateSet += ' :'+tmpColumnParameter;\n\t\t\t\t\t\t// Set the query parameter\n\t\t\t\t\t\tpParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbuildDefaultDefinition();\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// We use an appended number to make sure parameters are unique.\n\t\t\ttmpCurrentColumn++;\n\t\t}\n\n\t\t// We need to tell the query not to generate improperly if there are no values set.\n\t\tif (tmpCreateSet === '')\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tmpCreateSet;\n\t};\n\n\t/**\n\t* Generate the create SET clause\n\t*\n\t* @method: generateCreateSetList\n\t* @param: {Object} pParameters SQL Query Parameters\n\t* @return: {String} Returns the table name clause\n\t*/\n\tvar generateCreateSetList = function(pParameters)\n\t{\n\t\t// The records were already validated by generateCreateSetValues\n\t\tvar tmpRecords = pParameters.query.records;\n\n\t\t// Check if there is a schema. If so, we will use it to decide if these are parameterized or not.\n\t\tvar tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];\n\n\t\tvar tmpCreateSet = '';\n\t\t// If there is more than one record in records, we are going to ignore them for now.\n\t\tfor(var tmpColumn in tmpRecords[0])\n\t\t{\n\t\t\t// No hash table yet, so, we will just linear search it for now.\n\t\t\t// This uses the schema to decide if we want to treat a column differently on insert\n\t\t\tvar tmpSchemaEntry = {Column:tmpColumn, Type:'Default'};\n\t\t\tfor (var i = 0; i < tmpSchema.length; i++)\n\t\t\t{\n\t\t\t\tif (tmpColumn == tmpSchema[i].Column)\n\t\t\t\t{\n\t\t\t\t\t// There is a schema entry for it. Process it accordingly.\n\t\t\t\t\ttmpSchemaEntry = tmpSchema[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!pParameters.query.disableDeleteTracking)\n\t\t\t{\n\t\t\t\tif (tmpSchemaEntry.Type === 'DeleteDate' ||\n\t\t\t\t\ttmpSchemaEntry.Type === 'DeleteIDUser')\n\t\t\t\t{\n\t\t\t\t\t// These are all ignored on insert (if delete tracking is enabled as normal)\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tswitch (tmpSchemaEntry.Type)\n\t\t\t{\n\t\t\t\tdefault:\n\t\t\t\t\tif (tmpCreateSet != '')\n\t\t\t\t\t{\n\t\t\t\t\t\ttmpCreateSet += ',';\n\t\t\t\t\t}\n\t\t\t\t\ttmpCreateSet += ' '+tmpColumn;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn tmpCreateSet;\n\t};\n\n\n\tvar Create = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpCreateSetList = generateCreateSetList(pParameters);\n\t\tvar tmpCreateSetValues = generateCreateSetValues(pParameters);\n\n\t\tif (!tmpCreateSetValues)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn 'INSERT INTO'+tmpTableName+' ('+tmpCreateSetList+') VALUES ('+tmpCreateSetValues+');';\n\t};\n\n\n\t/**\n\t* Read one or many records\n\t*\n\t* Some examples:\n\t* SELECT * FROM WIDGETS;\n\t* SELECT * FROM WIDGETS LIMIT 0, 20;\n\t* SELECT * FROM WIDGETS LIMIT 5, 20;\n\t* SELECT ID, Name, Cost FROM WIDGETS LIMIT 5, 20;\n\t* SELECT ID, Name, Cost FROM WIDGETS LIMIT 5, 20 WHERE LastName = 'Smith';\n\t*\n\t* @method Read\n\t* @param {Object} pParameters SQL Query parameters\n\t* @return {String} Returns the current Query for chaining.\n\t*/\n\tvar Read = function(pParameters)\n\t{\n\t\tvar tmpFieldList = generateFieldList(pParameters);\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpJoin = generateJoins(pParameters);\n\t\tvar tmpOrderBy = generateOrderBy(pParameters);\n\t\tvar tmpLimit = generateLimit(pParameters);\n\t\tconst tmpOptDistinct = pParameters.distinct ? ' DISTINCT' : '';\n\n\t\tif (pParameters.queryOverride)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tvar tmpQueryTemplate = _Fable.Utility.template(pParameters.queryOverride);\n\t\t\t\treturn tmpQueryTemplate({FieldList:tmpFieldList, TableName:tmpTableName, Where:tmpWhere, Join:tmpJoin, OrderBy:tmpOrderBy, Limit:tmpLimit, Distinct: tmpOptDistinct, _Params: pParameters});\n\t\t\t}\n\t\t\tcatch (pError)\n\t\t\t{\n\t\t\t\t// This pokemon is here to give us a convenient way of not throwing up totally if the query fails.\n\t\t\t\tconsole.log('Error with custom Read Query ['+pParameters.queryOverride+']: '+pError);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn `SELECT${tmpOptDistinct}${tmpFieldList} FROM${tmpTableName}${tmpJoin}${tmpWhere}${tmpOrderBy}${tmpLimit};`;\n\t};\n\n\tvar Update = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpUpdateSetters = generateUpdateSetters(pParameters);\n\n\t\tif (!tmpUpdateSetters)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn 'UPDATE'+tmpTableName+' SET'+tmpUpdateSetters+tmpWhere+';';\n\t};\n\n\tvar Delete = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpUpdateDeleteSetters = generateUpdateDeleteSetters(pParameters);\n\n\t\tif (tmpUpdateDeleteSetters)\n\t\t{\n\t\t\t//If it has a deleted bit, update it instead of actually deleting the record\n\t\t\treturn 'UPDATE'+tmpTableName+' SET'+tmpUpdateDeleteSetters+tmpWhere+';';\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn 'DELETE FROM'+tmpTableName+tmpWhere+';';\n\t\t}\n\t};\n\n\tvar Undelete = function(pParameters)\n\t{\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\t// TODO: Fix these\n\t\tlet tmpDeleteTrackingState = pParameters.query.disableDeleteTracking;\n\t\tpParameters.query.disableDeleteTracking = true;\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\tvar tmpUpdateUndeleteSetters = generateUpdateUndeleteSetters(pParameters);\n\t\tpParameters.query.disableDeleteTracking = tmpDeleteTrackingState;\n\n\t\tif (tmpUpdateUndeleteSetters)\n\t\t{\n\t\t\t//If the table has a deleted bit, go forward with the update to change things.\n\t\t\treturn 'UPDATE'+tmpTableName+' SET'+tmpUpdateUndeleteSetters+tmpWhere+';';\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// This is a no-op because the record can't be undeleted.\n\t\t\t// TODO: Should it throw instead?\n\t\t\treturn 'SELECT NULL;';\n\t\t}\n\t};\n\n\tvar Count = function(pParameters)\n\t{\n\t\tvar tmpFieldList = pParameters.distinct ? generateFieldList(pParameters, true) : '*';\n\t\tvar tmpTableName = generateTableName(pParameters);\n\t\tvar tmpJoin = generateJoins(pParameters);\n\t\tvar tmpWhere = generateWhere(pParameters);\n\t\t// here, we ignore the distinct keyword if no fields have been specified and\n\t\tif (pParameters.distinct && tmpFieldList.length < 1)\n\t\t{\n\t\t\tconsole.warn('Distinct requested but no field list or schema are available, so not honoring distinct for count query.');\n\t\t}\n\t\tconst tmpOptDistinct = pParameters.distinct && tmpFieldList.length > 0 ? 'DISTINCT' : '';\n\n\t\tif (pParameters.queryOverride)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tvar tmpQueryTemplate = _Fable.Utility.template(pParameters.queryOverride);\n\t\t\t\treturn tmpQueryTemplate({FieldList:[], TableName:tmpTableName, Where:tmpWhere, OrderBy:'', Limit:'', Distinct: tmpOptDistinct, _Params: pParameters});\n\t\t\t}\n\t\t\tcatch (pError)\n\t\t\t{\n\t\t\t\t// This pokemon is here to give us a convenient way of not throwing up totally if the query fails.\n\t\t\t\tconsole.log('Error with custom Count Query ['+pParameters.queryOverride+']: '+pError);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn `SELECT COUNT(${tmpOptDistinct}${tmpFieldList || '*'}) AS RowCount FROM${tmpTableName}${tmpJoin}${tmpWhere};`;\n\t};\n\n\tvar tmpDialect = ({\n\t\tCreate: Create,\n\t\tRead: Read,\n\t\tUpdate: Update,\n\t\tDelete: Delete,\n\t\tUndelete: Undelete,\n\t\tCount: Count\n\t});\n\n\t/**\n\t* Dialect Name\n\t*\n\t* @property name\n\t* @type string\n\t*/\n\tObject.defineProperty(tmpDialect, 'name',\n\t\t{\n\t\t\tget: function() { return 'MySQL'; },\n\t\t\tenumerable: true\n\t\t});\n\n\treturn tmpDialect;\n};\n\nmodule.exports = FoxHoundDialectMySQL;\n"]}
|