masterrecord 0.0.23 → 0.0.24

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.
@@ -1,322 +1,322 @@
1
- // TODO: EXPRESSION WILL HAVE METHODS THAT WILL CONVERT EXPRESIONS TO SYNTAX TREE
2
- // TODO: THEN WE WILL TURN THAT EXPRESSION SYNTEX TREE INTO SQLENGINE OBJECTS
3
- // TODO: THE SQL ENGINE WILL THEN CONVERT THAT TO RAW SQL
4
- // TODO: THEN THE RAW SQL WILL BE PUSHED TO SQL DATABASE
5
- // TODO: ON RETURN THE OBJECT WILL PARSED USING THE ENTITY PARSER
6
- // TODO: THE ENTITY WILL THEN BE TRACKED FOR ANY CHANGES
7
-
8
- // EXAMPLE: https://www.npmjs.com/package/@rduk/expression
9
- // EXAMPLE : https://goranhrovat.github.io/linqify/index.html
10
- // LIST OF C# METHODS : https://medium.com/@aikeru/a-c-linq-to-javascript-translation-guide-6e1558fc1905
11
-
12
-
13
-
14
-
15
- var MATCH_EXPR_REGEX = /^([\w\d$_]+?)\s*=>((?:\{\sreturn\s)?[\s\S]*(?:\})?)/;
16
- const LOG_OPERATORS_REGEX = /(\|\|)|(&&)/;
17
- const SPLIT_GROUP_REGEX = /(^|\||&| )\(/;
18
- const REGEX_CACHE = {};
19
-
20
-
21
- // ON INIT we convert the expression into an object literal with strings
22
- // then we loop through each object in the object literal.
23
- // we grab the value/key of the row
24
- // we remove the entity so that only the query is left
25
- // we while loop through each string broken by a DOT
26
- // we run string through a rule checker
27
- // is it a field in the current entity
28
- // if so add it to selectField
29
- // is it an argument
30
- // run it through the nestedQuery Instance
31
- // is it a nested field
32
- // if so get type collection or single
33
- // create new instance of query language
34
- // run it through some rule checker
35
- // if its a collection the next string item should be an argument
36
- // then call the nested query language instance argument.
37
- // if its a single then the next must be a field of that model including another nested field
38
- // if its a reguler field then add it the select nested field
39
-
40
- function describeExpressionParts(parts, exprPartRegExp) {
41
- let result = [], match, desc, fields, func, arg;
42
- for (let part of parts) {
43
- if (part.constructor == Array) {
44
- result.push(describeExpressionParts(part, exprPartRegExp));
45
- }
46
- else {
47
- if (part == "and" || part == "or") {
48
- result.push(part);
49
- }
50
- else if (match = part.match(exprPartRegExp)) {
51
- fields = match[1].split(".");
52
- func = (match[2] ? fields[fields.length - 1] : (match[3] || "exists"));
53
- if (func == "==" || func == "===") {
54
- func = "=";
55
- }
56
- else if (func == "!==") {
57
- func = "!=";
58
- }
59
- arg = match[2] || match[4];
60
- if (arg == "true" || arg == "false") {
61
- arg = arg == "true";
62
- }
63
- else if (arg && arg.charAt(0) == arg.charAt(arg.length - 1) && (arg.charAt(0) == "'" || arg.charAt(0) == '"')) {
64
- arg = arg.slice(1, -1);
65
- }
66
- desc = {
67
- field: (match[2] ? fields.slice(0, -1) : fields).join("."),
68
- func: func.toLowerCase(),
69
- arg: arg
70
- };
71
- result.push(desc);
72
- }
73
- }
74
- }
75
- return result;
76
- }
77
-
78
- function splitByLogicalOperators(str, entityRegExp) {
79
- let operatorIndex, parts = [], part;
80
- while ((operatorIndex = str.search(LOG_OPERATORS_REGEX)) != -1) {
81
- part = str.slice(0, operatorIndex).trim();
82
- // Check if this part is relevant for query -> contains entity variable
83
- // -> if it do nothing with entity, it shouldn't be in query eg. 1 == 1
84
- if (entityRegExp.test(part)) {
85
- parts.push(part);
86
- }
87
- parts.push(str.charAt(operatorIndex) == "|" ? "or" : "and");
88
- str = str.slice(operatorIndex + 2);
89
- }
90
- if (str.length > 0 && entityRegExp.test(str)) {
91
- parts.push(str);
92
- }
93
- return parts;
94
- }
95
-
96
- function splitGroupsByLogicalOperators(groups, entityRegExp, nested = false) {
97
- let parts = [], tmp;
98
- for (let part of groups) {
99
- if (part.constructor == Array) {
100
- tmp = splitGroupsByLogicalOperators(part, entityRegExp, true);
101
- if (tmp.length) {
102
- parts.push(tmp);
103
- }
104
- }
105
- else {
106
- tmp = splitByLogicalOperators(part, entityRegExp);
107
- if (tmp) {
108
- parts = parts.concat(tmp);
109
- }
110
- }
111
- }
112
- // Check if there are some doubled logical operators after removing irelevant parts
113
- for (let i = 0; i < parts.length; i++) {
114
- if ((parts[i] == "and" || parts[i] == "or") && (parts[i + 1] == "and" || parts[i + 1] == "or")) {
115
- parts.splice(i, 1);
116
- i--;
117
- }
118
- }
119
- const last = parts[parts.length - 1];
120
- // Remove operators at end of group
121
- if (last == "or" || last == "and") {
122
- parts = parts.slice(0, -1);
123
- }
124
- // If it's only one part, return that part; but returned value must be always array
125
- if (parts.length == 1 && (nested || parts[0].constructor == Array)) {
126
- return parts[0];
127
- }
128
- return parts;
129
- }
130
-
131
- function splitByGroups(expr) {
132
- const parts = [];
133
- let bracketIndex, end, offset = 0, opening, closing, char;
134
- let part = expr;
135
- while ((bracketIndex = part.search(SPLIT_GROUP_REGEX)) != -1) {
136
- // Search FIX - match symbol before bracket
137
- if (bracketIndex != 0 || part.charAt(0) != "(") {
138
- bracketIndex++;
139
- }
140
- // Count brackets -> find ending bracket
141
- opening = 1;
142
- closing = 0;
143
- offset = bracketIndex + 1;
144
- while (opening != closing && offset < part.length) {
145
- char = part.charAt(offset);
146
- if (char == "(") {
147
- opening++;
148
- }
149
- else if (char == ")")
150
- closing++;
151
- offset++;
152
- }
153
- if (opening != closing) {
154
- throw new Error("Expression has unclosed bracket");
155
- }
156
- parts.push(part.slice(0, bracketIndex).trim());
157
- end = offset - 1;
158
- // Find nested groups
159
- parts.push(splitByGroups(part.slice(bracketIndex + 1, end).trim()));
160
- part = part.slice(end + 1).trim();
161
- }
162
- if (parts.length == 0) {
163
- parts.push(expr);
164
- }
165
- return parts;
166
- }
167
-
168
- function getEntityRegExps(entityName) {
169
- let REGEXPS = REGEX_CACHE[entityName];
170
- if (!REGEXPS) {
171
- REGEX_CACHE[entityName] = REGEXPS = {
172
- MATCH_ENTITY_REGEXP: new RegExp("(^|[^\\w\\d])" + entityName + "[ \\.\\)]"),
173
- OPERATORS_REGEX: new RegExp("(?:^|[^\\w\\d])" + entityName
174
- + "\\.((?:\\.?[\\w\\d_\\$]+)+)(?:\\((.*?)\\))?(?:\\s*(>|<|(?:===)|(?:!==)|(?:==)|(?:!=)|(?:<=)|(?:>=)|(?:in))\\s*(.*))?")
175
- };
176
- }
177
- return REGEXPS;
178
- }
179
-
180
- function convertWhereExpr(expr) {
181
- const exprs = expr.expr;
182
- const { MATCH_ENTITY_REGEXP, OPERATORS_REGEX } = getEntityRegExps(expr.entity);
183
- const groups = splitByGroups(exprs);
184
- const parts = splitGroupsByLogicalOperators(groups, MATCH_ENTITY_REGEXP);
185
- expr.desc = describeExpressionParts(parts, OPERATORS_REGEX);
186
- return expr;
187
- }
188
-
189
- class Expression{
190
-
191
- constructor(){
192
- /**
193
- * List of conditions
194
- * @private
195
- */
196
- this.conditions = [];
197
- /**
198
- * List of filter arguments
199
- * @private
200
- */
201
- this.whereArgs = [];
202
- }
203
-
204
- addExpression(expression, ...args) {
205
-
206
- const conexpr = this.matchExpression(expression);
207
- const expr = convertWhereExpr(conexpr);
208
- // If some coditions already exists, add this WHERE as AND
209
- if (this.conditions.length != 0) {
210
- expr.desc.unshift("and");
211
- }
212
- this.whereArgs = this.whereArgs.concat(args);
213
- this.conditions = this.conditions.concat(expr.desc);
214
- }
215
-
216
- // adds the context to virtual obj
217
- getContext(virtualObj, contexts){
218
-
219
- // virtual model: type, field and arg
220
- var build = this.buildExpObject(virtualObj.func);
221
- var foundContext = false;
222
- for (var context of contexts) {
223
- if(context.name === virtualObj.name){
224
- build.context = new context();
225
- foundContext = true;
226
- }
227
- }
228
-
229
- if(foundContext === false){
230
- throw new Error(virtualObj.name + " is not a model name in dbset");
231
- }
232
-
233
- return build;
234
- }
235
-
236
- // builds an object from an expression
237
- buildExpObject(stringExpression){
238
- return {
239
- name :stringExpression.match(new RegExp("^([^.]+)", "g"))[0],
240
- func : stringExpression.replace(new RegExp("^([^.]+)", "g"), "").replace(/^\./, ""),
241
- arg: "grab the inside of the name"
242
- }
243
- }
244
-
245
- initExpression(expr, model, modelName) {
246
-
247
- const str = expr.toString();
248
- var that = this;
249
- if (str[str.length - 1] == "}") {
250
- throw new Error("Parameter expr must be simple arrow function.")
251
- }
252
-
253
- if (str[0] === "(") {
254
- throw new Error("Use arrow function without brackets around parameter.");
255
- }
256
-
257
- const match = str.match(MATCH_EXPR_REGEX);
258
-
259
- if (!match) {
260
- throw new Error("Invalid expression");
261
- }
262
-
263
- const entity = match[1];
264
- let exprStr = match[2];
265
-
266
- const fields = [];
267
- const virtualFields = [];
268
- const nestedFields = [];
269
- // var regex = new RegExp(entity + "\\.([\\w_]+)", "g");
270
- var regexString = "(?<=:\\" + entity + ")([^,}]*)";
271
- var regex = new RegExp(regexString, "g");
272
- exprStr.replace(regex, function (_, field) {
273
-
274
- // remove the entity from string
275
- var fieldExp = field.replace(/(\/\*[^*]*\*\/)|(\/\/[^*]*)/g, '').replace(new RegExp("^(" + entity + "\.)", "g"), "").trim();
276
- var fieldObj = that.buildExpObject(fieldExp);
277
- const keys = Object.keys(model);
278
- var keyNotFound = false;
279
- for (const key of keys) {
280
- if(fieldObj.name === model[key].name){
281
- keyNotFound = true;
282
- if(model[key].virtual === true){
283
- // check is vitual is a single or collection one to one or one to many or many to many
284
- var modelKeyType;
285
- if(model[key].hasMany !== undefined){
286
- modelKeyType = "collection";
287
- }else{
288
- modelKeyType = "single";
289
- }
290
- fieldObj.type = modelKeyType;
291
- virtualFields.push(fieldObj); // we will do a left outer join
292
-
293
- }
294
- else{
295
- // if arg has no text then that means there is no nested values
296
- if(fieldObj.func === ""){
297
- if (!fields.includes(fieldObj.name)) fields.push(fieldObj.name);
298
- }else{
299
- nestedFields.push(fieldObj);
300
- }
301
-
302
- }
303
- }
304
- }
305
- if(keyNotFound === false){
306
- throw new Error(fieldObj.name + " is not apart of " + modelName);
307
- }
308
- });
309
-
310
- let cachedExpr = {
311
- entity: entity,
312
- expr: exprStr.trim(),
313
- selectFields: fields,
314
- virtualFields : virtualFields,
315
- nestedFields : nestedFields
316
- };
317
-
318
-
319
- return cachedExpr;
320
- };
321
- }
1
+ // TODO: EXPRESSION WILL HAVE METHODS THAT WILL CONVERT EXPRESIONS TO SYNTAX TREE
2
+ // TODO: THEN WE WILL TURN THAT EXPRESSION SYNTEX TREE INTO SQLENGINE OBJECTS
3
+ // TODO: THE SQL ENGINE WILL THEN CONVERT THAT TO RAW SQL
4
+ // TODO: THEN THE RAW SQL WILL BE PUSHED TO SQL DATABASE
5
+ // TODO: ON RETURN THE OBJECT WILL PARSED USING THE ENTITY PARSER
6
+ // TODO: THE ENTITY WILL THEN BE TRACKED FOR ANY CHANGES
7
+
8
+ // EXAMPLE: https://www.npmjs.com/package/@rduk/expression
9
+ // EXAMPLE : https://goranhrovat.github.io/linqify/index.html
10
+ // LIST OF C# METHODS : https://medium.com/@aikeru/a-c-linq-to-javascript-translation-guide-6e1558fc1905
11
+
12
+
13
+
14
+
15
+ var MATCH_EXPR_REGEX = /^([\w\d$_]+?)\s*=>((?:\{\sreturn\s)?[\s\S]*(?:\})?)/;
16
+ const LOG_OPERATORS_REGEX = /(\|\|)|(&&)/;
17
+ const SPLIT_GROUP_REGEX = /(^|\||&| )\(/;
18
+ const REGEX_CACHE = {};
19
+
20
+
21
+ // ON INIT we convert the expression into an object literal with strings
22
+ // then we loop through each object in the object literal.
23
+ // we grab the value/key of the row
24
+ // we remove the entity so that only the query is left
25
+ // we while loop through each string broken by a DOT
26
+ // we run string through a rule checker
27
+ // is it a field in the current entity
28
+ // if so add it to selectField
29
+ // is it an argument
30
+ // run it through the nestedQuery Instance
31
+ // is it a nested field
32
+ // if so get type collection or single
33
+ // create new instance of query language
34
+ // run it through some rule checker
35
+ // if its a collection the next string item should be an argument
36
+ // then call the nested query language instance argument.
37
+ // if its a single then the next must be a field of that model including another nested field
38
+ // if its a reguler field then add it the select nested field
39
+
40
+ function describeExpressionParts(parts, exprPartRegExp) {
41
+ let result = [], match, desc, fields, func, arg;
42
+ for (let part of parts) {
43
+ if (part.constructor == Array) {
44
+ result.push(describeExpressionParts(part, exprPartRegExp));
45
+ }
46
+ else {
47
+ if (part == "and" || part == "or") {
48
+ result.push(part);
49
+ }
50
+ else if (match = part.match(exprPartRegExp)) {
51
+ fields = match[1].split(".");
52
+ func = (match[2] ? fields[fields.length - 1] : (match[3] || "exists"));
53
+ if (func == "==" || func == "===") {
54
+ func = "=";
55
+ }
56
+ else if (func == "!==") {
57
+ func = "!=";
58
+ }
59
+ arg = match[2] || match[4];
60
+ if (arg == "true" || arg == "false") {
61
+ arg = arg == "true";
62
+ }
63
+ else if (arg && arg.charAt(0) == arg.charAt(arg.length - 1) && (arg.charAt(0) == "'" || arg.charAt(0) == '"')) {
64
+ arg = arg.slice(1, -1);
65
+ }
66
+ desc = {
67
+ field: (match[2] ? fields.slice(0, -1) : fields).join("."),
68
+ func: func.toLowerCase(),
69
+ arg: arg
70
+ };
71
+ result.push(desc);
72
+ }
73
+ }
74
+ }
75
+ return result;
76
+ }
77
+
78
+ function splitByLogicalOperators(str, entityRegExp) {
79
+ let operatorIndex, parts = [], part;
80
+ while ((operatorIndex = str.search(LOG_OPERATORS_REGEX)) != -1) {
81
+ part = str.slice(0, operatorIndex).trim();
82
+ // Check if this part is relevant for query -> contains entity variable
83
+ // -> if it do nothing with entity, it shouldn't be in query eg. 1 == 1
84
+ if (entityRegExp.test(part)) {
85
+ parts.push(part);
86
+ }
87
+ parts.push(str.charAt(operatorIndex) == "|" ? "or" : "and");
88
+ str = str.slice(operatorIndex + 2);
89
+ }
90
+ if (str.length > 0 && entityRegExp.test(str)) {
91
+ parts.push(str);
92
+ }
93
+ return parts;
94
+ }
95
+
96
+ function splitGroupsByLogicalOperators(groups, entityRegExp, nested = false) {
97
+ let parts = [], tmp;
98
+ for (let part of groups) {
99
+ if (part.constructor == Array) {
100
+ tmp = splitGroupsByLogicalOperators(part, entityRegExp, true);
101
+ if (tmp.length) {
102
+ parts.push(tmp);
103
+ }
104
+ }
105
+ else {
106
+ tmp = splitByLogicalOperators(part, entityRegExp);
107
+ if (tmp) {
108
+ parts = parts.concat(tmp);
109
+ }
110
+ }
111
+ }
112
+ // Check if there are some doubled logical operators after removing irelevant parts
113
+ for (let i = 0; i < parts.length; i++) {
114
+ if ((parts[i] == "and" || parts[i] == "or") && (parts[i + 1] == "and" || parts[i + 1] == "or")) {
115
+ parts.splice(i, 1);
116
+ i--;
117
+ }
118
+ }
119
+ const last = parts[parts.length - 1];
120
+ // Remove operators at end of group
121
+ if (last == "or" || last == "and") {
122
+ parts = parts.slice(0, -1);
123
+ }
124
+ // If it's only one part, return that part; but returned value must be always array
125
+ if (parts.length == 1 && (nested || parts[0].constructor == Array)) {
126
+ return parts[0];
127
+ }
128
+ return parts;
129
+ }
130
+
131
+ function splitByGroups(expr) {
132
+ const parts = [];
133
+ let bracketIndex, end, offset = 0, opening, closing, char;
134
+ let part = expr;
135
+ while ((bracketIndex = part.search(SPLIT_GROUP_REGEX)) != -1) {
136
+ // Search FIX - match symbol before bracket
137
+ if (bracketIndex != 0 || part.charAt(0) != "(") {
138
+ bracketIndex++;
139
+ }
140
+ // Count brackets -> find ending bracket
141
+ opening = 1;
142
+ closing = 0;
143
+ offset = bracketIndex + 1;
144
+ while (opening != closing && offset < part.length) {
145
+ char = part.charAt(offset);
146
+ if (char == "(") {
147
+ opening++;
148
+ }
149
+ else if (char == ")")
150
+ closing++;
151
+ offset++;
152
+ }
153
+ if (opening != closing) {
154
+ throw new Error("Expression has unclosed bracket");
155
+ }
156
+ parts.push(part.slice(0, bracketIndex).trim());
157
+ end = offset - 1;
158
+ // Find nested groups
159
+ parts.push(splitByGroups(part.slice(bracketIndex + 1, end).trim()));
160
+ part = part.slice(end + 1).trim();
161
+ }
162
+ if (parts.length == 0) {
163
+ parts.push(expr);
164
+ }
165
+ return parts;
166
+ }
167
+
168
+ function getEntityRegExps(entityName) {
169
+ let REGEXPS = REGEX_CACHE[entityName];
170
+ if (!REGEXPS) {
171
+ REGEX_CACHE[entityName] = REGEXPS = {
172
+ MATCH_ENTITY_REGEXP: new RegExp("(^|[^\\w\\d])" + entityName + "[ \\.\\)]"),
173
+ OPERATORS_REGEX: new RegExp("(?:^|[^\\w\\d])" + entityName
174
+ + "\\.((?:\\.?[\\w\\d_\\$]+)+)(?:\\((.*?)\\))?(?:\\s*(>|<|(?:===)|(?:!==)|(?:==)|(?:!=)|(?:<=)|(?:>=)|(?:in))\\s*(.*))?")
175
+ };
176
+ }
177
+ return REGEXPS;
178
+ }
179
+
180
+ function convertWhereExpr(expr) {
181
+ const exprs = expr.expr;
182
+ const { MATCH_ENTITY_REGEXP, OPERATORS_REGEX } = getEntityRegExps(expr.entity);
183
+ const groups = splitByGroups(exprs);
184
+ const parts = splitGroupsByLogicalOperators(groups, MATCH_ENTITY_REGEXP);
185
+ expr.desc = describeExpressionParts(parts, OPERATORS_REGEX);
186
+ return expr;
187
+ }
188
+
189
+ class Expression{
190
+
191
+ constructor(){
192
+ /**
193
+ * List of conditions
194
+ * @private
195
+ */
196
+ this.conditions = [];
197
+ /**
198
+ * List of filter arguments
199
+ * @private
200
+ */
201
+ this.whereArgs = [];
202
+ }
203
+
204
+ addExpression(expression, ...args) {
205
+
206
+ const conexpr = this.matchExpression(expression);
207
+ const expr = convertWhereExpr(conexpr);
208
+ // If some coditions already exists, add this WHERE as AND
209
+ if (this.conditions.length != 0) {
210
+ expr.desc.unshift("and");
211
+ }
212
+ this.whereArgs = this.whereArgs.concat(args);
213
+ this.conditions = this.conditions.concat(expr.desc);
214
+ }
215
+
216
+ // adds the context to virtual obj
217
+ getContext(virtualObj, contexts){
218
+
219
+ // virtual model: type, field and arg
220
+ var build = this.buildExpObject(virtualObj.func);
221
+ var foundContext = false;
222
+ for (var context of contexts) {
223
+ if(context.name === virtualObj.name){
224
+ build.context = new context();
225
+ foundContext = true;
226
+ }
227
+ }
228
+
229
+ if(foundContext === false){
230
+ throw new Error(virtualObj.name + " is not a model name in dbset");
231
+ }
232
+
233
+ return build;
234
+ }
235
+
236
+ // builds an object from an expression
237
+ buildExpObject(stringExpression){
238
+ return {
239
+ name :stringExpression.match(new RegExp("^([^.]+)", "g"))[0],
240
+ func : stringExpression.replace(new RegExp("^([^.]+)", "g"), "").replace(/^\./, ""),
241
+ arg: "grab the inside of the name"
242
+ }
243
+ }
244
+
245
+ initExpression(expr, model, modelName) {
246
+
247
+ const str = expr.toString();
248
+ var that = this;
249
+ if (str[str.length - 1] == "}") {
250
+ throw new Error("Parameter expr must be simple arrow function.")
251
+ }
252
+
253
+ if (str[0] === "(") {
254
+ throw new Error("Use arrow function without brackets around parameter.");
255
+ }
256
+
257
+ const match = str.match(MATCH_EXPR_REGEX);
258
+
259
+ if (!match) {
260
+ throw new Error("Invalid expression");
261
+ }
262
+
263
+ const entity = match[1];
264
+ let exprStr = match[2];
265
+
266
+ const fields = [];
267
+ const virtualFields = [];
268
+ const nestedFields = [];
269
+ // var regex = new RegExp(entity + "\\.([\\w_]+)", "g");
270
+ var regexString = "(?<=:\\" + entity + ")([^,}]*)";
271
+ var regex = new RegExp(regexString, "g");
272
+ exprStr.replace(regex, function (_, field) {
273
+
274
+ // remove the entity from string
275
+ var fieldExp = field.replace(/(\/\*[^*]*\*\/)|(\/\/[^*]*)/g, '').replace(new RegExp("^(" + entity + "\.)", "g"), "").trim();
276
+ var fieldObj = that.buildExpObject(fieldExp);
277
+ const keys = Object.keys(model);
278
+ var keyNotFound = false;
279
+ for (const key of keys) {
280
+ if(fieldObj.name === model[key].name){
281
+ keyNotFound = true;
282
+ if(model[key].virtual === true){
283
+ // check is vitual is a single or collection one to one or one to many or many to many
284
+ var modelKeyType;
285
+ if(model[key].hasMany !== undefined){
286
+ modelKeyType = "collection";
287
+ }else{
288
+ modelKeyType = "single";
289
+ }
290
+ fieldObj.type = modelKeyType;
291
+ virtualFields.push(fieldObj); // we will do a left outer join
292
+
293
+ }
294
+ else{
295
+ // if arg has no text then that means there is no nested values
296
+ if(fieldObj.func === ""){
297
+ if (!fields.includes(fieldObj.name)) fields.push(fieldObj.name);
298
+ }else{
299
+ nestedFields.push(fieldObj);
300
+ }
301
+
302
+ }
303
+ }
304
+ }
305
+ if(keyNotFound === false){
306
+ throw new Error(fieldObj.name + " is not apart of " + modelName);
307
+ }
308
+ });
309
+
310
+ let cachedExpr = {
311
+ entity: entity,
312
+ expr: exprStr.trim(),
313
+ selectFields: fields,
314
+ virtualFields : virtualFields,
315
+ nestedFields : nestedFields
316
+ };
317
+
318
+
319
+ return cachedExpr;
320
+ };
321
+ }
322
322
  module.exports = Expression;