masterrecord 0.0.45 → 0.0.46
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/context.js +43 -2
- package/mySQLEngine.js +409 -0
- package/package.json +3 -2
- package/postgresEngine.js +241 -32
package/context.js
CHANGED
|
@@ -4,7 +4,7 @@ var modelBuilder = require('./Entity/entityModelBuilder');
|
|
|
4
4
|
var query = require('masterrecord/QueryLanguage/queryMethods');
|
|
5
5
|
var tools = require('./Tools');
|
|
6
6
|
var SQLLiteEngine = require('masterrecord/SQLLiteEngine');
|
|
7
|
-
var MYSQLEngine = require('masterrecord/
|
|
7
|
+
var MYSQLEngine = require('masterrecord/mySQLEngine');
|
|
8
8
|
var insertManager = require('./insertManager');
|
|
9
9
|
var deleteManager = require('./deleteManager');
|
|
10
10
|
var globSearch = require("glob");
|
|
@@ -23,6 +23,7 @@ class context {
|
|
|
23
23
|
__name = "";
|
|
24
24
|
isSQLite = false;
|
|
25
25
|
isMySQL = false;
|
|
26
|
+
isPostgres = false;
|
|
26
27
|
|
|
27
28
|
constructor(){
|
|
28
29
|
this. __enviornment = process.env.master;
|
|
@@ -128,16 +129,20 @@ class context {
|
|
|
128
129
|
var file = this.__findSettings(root, rootFolderLocation, envType);
|
|
129
130
|
var settings = require(file.file);
|
|
130
131
|
var options = settings[contextName];
|
|
132
|
+
|
|
131
133
|
if(options === undefined){
|
|
132
134
|
console.log("settings missing context name settings");
|
|
133
135
|
throw error("settings missing context name settings");
|
|
134
136
|
}
|
|
137
|
+
|
|
135
138
|
this.validateSQLiteOptions(options);
|
|
136
139
|
options.completeConnection = `${file.rootFolder}${options.connection}`;
|
|
137
140
|
var dbDirectory = options.completeConnection.substr(0, options.completeConnection.lastIndexOf("\/"));
|
|
141
|
+
|
|
138
142
|
if (!fs.existsSync(dbDirectory)){
|
|
139
143
|
fs.mkdirSync(dbDirectory);
|
|
140
144
|
}
|
|
145
|
+
|
|
141
146
|
this.db = this.__SQLiteInit(options, "better-sqlite3");
|
|
142
147
|
this._SQLEngine.setDB(this.db, "better-sqlite3");
|
|
143
148
|
return this;
|
|
@@ -151,8 +156,9 @@ class context {
|
|
|
151
156
|
|
|
152
157
|
}
|
|
153
158
|
|
|
154
|
-
useMySql(options
|
|
159
|
+
useMySql(options){
|
|
155
160
|
if(options !== undefined){
|
|
161
|
+
this.isMySQL = true;
|
|
156
162
|
this.db = this.__mysqlInit(options, "mysql");
|
|
157
163
|
this._MYSQLEngine.setDB(this.db, "mysql");
|
|
158
164
|
return this;
|
|
@@ -217,6 +223,41 @@ class context {
|
|
|
217
223
|
this.__clearErrorHandler();
|
|
218
224
|
this._SQLEngine.endTransaction();
|
|
219
225
|
}
|
|
226
|
+
if(this.isMySQL){
|
|
227
|
+
this._SQLEngine.startTransaction();
|
|
228
|
+
for (var model in tracked) {
|
|
229
|
+
var currentModel = tracked[model];
|
|
230
|
+
switch(currentModel.__state) {
|
|
231
|
+
case "insert":
|
|
232
|
+
var insert = new insertManager(this._SQLEngine, this._isModelValid, this.__entities);
|
|
233
|
+
insert.init(currentModel);
|
|
234
|
+
|
|
235
|
+
break;
|
|
236
|
+
case "modified":
|
|
237
|
+
if(currentModel.__dirtyFields.length > 0){
|
|
238
|
+
var cleanCurrentModel = tools.removePrimarykeyandVirtual(currentModel, currentModel._entity);
|
|
239
|
+
// build columns equal to value string
|
|
240
|
+
var argu = this._SQLEngine._buildSQLEqualTo(cleanCurrentModel);
|
|
241
|
+
var primaryKey = tools.getPrimaryKeyObject(cleanCurrentModel.__entity);
|
|
242
|
+
var sqlUpdate = {tableName: cleanCurrentModel.__entity.__name, arg: argu, primaryKey : primaryKey, primaryKeyValue : cleanCurrentModel[primaryKey] };
|
|
243
|
+
this._SQLEngine.update(sqlUpdate);
|
|
244
|
+
}
|
|
245
|
+
else{
|
|
246
|
+
console.log("Tracked entity modified with no values being changed");
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// code block
|
|
250
|
+
break;
|
|
251
|
+
case "delete":
|
|
252
|
+
var deleteObject = new deleteManager(this._SQLEngine, this.__entities);
|
|
253
|
+
deleteObject.init(currentModel);
|
|
254
|
+
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
this.__clearErrorHandler();
|
|
259
|
+
this._SQLEngine.endTransaction();
|
|
260
|
+
}
|
|
220
261
|
}
|
|
221
262
|
else{
|
|
222
263
|
console.log("save changes has no tracked entities");
|
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;
|
package/package.json
CHANGED
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
"commander": "^11.1.0",
|
|
6
6
|
"glob" : "^10.3.10",
|
|
7
7
|
"deep-object-diff" : "^1.1.9",
|
|
8
|
-
"pg" : "^8.13.3"
|
|
8
|
+
"pg" : "^8.13.3",
|
|
9
|
+
"mysql" : "^2.18.1"
|
|
9
10
|
},
|
|
10
|
-
"version": "0.0.
|
|
11
|
+
"version": "0.0.46",
|
|
11
12
|
"description": "An Object-relational mapping for the Master framework. Master Record connects classes to relational database tables to establish a database with almost zero-configuration ",
|
|
12
13
|
"homepage": "https://github.com/Tailor/MasterRecord#readme",
|
|
13
14
|
"repository": {
|
package/postgresEngine.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
// Version 0.0.12
|
|
1
2
|
var tools = require('masterrecord/Tools');
|
|
2
3
|
|
|
3
|
-
class
|
|
4
|
+
class postgresEngine {
|
|
4
5
|
|
|
5
6
|
unsupportedWords = ["order"]
|
|
6
7
|
|
|
@@ -35,7 +36,12 @@ class SQLLiteEngine {
|
|
|
35
36
|
queryString.query = query.raw;
|
|
36
37
|
}
|
|
37
38
|
else{
|
|
38
|
-
|
|
39
|
+
if(typeof query === 'string'){
|
|
40
|
+
queryString.query = query;
|
|
41
|
+
}
|
|
42
|
+
else{
|
|
43
|
+
queryString = this.buildQuery(query, entity, context);
|
|
44
|
+
}
|
|
39
45
|
}
|
|
40
46
|
if(queryString.query){
|
|
41
47
|
console.log("SQL:", queryString.query);
|
|
@@ -57,10 +63,14 @@ class SQLLiteEngine {
|
|
|
57
63
|
queryString.query = query.raw;
|
|
58
64
|
}
|
|
59
65
|
else{
|
|
60
|
-
|
|
66
|
+
if(query.count === undefined){
|
|
67
|
+
query.count = "none";
|
|
68
|
+
}
|
|
69
|
+
queryString.entity = this.getEntity(entity.__name, query.entityMap);
|
|
70
|
+
queryString.query = `SELECT ${this.buildCount(query, entity)} ${this.buildFrom(query, entity)} ${this.buildWhere(query, entity)}`
|
|
61
71
|
}
|
|
62
72
|
if(queryString.query){
|
|
63
|
-
var queryCount =
|
|
73
|
+
var queryCount = queryString.query
|
|
64
74
|
console.log("SQL:", queryCount );
|
|
65
75
|
var queryReturn = this.db.prepare(queryCount ).get();
|
|
66
76
|
return queryReturn;
|
|
@@ -79,6 +89,7 @@ class SQLLiteEngine {
|
|
|
79
89
|
selectQuery.query = query.raw;
|
|
80
90
|
}
|
|
81
91
|
else{
|
|
92
|
+
|
|
82
93
|
selectQuery = this.buildQuery(query, entity, context);
|
|
83
94
|
}
|
|
84
95
|
if(selectQuery.query){
|
|
@@ -93,17 +104,49 @@ class SQLLiteEngine {
|
|
|
93
104
|
}
|
|
94
105
|
}
|
|
95
106
|
|
|
107
|
+
changeNullQuery(query){
|
|
108
|
+
if(query.where){
|
|
109
|
+
var whereClaus;
|
|
110
|
+
whereClaus = query.where.expr.replace("=== null", "is null");
|
|
111
|
+
if(whereClaus === query.where.expr){
|
|
112
|
+
whereClaus = query.where.expr.replace("!= null", "is not null");
|
|
113
|
+
}
|
|
114
|
+
query.where.expr = whereClaus;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
buildCount(query, mainQuery){
|
|
120
|
+
var entity = this.getEntity(query.parentName, query.entityMap);
|
|
121
|
+
if(query.count){
|
|
122
|
+
if(query.count !== "none"){
|
|
123
|
+
return `COUNT(${entity}.${query.count.selectFields[0]})`
|
|
124
|
+
}
|
|
125
|
+
else{
|
|
126
|
+
return `COUNT(*)`
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
else{
|
|
130
|
+
return ""
|
|
131
|
+
}
|
|
132
|
+
}
|
|
96
133
|
|
|
97
|
-
buildQuery(query, entity, context){
|
|
134
|
+
buildQuery(query, entity, context, limit){
|
|
98
135
|
|
|
99
136
|
var queryObject = {};
|
|
100
137
|
queryObject.entity = this.getEntity(entity.__name, query.entityMap);
|
|
101
138
|
queryObject.select = this.buildSelect(query, entity);
|
|
139
|
+
queryObject.count = this.buildCount(query, entity);
|
|
102
140
|
queryObject.from = this.buildFrom(query, entity);
|
|
103
141
|
queryObject.include = this.buildInclude(query, entity, context, queryObject);
|
|
104
142
|
queryObject.where = this.buildWhere(query, entity);
|
|
143
|
+
queryObject.and = this.buildAnd(query, entity);
|
|
144
|
+
queryObject.take = this.buildTake(query);
|
|
145
|
+
queryObject.skip = this.buildSkip(query);
|
|
146
|
+
queryObject.orderBy = this.buildOrderBy(query);
|
|
147
|
+
|
|
105
148
|
|
|
106
|
-
var queryString = `${queryObject.select} ${queryObject.from} ${queryObject.include} ${queryObject.where}`;
|
|
149
|
+
var queryString = `${queryObject.select} ${queryObject.count} ${queryObject.from} ${queryObject.include} ${queryObject.where} ${queryObject.and} ${queryObject.orderBy} ${queryObject.take} ${queryObject.skip}`;
|
|
107
150
|
return {
|
|
108
151
|
query : queryString,
|
|
109
152
|
entity : this.getEntity(entity.__name, query.entityMap)
|
|
@@ -111,14 +154,62 @@ class SQLLiteEngine {
|
|
|
111
154
|
|
|
112
155
|
}
|
|
113
156
|
|
|
114
|
-
|
|
115
|
-
|
|
157
|
+
buildOrderBy(query){
|
|
158
|
+
// ORDER BY column1, column2, ... ASC|DESC;
|
|
159
|
+
var $that = this;
|
|
160
|
+
var orderByType = "ASC";
|
|
161
|
+
var orderByEntity = query.orderBy;
|
|
162
|
+
var strQuery = "";
|
|
163
|
+
if(orderByEntity === false){
|
|
164
|
+
orderByType = "DESC";
|
|
165
|
+
orderByEntity = query.orderByDesc;
|
|
166
|
+
}
|
|
167
|
+
if(orderByEntity){
|
|
168
|
+
var entity = this.getEntity(query.parentName, query.entityMap);
|
|
169
|
+
var fieldList = "";
|
|
170
|
+
for (const item in orderByEntity.selectFields) {
|
|
171
|
+
fieldList += `${entity}.${orderByEntity.selectFields[item]}, `;
|
|
172
|
+
};
|
|
173
|
+
fieldList = fieldList.replace(/,\s*$/, "");
|
|
174
|
+
strQuery = "ORDER BY";
|
|
175
|
+
strQuery += ` ${fieldList} ${orderByType}`;
|
|
176
|
+
}
|
|
177
|
+
return strQuery;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
buildTake(query){
|
|
181
|
+
if(query.take){
|
|
182
|
+
return `LIMIT ${query.take}`
|
|
183
|
+
}
|
|
184
|
+
else{
|
|
185
|
+
return "";
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
buildSkip(query){
|
|
190
|
+
if(query.skip){
|
|
191
|
+
return `OFFSET ${query.skip}`
|
|
192
|
+
}
|
|
193
|
+
else{
|
|
194
|
+
return "";
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
buildAnd(query, mainQuery){
|
|
199
|
+
// loop through the AND
|
|
200
|
+
// loop update ther where .expr
|
|
201
|
+
var andEntity = query.and;
|
|
116
202
|
var strQuery = "";
|
|
117
203
|
var $that = this;
|
|
118
|
-
|
|
204
|
+
var str = "";
|
|
205
|
+
|
|
206
|
+
if(andEntity){
|
|
119
207
|
var entity = this.getEntity(query.parentName, query.entityMap);
|
|
120
|
-
|
|
121
|
-
|
|
208
|
+
var andList = [];
|
|
209
|
+
for (let entityPart in andEntity) { // loop through list of and's
|
|
210
|
+
var itemEntity = andEntity[entityPart]; // get the entityANd
|
|
211
|
+
for (let table in itemEntity[query.parentName]) { // find the main table
|
|
212
|
+
var item = itemEntity[query.parentName][table];
|
|
122
213
|
for (let exp in item.expressions) {
|
|
123
214
|
var field = tools.capitalizeFirstLetter(item.expressions[exp].field);
|
|
124
215
|
if(mainQuery[field]){
|
|
@@ -127,14 +218,90 @@ class SQLLiteEngine {
|
|
|
127
218
|
field = item.fields[1];
|
|
128
219
|
}
|
|
129
220
|
}
|
|
221
|
+
if(item.expressions[exp].arg === "null"){
|
|
222
|
+
if(item.expressions[exp].func === "="){
|
|
223
|
+
item.expressions[exp].func = "is"
|
|
224
|
+
}
|
|
225
|
+
if(item.expressions[exp].func === "!="){
|
|
226
|
+
item.expressions[exp].func = "is not"
|
|
227
|
+
}
|
|
228
|
+
}
|
|
130
229
|
if(strQuery === ""){
|
|
131
|
-
|
|
230
|
+
if(item.expressions[exp].arg === "null"){
|
|
231
|
+
strQuery = `${entity}.${field} ${item.expressions[exp].func} ${item.expressions[exp].arg}`;
|
|
232
|
+
}else{
|
|
233
|
+
strQuery = `${entity}.${field} ${item.expressions[exp].func} '${item.expressions[exp].arg}'`;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
else{
|
|
237
|
+
if(item.expressions[exp].arg === "null"){
|
|
238
|
+
strQuery = `${strQuery} and ${entity}.${field} ${item.expressions[exp].func} ${item.expressions[exp].arg}`;
|
|
239
|
+
}else{
|
|
240
|
+
strQuery = `${strQuery} and ${entity}.${field} ${item.expressions[exp].func} '${item.expressions[exp].arg}'`;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
andList.push(strQuery);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if(andList.length > 0){
|
|
251
|
+
str = `and ${andList.join(" and ")}`;
|
|
252
|
+
}
|
|
253
|
+
return str
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
buildWhere(query, mainQuery){
|
|
257
|
+
var whereEntity = query.where;
|
|
258
|
+
|
|
259
|
+
var strQuery = "";
|
|
260
|
+
var $that = this;
|
|
261
|
+
if(whereEntity){
|
|
262
|
+
var entity = this.getEntity(query.parentName, query.entityMap);
|
|
263
|
+
|
|
264
|
+
var item = whereEntity[query.parentName].query;
|
|
265
|
+
for (let exp in item.expressions) {
|
|
266
|
+
var field = tools.capitalizeFirstLetter(item.expressions[exp].field);
|
|
267
|
+
if(mainQuery[field]){
|
|
268
|
+
if(mainQuery[field].isNavigational){
|
|
269
|
+
entity = $that.getEntity(field, query.entityMap);
|
|
270
|
+
field = item.fields[1];
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if(item.expressions[exp].arg === "null"){
|
|
274
|
+
if(item.expressions[exp].func === "="){
|
|
275
|
+
item.expressions[exp].func = "is"
|
|
276
|
+
}
|
|
277
|
+
if(item.expressions[exp].func === "!="){
|
|
278
|
+
item.expressions[exp].func = "is not"
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if(strQuery === ""){
|
|
282
|
+
if(item.expressions[exp].arg === "null"){
|
|
283
|
+
strQuery = `WHERE ${entity}.${field} ${item.expressions[exp].func} ${item.expressions[exp].arg}`;
|
|
284
|
+
}else{
|
|
285
|
+
if(item.expressions[exp].func === "IN"){
|
|
286
|
+
strQuery = `WHERE ${entity}.${field} ${item.expressions[exp].func} ${item.expressions[exp].arg}`;
|
|
132
287
|
}
|
|
133
288
|
else{
|
|
134
|
-
strQuery =
|
|
289
|
+
strQuery = `WHERE ${entity}.${field} ${item.expressions[exp].func} '${item.expressions[exp].arg}'`;
|
|
135
290
|
}
|
|
136
291
|
}
|
|
137
292
|
}
|
|
293
|
+
else{
|
|
294
|
+
if(item.expressions[exp].arg === "null"){
|
|
295
|
+
strQuery = `${strQuery} and ${entity}.${field} ${item.expressions[exp].func} ${item.expressions[exp].arg}`;
|
|
296
|
+
}else{
|
|
297
|
+
strQuery = `${strQuery} and ${entity}.${field} ${item.expressions[exp].func} '${item.expressions[exp].arg}'`;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
|
|
138
305
|
}
|
|
139
306
|
return strQuery;
|
|
140
307
|
}
|
|
@@ -249,7 +416,7 @@ class SQLLiteEngine {
|
|
|
249
416
|
getEntity(name, maps){
|
|
250
417
|
for (let item in maps) {
|
|
251
418
|
var map = maps[item];
|
|
252
|
-
if(tools.capitalizeFirstLetter(name) === map.name){
|
|
419
|
+
if(tools.capitalizeFirstLetter(name) === tools.capitalizeFirstLetter(map.name)){
|
|
253
420
|
return map.entity
|
|
254
421
|
}
|
|
255
422
|
}
|
|
@@ -263,21 +430,16 @@ class SQLLiteEngine {
|
|
|
263
430
|
for (var ent in entity) {
|
|
264
431
|
if(!ent.startsWith("_")){
|
|
265
432
|
if(!entity[ent].foreignKey){
|
|
266
|
-
if(
|
|
267
|
-
|
|
268
|
-
entitiesList.push(`'${entity[ent].relationshipTable}'`);
|
|
269
|
-
}
|
|
270
|
-
else{
|
|
271
|
-
entitiesList.push(entity[ent].relationshipTable);
|
|
272
|
-
}
|
|
433
|
+
if($that.chechUnsupportedWords(ent)){
|
|
434
|
+
entitiesList.push(`'${ent}'`);
|
|
273
435
|
}
|
|
274
436
|
else{
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
}
|
|
437
|
+
entitiesList.push(ent);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
else{
|
|
441
|
+
if(entity[ent].type === 'belongsTo'){
|
|
442
|
+
entitiesList.push(`${entity[ent].foreignKey}`);
|
|
281
443
|
}
|
|
282
444
|
}
|
|
283
445
|
}
|
|
@@ -311,16 +473,39 @@ class SQLLiteEngine {
|
|
|
311
473
|
var $that = this;
|
|
312
474
|
var argument = null;
|
|
313
475
|
var dirtyFields = model.__dirtyFields;
|
|
314
|
-
|
|
476
|
+
|
|
315
477
|
for (var column in dirtyFields) {
|
|
478
|
+
|
|
316
479
|
// TODO Boolean value is a string with a letter
|
|
317
480
|
switch(model.__entity[dirtyFields[column]].type){
|
|
318
|
-
|
|
481
|
+
case "integer" :
|
|
482
|
+
//model.__entity[dirtyFields[column]].skipGetFunction = true;
|
|
319
483
|
argument = argument === null ? `[${dirtyFields[column]}] = ${model[dirtyFields[column]]},` : `${argument} [${dirtyFields[column]}] = ${model[dirtyFields[column]]},`;
|
|
484
|
+
//model.__entity[dirtyFields[column]].skipGetFunction = false;
|
|
320
485
|
break;
|
|
321
486
|
case "string" :
|
|
322
487
|
argument = argument === null ? `[${dirtyFields[column]}] = '${$that._santizeSingleQuotes(model[dirtyFields[column]])}',` : `${argument} [${dirtyFields[column]}] = '${$that._santizeSingleQuotes(model[dirtyFields[column]])}',`;
|
|
323
488
|
break;
|
|
489
|
+
case "boolean" :
|
|
490
|
+
var bool = "";
|
|
491
|
+
if(model.__entity[dirtyFields[column]].valueConversion){
|
|
492
|
+
bool = tools.convertBooleanToNumber(model[dirtyFields[column]]);
|
|
493
|
+
}
|
|
494
|
+
else{
|
|
495
|
+
bool = model[dirtyFields[column]];
|
|
496
|
+
}
|
|
497
|
+
argument = argument === null ? `[${dirtyFields[column]}] = '${bool}',` : `${argument} [${dirtyFields[column]}] = ${bool},`;
|
|
498
|
+
break;
|
|
499
|
+
case "time" :
|
|
500
|
+
argument = argument === null ? `[${dirtyFields[column]}] = '${model[dirtyFields[column]]}',` : `${argument} [${dirtyFields[column]}] = ${model[dirtyFields[column]]},`;
|
|
501
|
+
break;
|
|
502
|
+
case "belongsTo" :
|
|
503
|
+
var fore = `_${dirtyFields[column]}`;
|
|
504
|
+
argument = argument === null ? `[${model.__entity[dirtyFields[column]].foreignKey}] = '${model[fore]}',` : `${argument} [${model.__entity[dirtyFields[column]].foreignKey}] = '${model[fore]}',`;
|
|
505
|
+
break;
|
|
506
|
+
case "hasMany" :
|
|
507
|
+
argument = argument === null ? `[${dirtyFields[column]}] = '${model[dirtyFields[column]]}',` : `${argument} [${dirtyFields[column]}] = '${model[dirtyFields[column]]}',`;
|
|
508
|
+
break;
|
|
324
509
|
default:
|
|
325
510
|
argument = argument === null ? `[${dirtyFields[column]}] = '${model[dirtyFields[column]]}',` : `${argument} [${dirtyFields[column]}] = '${model[dirtyFields[column]]}',`;
|
|
326
511
|
}
|
|
@@ -353,7 +538,7 @@ class SQLLiteEngine {
|
|
|
353
538
|
if((fieldColumn !== undefined && fieldColumn !== null && fieldColumn !== "" ) && typeof(fieldColumn) !== "object"){
|
|
354
539
|
switch(modelEntity[column].type){
|
|
355
540
|
case "belongsTo" :
|
|
356
|
-
column = modelEntity[column].
|
|
541
|
+
column = modelEntity[column].foreignKey === undefined ? column : modelEntity[column].foreignKey;
|
|
357
542
|
break;
|
|
358
543
|
case "string" :
|
|
359
544
|
fieldColumn = `'${$that._santizeSingleQuotes(fields[column])}'`;
|
|
@@ -367,6 +552,24 @@ class SQLLiteEngine {
|
|
|
367
552
|
values = values === null ? `${fieldColumn},` : `${values} ${fieldColumn},`;
|
|
368
553
|
|
|
369
554
|
}
|
|
555
|
+
else{
|
|
556
|
+
switch(modelEntity[column].type){
|
|
557
|
+
case "belongsTo" :
|
|
558
|
+
var fieldObject = tools.findTrackedObject(fields.__context.__trackedEntities, column );
|
|
559
|
+
if( Object.keys(fieldObject).length > 0){
|
|
560
|
+
var primaryKey = tools.getPrimaryKeyObject(fieldObject.__entity);
|
|
561
|
+
fieldColumn = fieldObject[primaryKey];
|
|
562
|
+
column = modelEntity[column].foreignKey;
|
|
563
|
+
columns = columns === null ? `'${column}',` : `${columns} '${column}',`;
|
|
564
|
+
values = values === null ? `${fieldColumn},` : `${values} ${fieldColumn},`;
|
|
565
|
+
}else{
|
|
566
|
+
console.log("Cannot find belings to relationship")
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
break;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
}
|
|
370
573
|
}
|
|
371
574
|
}
|
|
372
575
|
return {tableName: modelEntity.__name, columns: columns.replace(/,\s*$/, ""), values: values.replace(/,\s*$/, "")};
|
|
@@ -375,7 +578,13 @@ class SQLLiteEngine {
|
|
|
375
578
|
|
|
376
579
|
// will add double single quotes to allow sting to be saved.
|
|
377
580
|
_santizeSingleQuotes(string){
|
|
378
|
-
|
|
581
|
+
if (typeof string === 'string' || string instanceof String){
|
|
582
|
+
return string.replace(/'/g, "''");
|
|
583
|
+
}
|
|
584
|
+
else{
|
|
585
|
+
console.log("warning - Field being passed is not a string");
|
|
586
|
+
throw "warning - Field being passed is not a string";
|
|
587
|
+
}
|
|
379
588
|
}
|
|
380
589
|
|
|
381
590
|
// converts any object into SQL parameter select string
|
|
@@ -406,4 +615,4 @@ class SQLLiteEngine {
|
|
|
406
615
|
}
|
|
407
616
|
}
|
|
408
617
|
|
|
409
|
-
module.exports =
|
|
618
|
+
module.exports = postgresEngine;
|