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.
@@ -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;