masterrecord 0.0.23 → 0.0.25
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/DeleteManager.js +51 -0
- package/Entity/EntityModel.js +192 -120
- package/Entity/EntityModelBuilder.js +41 -63
- package/Entity/EntityTrackerModel.js +222 -42
- package/InsertManager.js +138 -0
- package/MYSQLEngine.js +409 -0
- package/Masterrecord.js +233 -179
- package/Migrations/cli.js +106 -105
- package/Migrations/migrationTemplate.js +63 -63
- package/Migrations/migrations.js +65 -22
- package/Migrations/schema.js +42 -42
- package/QueryLanguage/queryManager.js +66 -0
- package/QueryLanguage/queryMethods.js +171 -0
- package/QueryLanguage/queryScript.js +331 -0
- package/SQLLiteEngine.js +409 -0
- package/Tools.js +118 -55
- package/package.json +23 -27
- package/QueryLanguage/_Expression.js +0 -322
- package/QueryLanguage/_LogicalQuery.js +0 -23
- package/QueryLanguage/_OperatorList.js +0 -88
- package/QueryLanguage/_QueryModel.js +0 -442
- package/QueryLanguage/_Tokenization.js +0 -173
- package/QueryLanguage/__Query.js +0 -386
- package/QueryLanguage/_simpleQuery.js +0 -184
- package/QueryLanguage/queryBuilder.js +0 -52
- package/SQLEngine.js +0 -52
package/MYSQLEngine.js
ADDED
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
var tools = require('masterrecord/Tools');
|
|
2
|
+
|
|
3
|
+
class SQLLiteEngine {
|
|
4
|
+
|
|
5
|
+
unsupportedWords = ["order"]
|
|
6
|
+
|
|
7
|
+
update(query){
|
|
8
|
+
var sqlQuery = ` UPDATE [${query.tableName}]
|
|
9
|
+
SET ${query.arg}
|
|
10
|
+
WHERE [${query.tableName}].[${query.primaryKey}] = ${query.primaryKeyValue}` // primary key for that table =
|
|
11
|
+
return this._run(sqlQuery);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
delete(queryObject){
|
|
15
|
+
var sqlObject = this._buildDeleteObject(queryObject);
|
|
16
|
+
var sqlQuery = `DELETE FROM [${sqlObject.tableName}] WHERE [${sqlObject.tableName}].[${sqlObject.primaryKey}] = ${sqlObject.value}`;
|
|
17
|
+
return this._execute(sqlQuery);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
insert(queryObject){
|
|
21
|
+
var sqlObject = this._buildSQLInsertObject(queryObject, queryObject.__entity);
|
|
22
|
+
var query = `INSERT INTO [${sqlObject.tableName}] (${sqlObject.columns})
|
|
23
|
+
VALUES (${sqlObject.values})`;
|
|
24
|
+
var queryObj = this._run(query);
|
|
25
|
+
var open = {
|
|
26
|
+
"id": queryObj.lastInsertRowid
|
|
27
|
+
};
|
|
28
|
+
return open;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get(query, entity, context){
|
|
32
|
+
var queryString = {};
|
|
33
|
+
try {
|
|
34
|
+
if(query.raw){
|
|
35
|
+
queryString.query = query.raw;
|
|
36
|
+
}
|
|
37
|
+
else{
|
|
38
|
+
queryString = this.buildQuery(query, entity, context);
|
|
39
|
+
}
|
|
40
|
+
if(queryString.query){
|
|
41
|
+
console.log("SQL:", queryString.query);
|
|
42
|
+
var queryReturn = this.db.prepare(queryString.query).get();
|
|
43
|
+
return queryReturn;
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
} catch (err) {
|
|
47
|
+
console.error(err);
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
getCount(queryObject, entity, context){
|
|
53
|
+
var query = queryObject.script;
|
|
54
|
+
var queryString = {};
|
|
55
|
+
try {
|
|
56
|
+
if(query.raw){
|
|
57
|
+
queryString.query = query.raw;
|
|
58
|
+
}
|
|
59
|
+
else{
|
|
60
|
+
queryString = this.buildQuery(query, entity, context);
|
|
61
|
+
}
|
|
62
|
+
if(queryString.query){
|
|
63
|
+
var queryCount = queryObject.count(queryString.query)
|
|
64
|
+
console.log("SQL:", queryCount );
|
|
65
|
+
var queryReturn = this.db.prepare(queryCount ).get();
|
|
66
|
+
return queryReturn;
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
} catch (err) {
|
|
70
|
+
console.error(err);
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
all(query, entity, context){
|
|
76
|
+
var selectQuery = {};
|
|
77
|
+
try {
|
|
78
|
+
if(query.raw){
|
|
79
|
+
selectQuery.query = query.raw;
|
|
80
|
+
}
|
|
81
|
+
else{
|
|
82
|
+
selectQuery = this.buildQuery(query, entity, context);
|
|
83
|
+
}
|
|
84
|
+
if(selectQuery.query){
|
|
85
|
+
console.log("SQL:", selectQuery.query);
|
|
86
|
+
var queryReturn = this.db.prepare(selectQuery.query).all();
|
|
87
|
+
return queryReturn;
|
|
88
|
+
}
|
|
89
|
+
return null;
|
|
90
|
+
} catch (err) {
|
|
91
|
+
console.error(err);
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
buildQuery(query, entity, context){
|
|
98
|
+
|
|
99
|
+
var queryObject = {};
|
|
100
|
+
queryObject.entity = this.getEntity(entity.__name, query.entityMap);
|
|
101
|
+
queryObject.select = this.buildSelect(query, entity);
|
|
102
|
+
queryObject.from = this.buildFrom(query, entity);
|
|
103
|
+
queryObject.include = this.buildInclude(query, entity, context, queryObject);
|
|
104
|
+
queryObject.where = this.buildWhere(query, entity);
|
|
105
|
+
|
|
106
|
+
var queryString = `${queryObject.select} ${queryObject.from} ${queryObject.include} ${queryObject.where}`;
|
|
107
|
+
return {
|
|
108
|
+
query : queryString,
|
|
109
|
+
entity : this.getEntity(entity.__name, query.entityMap)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
buildWhere(query, mainQuery){
|
|
115
|
+
var whereEntity = query.where;
|
|
116
|
+
var strQuery = "";
|
|
117
|
+
var $that = this;
|
|
118
|
+
if(whereEntity){
|
|
119
|
+
var entity = this.getEntity(query.parentName, query.entityMap);
|
|
120
|
+
for (let part in whereEntity[query.parentName]) {
|
|
121
|
+
var item = whereEntity[query.parentName][part];
|
|
122
|
+
for (let exp in item.expressions) {
|
|
123
|
+
var field = tools.capitalizeFirstLetter(item.expressions[exp].field);
|
|
124
|
+
if(mainQuery[field]){
|
|
125
|
+
if(mainQuery[field].isNavigational){
|
|
126
|
+
entity = $that.getEntity(field, query.entityMap);
|
|
127
|
+
field = item.fields[1];
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if(strQuery === ""){
|
|
131
|
+
strQuery = `WHERE ${entity}.${field} ${item.expressions[exp].func} '${item.expressions[exp].arg}'`;
|
|
132
|
+
}
|
|
133
|
+
else{
|
|
134
|
+
strQuery = `${strQuery} and ${entity}.${field} ${item.expressions[exp].func} '${item.expressions[exp].arg}'`;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return strQuery;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
buildInclude( query, entity, context){
|
|
143
|
+
var includeQuery = "";
|
|
144
|
+
for (let part in query.include) {
|
|
145
|
+
var includeEntity = query.include[part];
|
|
146
|
+
var $that = this;
|
|
147
|
+
if(includeEntity){
|
|
148
|
+
var parentObj = includeEntity[query.parentName];
|
|
149
|
+
var currentContext = "";
|
|
150
|
+
if(includeEntity.selectFields){
|
|
151
|
+
currentContext = context[tools.capitalizeFirstLetter(includeEntity.selectFields[0])];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if(parentObj){
|
|
155
|
+
parentObj.entityMap = query.entityMap;
|
|
156
|
+
var foreignKey = $that.getForeignKey(entity.__name, currentContext.__entity);
|
|
157
|
+
var mainPrimaryKey = $that.getPrimarykey(entity);
|
|
158
|
+
var mainEntity = $that.getEntity(entity.__name, query.entityMap);
|
|
159
|
+
if(currentContext.__entity[entity.__name].type === "hasManyThrough"){
|
|
160
|
+
var foreignTable = tools.capitalizeFirstLetter(currentContext.__entity[entity.__name].foreignTable); //to uppercase letter
|
|
161
|
+
foreignKey = $that.getPrimarykey(currentContext.__entity);
|
|
162
|
+
mainPrimaryKey = context[foreignTable].__entity[currentContext.__entity.__name].foreignKey;
|
|
163
|
+
var mainEntity = $that.getEntity(foreignTable,query.entityMap);
|
|
164
|
+
}
|
|
165
|
+
// add foreign key to select so that it picks it up
|
|
166
|
+
if(parentObj.select){
|
|
167
|
+
parentObj.select.selectFields.push(foreignKey);
|
|
168
|
+
}else{
|
|
169
|
+
parentObj.select = {};
|
|
170
|
+
parentObj.select.selectFields = [];
|
|
171
|
+
parentObj.select.selectFields.push(foreignKey);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
var innerQuery = $that.buildQuery(parentObj, currentContext.__entity, context);
|
|
175
|
+
|
|
176
|
+
includeQuery += `LEFT JOIN (${innerQuery.query}) AS ${innerQuery.entity} ON ${ mainEntity}.${mainPrimaryKey} = ${innerQuery.entity}.${foreignKey} `;
|
|
177
|
+
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return includeQuery;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
buildFrom(query, entity){
|
|
185
|
+
var entityName = this.getEntity(entity.__name, query.entityMap);
|
|
186
|
+
if(entityName ){
|
|
187
|
+
return `FROM ${entity.__name } AS ${entityName}`;
|
|
188
|
+
}
|
|
189
|
+
else{ return "" }
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
buildSelect(query, entity){
|
|
193
|
+
// this means that there is a select statement
|
|
194
|
+
var select = "SELECT";
|
|
195
|
+
var arr = "";
|
|
196
|
+
var $that = this;
|
|
197
|
+
if(query.select){
|
|
198
|
+
for (const item in query.select.selectFields) {
|
|
199
|
+
arr += `${$that.getEntity(entity.__name, query.entityMap)}.${query.select.selectFields[item]}, `;
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
}
|
|
203
|
+
else{
|
|
204
|
+
var entityList = this.getEntityList(entity);
|
|
205
|
+
for (const item in entityList) {
|
|
206
|
+
arr += `${$that.getEntity(entity.__name, query.entityMap)}.${entityList[item]}, `;
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
arr = arr.replace(/,\s*$/, "");
|
|
210
|
+
return `${select} ${arr} `;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
getForeignKey(name, entity){
|
|
214
|
+
if(entity && name){
|
|
215
|
+
return entity[name].foreignKey;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
getPrimarykey(entity){
|
|
220
|
+
for (const item in entity) {
|
|
221
|
+
if(entity[item].primary){
|
|
222
|
+
if(entity[item].primary === true){
|
|
223
|
+
return entity[item].name;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
getForeignTable(name, entity){
|
|
230
|
+
if(entity && name){
|
|
231
|
+
return entity[name].foreignTable;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
getInclude(name, query){
|
|
236
|
+
var include = query.include;
|
|
237
|
+
if(include){
|
|
238
|
+
for (let part in include) {
|
|
239
|
+
if(tools.capitalizeFirstLetter(include[part].selectFields[0]) === name){
|
|
240
|
+
return include[part];
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
else{
|
|
245
|
+
return "";
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
getEntity(name, maps){
|
|
250
|
+
for (let item in maps) {
|
|
251
|
+
var map = maps[item];
|
|
252
|
+
if(tools.capitalizeFirstLetter(name) === map.name){
|
|
253
|
+
return map.entity
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return "";
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// return a list of entity names and skip foreign keys and underscore.
|
|
260
|
+
getEntityList(entity){
|
|
261
|
+
var entitiesList = [];
|
|
262
|
+
var $that = this;
|
|
263
|
+
for (var ent in entity) {
|
|
264
|
+
if(!ent.startsWith("_")){
|
|
265
|
+
if(!entity[ent].foreignKey){
|
|
266
|
+
if(entity[ent].relationshipTable){
|
|
267
|
+
if($that.chechUnsupportedWords(entity[ent].relationshipTable)){
|
|
268
|
+
entitiesList.push(`'${entity[ent].relationshipTable}'`);
|
|
269
|
+
}
|
|
270
|
+
else{
|
|
271
|
+
entitiesList.push(entity[ent].relationshipTable);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
else{
|
|
275
|
+
if($that.chechUnsupportedWords(ent)){
|
|
276
|
+
entitiesList.push(`'${ent}'`);
|
|
277
|
+
}
|
|
278
|
+
else{
|
|
279
|
+
entitiesList.push(ent);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return entitiesList
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
chechUnsupportedWords(word){
|
|
289
|
+
for (var item in this.unsupportedWords) {
|
|
290
|
+
var text = this.unsupportedWords[item];
|
|
291
|
+
if(text === word){
|
|
292
|
+
return true
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
startTransaction(){
|
|
299
|
+
this.db.prepare('BEGIN').run();
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
endTransaction(){
|
|
303
|
+
this.db.prepare('COMMIT').run();
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
errorTransaction(){
|
|
307
|
+
this.db.prepare('ROLLBACK').run();
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
_buildSQLEqualTo(model){
|
|
311
|
+
var $that = this;
|
|
312
|
+
var argument = null;
|
|
313
|
+
var dirtyFields = model.__dirtyFields;
|
|
314
|
+
|
|
315
|
+
for (var column in dirtyFields) {
|
|
316
|
+
// TODO Boolean value is a string with a letter
|
|
317
|
+
switch(model.__entity[dirtyFields[column]].type){
|
|
318
|
+
case "integer" :
|
|
319
|
+
argument = argument === null ? `[${dirtyFields[column]}] = ${model[dirtyFields[column]]},` : `${argument} [${dirtyFields[column]}] = ${model[dirtyFields[column]]},`;
|
|
320
|
+
break;
|
|
321
|
+
case "string" :
|
|
322
|
+
argument = argument === null ? `[${dirtyFields[column]}] = '${$that._santizeSingleQuotes(model[dirtyFields[column]])}',` : `${argument} [${dirtyFields[column]}] = '${$that._santizeSingleQuotes(model[dirtyFields[column]])}',`;
|
|
323
|
+
break;
|
|
324
|
+
default:
|
|
325
|
+
argument = argument === null ? `[${dirtyFields[column]}] = '${model[dirtyFields[column]]}',` : `${argument} [${dirtyFields[column]}] = '${model[dirtyFields[column]]}',`;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return argument.replace(/,\s*$/, "");
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
_buildDeleteObject(currentModel){
|
|
333
|
+
var primaryKey = currentModel.__Key === undefined ? tools.getPrimaryKeyObject(currentModel.__entity) : currentModel.__Key;
|
|
334
|
+
var value = currentModel.__value === undefined ? currentModel[primaryKey] : currentModel.__value;
|
|
335
|
+
var tableName = currentModel.__tableName === undefined ? currentModel.__entity.__name : currentModel.__tableName;
|
|
336
|
+
return {tableName: tableName, primaryKey : primaryKey, value : value};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
// return columns and value strings
|
|
341
|
+
_buildSQLInsertObject(fields, modelEntity){
|
|
342
|
+
var $that = this;
|
|
343
|
+
var columns = null;
|
|
344
|
+
var values = null;
|
|
345
|
+
for (var column in modelEntity) {
|
|
346
|
+
// column1 = value1, column2 = value2, ...
|
|
347
|
+
if(column.indexOf("__") === -1 ){
|
|
348
|
+
// call the get method if avlable
|
|
349
|
+
var fieldColumn = "";
|
|
350
|
+
// check if get function is avaliable if so use that
|
|
351
|
+
fieldColumn = fields[column];
|
|
352
|
+
|
|
353
|
+
if((fieldColumn !== undefined && fieldColumn !== null && fieldColumn !== "" ) && typeof(fieldColumn) !== "object"){
|
|
354
|
+
switch(modelEntity[column].type){
|
|
355
|
+
case "belongsTo" :
|
|
356
|
+
column = modelEntity[column].relationshipTable === undefined ? column : modelEntity[column].relationshipTable;
|
|
357
|
+
break;
|
|
358
|
+
case "string" :
|
|
359
|
+
fieldColumn = `'${$that._santizeSingleQuotes(fields[column])}'`;
|
|
360
|
+
break;
|
|
361
|
+
case "time" :
|
|
362
|
+
fieldColumn = fields[column];
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
columns = columns === null ? `'${column}',` : `${columns} '${column}',`;
|
|
367
|
+
values = values === null ? `${fieldColumn},` : `${values} ${fieldColumn},`;
|
|
368
|
+
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
return {tableName: modelEntity.__name, columns: columns.replace(/,\s*$/, ""), values: values.replace(/,\s*$/, "")};
|
|
373
|
+
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// will add double single quotes to allow sting to be saved.
|
|
377
|
+
_santizeSingleQuotes(string){
|
|
378
|
+
return string.replace(/'/g, "''");
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// converts any object into SQL parameter select string
|
|
382
|
+
_convertEntityToSelectParameterString(obj, entityName){
|
|
383
|
+
// todo: loop throgh object and append string with comma to
|
|
384
|
+
var mainString = "";
|
|
385
|
+
const entries = Object.keys(obj);
|
|
386
|
+
|
|
387
|
+
for (const [name] of entries) {
|
|
388
|
+
mainString += `${mainString}, ${entityName}.${name}`;
|
|
389
|
+
}
|
|
390
|
+
return mainString;;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
_execute(query){
|
|
394
|
+
console.log("SQL:", query);
|
|
395
|
+
return this.db.exec(query);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
_run(query){
|
|
399
|
+
console.log("SQL:", query);
|
|
400
|
+
return this.db.prepare(query).run();
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
setDB(db, type){
|
|
404
|
+
this.db = db;
|
|
405
|
+
this.dbType = type; // this will let us know which type of sqlengine to use.
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
module.exports = SQLLiteEngine;
|