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
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
// version 1.0.1
|
|
2
|
+
|
|
3
|
+
const LOG_OPERATORS_REGEX = /(\|\|)|(&&)/;
|
|
4
|
+
var tools = require('../Tools');
|
|
5
|
+
|
|
6
|
+
class queryScript{
|
|
7
|
+
|
|
8
|
+
constructor(){ }
|
|
9
|
+
|
|
10
|
+
script = {
|
|
11
|
+
select : false,
|
|
12
|
+
where: false,
|
|
13
|
+
include : [],
|
|
14
|
+
raw: false,
|
|
15
|
+
entity : "",
|
|
16
|
+
entityMap : []
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
reset(){
|
|
21
|
+
this.script = {
|
|
22
|
+
select : false,
|
|
23
|
+
where: false,
|
|
24
|
+
include : [],
|
|
25
|
+
raw: false,
|
|
26
|
+
entity : "",
|
|
27
|
+
entityMap : []
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
getScript(){
|
|
32
|
+
return this.script;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
raw(query){
|
|
36
|
+
this.script.raw = query;
|
|
37
|
+
return this.script;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
where(text, entityName){
|
|
41
|
+
this.buildScript(text, "where", this.script, entityName);
|
|
42
|
+
return this.script;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
include(text, entityName){
|
|
46
|
+
this.buildScript(text, "include", this.script, entityName);
|
|
47
|
+
return this.script;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
select(text, entityName){
|
|
51
|
+
this.buildScript(text, "select", this.script, entityName);
|
|
52
|
+
return this.script;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
count(queryString){
|
|
56
|
+
var matched = queryString.match(/(?<=select)(.*?)from/gmi );
|
|
57
|
+
matched[0] = matched[0].replace("from", "");
|
|
58
|
+
var cleanQuery = queryString.replace(/^(.*?)from/gmi, "");
|
|
59
|
+
var str = `Select Count(${matched[0]}) from ${cleanQuery}`
|
|
60
|
+
|
|
61
|
+
return str;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
buildScript(text, type, obj, entityName){
|
|
65
|
+
|
|
66
|
+
var groups = this.splitByFunctions(text);
|
|
67
|
+
var cachedExpr = {}; // this function will just get the high leve
|
|
68
|
+
if(groups.length > 0){
|
|
69
|
+
|
|
70
|
+
cachedExpr.entity = this.getEntity(text);
|
|
71
|
+
|
|
72
|
+
if(!this.isMapped(entityName, obj.entityMap)){
|
|
73
|
+
|
|
74
|
+
obj.entityMap.push({
|
|
75
|
+
name: entityName,
|
|
76
|
+
entity : cachedExpr.entity
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
obj.entity = cachedExpr.entity
|
|
80
|
+
//tools.getRandomLetter(1)
|
|
81
|
+
cachedExpr[entityName] = this.splitGroupsByLogicalOperators(groups);
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
// lets break the string into a list of functions
|
|
85
|
+
this.buildFields(text, cachedExpr);
|
|
86
|
+
|
|
87
|
+
if(type === "include"){
|
|
88
|
+
if(cachedExpr.selectFields){
|
|
89
|
+
if(!this.isMapped(cachedExpr.selectFields[0], obj.entityMap)){
|
|
90
|
+
obj.entityMap.push({
|
|
91
|
+
name: tools.capitalizeFirstLetter(cachedExpr.selectFields[0]),
|
|
92
|
+
entity : tools.getRandomLetter(1, obj.entityMap)
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
this.describeExpressionParts(cachedExpr[entityName], cachedExpr.selectFields[0], obj.entityMap);
|
|
99
|
+
if(type === "include"){
|
|
100
|
+
obj[type].push(cachedExpr)
|
|
101
|
+
}
|
|
102
|
+
else{
|
|
103
|
+
obj[type] = cachedExpr;
|
|
104
|
+
}
|
|
105
|
+
obj.parentName = entityName;
|
|
106
|
+
return cachedExpr;
|
|
107
|
+
|
|
108
|
+
}
|
|
109
|
+
else{
|
|
110
|
+
// this means cachedExpr is not formated as: a => a
|
|
111
|
+
if(type === "select"){
|
|
112
|
+
obj.select = {
|
|
113
|
+
"selectFields": JSON.parse(text)
|
|
114
|
+
}
|
|
115
|
+
return obj.select;
|
|
116
|
+
}
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
buildFields(text, desc){
|
|
123
|
+
var match = text.match(/^([\w\d$_]+?)\s*=>((?:\{\sreturn\s)?[\s\S]*(?:\})?)/);
|
|
124
|
+
if(match){
|
|
125
|
+
const entity = match[1];
|
|
126
|
+
let exprStr = match[2];
|
|
127
|
+
const fields = [];
|
|
128
|
+
|
|
129
|
+
exprStr.replace(new RegExp(entity + "\\.([\\w_]+)", "g"), function (_, field) {
|
|
130
|
+
if (!fields.includes(field)) fields.push(field);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
desc.expr = exprStr.trim()
|
|
134
|
+
desc.selectFields = fields
|
|
135
|
+
return desc;
|
|
136
|
+
}
|
|
137
|
+
else{
|
|
138
|
+
return null;
|
|
139
|
+
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
MATCH_ENTITY_REGEXP(entityName) {
|
|
144
|
+
return new RegExp("(^|[^\\w\\d])" + entityName + "[ \\.\\)]");
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
OPERATORS_REGEX(entityName){
|
|
148
|
+
return new RegExp("(?:^|[^\\w\\d])" + entityName
|
|
149
|
+
+ "\\.((?:\\.?[\\w\\d_\\$]+)+)(?:\\((.*?)\\))?(?:\\s*(>|<|(?:===)|(?:!==)|(?:==)|(?:!=)|(?:=)|(?:<=)|(?:>=)|(?:in))\\s*(.*))?")
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
splitGroupsByLogicalOperators(groups, nested = false) {
|
|
153
|
+
let parts = {}, tmp;
|
|
154
|
+
for (let part of groups) {
|
|
155
|
+
|
|
156
|
+
//tmp = this.splitByLogicalOperators(part.query, entityRegExp)
|
|
157
|
+
tmp = this.extractInside(part.query, part.name);
|
|
158
|
+
if(tmp){
|
|
159
|
+
part.inside = tmp;
|
|
160
|
+
parts[part.name] = part;
|
|
161
|
+
}
|
|
162
|
+
else{
|
|
163
|
+
part.inside = part.query;
|
|
164
|
+
parts[part.name] = part;
|
|
165
|
+
}
|
|
166
|
+
part.inside = part.inside.replace("&&", "and");
|
|
167
|
+
part.query = part.query.replace("&&", "and");
|
|
168
|
+
part.inside = part.inside.replace("||", "or");
|
|
169
|
+
part.query = part.query.replace("||", "or");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return parts;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
splitByFunctions(str) {
|
|
177
|
+
const regex = /(?<=\.(?=[A-z]+\())([^(]+)\((.+?)\)(?!\))/g;
|
|
178
|
+
let m;
|
|
179
|
+
const items = [];
|
|
180
|
+
while ((m = regex.exec(str)) !== null) {
|
|
181
|
+
// This is necessary to avoid infinite loops with zero-width matches
|
|
182
|
+
if (m.index === regex.lastIndex) {
|
|
183
|
+
regex.lastIndex++;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const [, fName, query] = m;
|
|
187
|
+
items.push(
|
|
188
|
+
{name: fName, query: `${fName}(${query})`}
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
if(items.length === 0){
|
|
192
|
+
items.push({name: "NOFUNCTIONS", query: str})
|
|
193
|
+
}
|
|
194
|
+
return items;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
describeExpressionParts(parts, parentField, entityMap) {
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
for (let item in parts) {
|
|
202
|
+
let match, fields, func, arg;
|
|
203
|
+
var part = parts[item];
|
|
204
|
+
part.expressions = [];
|
|
205
|
+
var partQuery = part.inside;
|
|
206
|
+
var entity = this.getEntity(partQuery);
|
|
207
|
+
var exprPartRegExp = this.OPERATORS_REGEX(entity);
|
|
208
|
+
// check if query contains an AND.
|
|
209
|
+
var splitByAnd = partQuery.split("and");
|
|
210
|
+
for (let splitAnds in splitByAnd) {
|
|
211
|
+
|
|
212
|
+
if (match = splitByAnd[splitAnds].match(exprPartRegExp)) {
|
|
213
|
+
fields = match[1].split(".");
|
|
214
|
+
func = (match[2] ? fields[fields.length - 1] : (match[3] || "exists"));
|
|
215
|
+
|
|
216
|
+
if (func == "==" || func == "===") {
|
|
217
|
+
func = "=";
|
|
218
|
+
}
|
|
219
|
+
else if (func == "!==") {
|
|
220
|
+
func = "!=";
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
arg = match[2] || match[4];
|
|
224
|
+
if (arg == "true" || arg == "false") {
|
|
225
|
+
arg = arg == "true";
|
|
226
|
+
}
|
|
227
|
+
else if (arg && arg.charAt(0) == arg.charAt(arg.length - 1) && (arg.charAt(0) == "'" || arg.charAt(0) == '"')) {
|
|
228
|
+
arg = arg.slice(1, -1);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
part.entity = entity;
|
|
232
|
+
if(this.isFunction(part.name)){
|
|
233
|
+
var scriptInner = {
|
|
234
|
+
include : [],
|
|
235
|
+
entityMap : entityMap
|
|
236
|
+
};
|
|
237
|
+
this.buildScript(part.inside, part.name, scriptInner, parentField, true);
|
|
238
|
+
parts.parentName = scriptInner.parentName;
|
|
239
|
+
part[scriptInner.parentName] = {};
|
|
240
|
+
if(part.name === "where"){
|
|
241
|
+
part.parentName = scriptInner.parentName;
|
|
242
|
+
part.entity = scriptInner.where.entity;
|
|
243
|
+
part.expr = scriptInner.where.expr;
|
|
244
|
+
part.selectFields = scriptInner.where.selectFields;
|
|
245
|
+
part[scriptInner.parentName] = scriptInner.where[scriptInner.parentName];
|
|
246
|
+
}
|
|
247
|
+
if(part.name === "include"){
|
|
248
|
+
part.parentName = scriptInner.parentName;
|
|
249
|
+
part.entity = scriptInner.include.entity;
|
|
250
|
+
part.expr = scriptInner.include.expr;
|
|
251
|
+
part.selectFields = scriptInner.include.selectFields;
|
|
252
|
+
part[scriptInner.parentName] = scriptInner.include[scriptInner.parentName];
|
|
253
|
+
|
|
254
|
+
}
|
|
255
|
+
if(part.name === "select"){
|
|
256
|
+
part.parentName = scriptInner.parentName;
|
|
257
|
+
part.entity = scriptInner.select.entity;
|
|
258
|
+
part.expr = scriptInner.select.expr;
|
|
259
|
+
part.selectFields = scriptInner.select.selectFields;
|
|
260
|
+
part[scriptInner.parentName] = scriptInner.select[scriptInner.parentName];
|
|
261
|
+
}
|
|
262
|
+
//part.inner = scriptInner;
|
|
263
|
+
}
|
|
264
|
+
else{
|
|
265
|
+
part.expressions.push({
|
|
266
|
+
field: fields[0],
|
|
267
|
+
func : func.toLowerCase(),
|
|
268
|
+
arg : arg
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return parts;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
getEntity(str){
|
|
281
|
+
var clean = str.replace(/\s/g, '');
|
|
282
|
+
return clean.substring(0, 1);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
isMapped(name, maps){
|
|
286
|
+
for (let item in maps) {
|
|
287
|
+
var map = maps[item];
|
|
288
|
+
if(tools.capitalizeFirstLetter(name) === map.name){
|
|
289
|
+
return true
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
//const res1 = extractInside(`User.include(a => a.Profile.where(r => r.name.startWith(i))).single()`, 'where');
|
|
296
|
+
// const res2 = extractInside(`User.include(a => a.Profile.select(r => r.name === "rick")).single()`, 'select');
|
|
297
|
+
extractInside(str, fname) {
|
|
298
|
+
if(this.isFunction(fname)){
|
|
299
|
+
const startIndex = str.indexOf(fname) + fname.length;
|
|
300
|
+
const stack = [];
|
|
301
|
+
for (let i = startIndex; i < str.length; i++) {
|
|
302
|
+
if(str[i] === '(') {
|
|
303
|
+
stack.push(str[i]);
|
|
304
|
+
|
|
305
|
+
} else if (str[i] === ')') {
|
|
306
|
+
stack.pop();
|
|
307
|
+
}
|
|
308
|
+
if(stack.length === 0) {
|
|
309
|
+
return str.substring(startIndex+1, i);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return str;
|
|
313
|
+
}
|
|
314
|
+
else{
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
isFunction(func){
|
|
320
|
+
var funcList = ["where", "select", "include"]
|
|
321
|
+
for(var i =0; i < funcList.length; i++){
|
|
322
|
+
if(funcList[i] === func){
|
|
323
|
+
return true
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return false;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
module.exports = queryScript;
|