masterrecord 0.0.24 → 0.0.26

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,171 @@
1
+ // ALL THIS SHOULD DO IS BUILD A SQL QUERY
2
+ // version 1.0.222
3
+ // TODO: change name of queryManager to select manager;
4
+ var entityTrackerModel = require('masterrecord/Entity/EntityTrackerModel');
5
+ var tools = require('masterrecord/Tools');
6
+ var queryScript = require('masterrecord/QueryLanguage/queryScript');
7
+
8
+ class queryMethods{
9
+
10
+ constructor(entity, context) {
11
+ this.__entity = entity;
12
+ this.__context = context;
13
+ this.__queryObject = new queryScript();
14
+ }
15
+
16
+ // build a single entity
17
+ __singleEntityBuilder(dataModel){
18
+ var $that = this;
19
+ if(dataModel){
20
+ var ent = new entityTrackerModel();
21
+ var mod = ent.build(dataModel, $that.__entity, $that.__context);
22
+ mod.__state = "track";
23
+ $that.__context.__track(mod);
24
+ return mod;
25
+ }else{
26
+ return null;
27
+ }
28
+ }
29
+
30
+ // build multiple entities
31
+ __multipleEntityBuilder(entityValue){
32
+ var $that = this;
33
+ var listArray = [];
34
+ if(entityValue){
35
+ for(let i = 0; i < entityValue.length; i++){
36
+ listArray.push($that.__singleEntityBuilder(entityValue[i]));
37
+ }
38
+ return listArray;
39
+ }else{
40
+ return null;
41
+ }
42
+ }
43
+
44
+ __reset(){
45
+ this.__queryObject.reset();
46
+ }
47
+
48
+ raw(query){
49
+
50
+ this.__queryObject.raw(query);
51
+ return this;
52
+ }
53
+
54
+ where(query, ...args){
55
+ var str = query.toString();
56
+ if(args){
57
+ for(let argument in args){
58
+ var item = args[argument];
59
+ str = str.replace("$$", item);
60
+ }
61
+ }
62
+ this.__queryObject.where(str, this.__entity.__name);
63
+ return this;
64
+ }
65
+
66
+ // when you dont want to use lazy loading and want it called at that moment
67
+ //Eagerly loading
68
+ include(query, ...args){
69
+ var str = query.toString();
70
+ if(args){
71
+ for(let argument in args){
72
+ var item = args[argument];
73
+ str = str.replace("$$", item);
74
+ }
75
+ }
76
+ this.__queryObject.include(str, this.__entity.__name);
77
+ return this;
78
+ }
79
+
80
+ // only takes a array of selected items
81
+ select(query, ...args){
82
+ var str = query.toString();
83
+ if(args){
84
+ for(let argument in args){
85
+ var item = args[argument];
86
+ str = str.replace("$$", item);
87
+ }
88
+ }
89
+ this.__queryObject.select(str, this.__entity.__name);
90
+ return this;
91
+ }
92
+
93
+
94
+
95
+ // do join on two tables = inner join
96
+ join(){
97
+
98
+ }
99
+
100
+ skip(){
101
+
102
+ }
103
+
104
+ limit(){
105
+
106
+ }
107
+
108
+ oderBy(){
109
+
110
+ }
111
+
112
+ groupBy(){
113
+
114
+ }
115
+
116
+ contains(){
117
+ // https://entityframework.net/knowledge-base/3491721/linq-to-entities---where-in-clause-in-query
118
+ }
119
+
120
+ count(){
121
+ // trying to match string select and relace with select Count(*);
122
+ var entityValue = this.__context._SQLEngine.getCount(this.__queryObject, this.__entity, this.__context);
123
+ var val = entityValue[Object.keys(entityValue)[0]];
124
+ this.__reset();
125
+ return val;
126
+ }
127
+
128
+ single(){
129
+ var entityValue = this.__context._SQLEngine.get(this.__queryObject.script, this.__entity, this.__context);
130
+ var sing = this.__singleEntityBuilder(entityValue, this._queryBuilder);
131
+ this.__reset();
132
+ return sing;
133
+ }
134
+
135
+ toList(){
136
+ var entityValue = this.__context._SQLEngine.all(this.__queryObject.script, this.__entity, this.__context);
137
+ var toLi = this.__multipleEntityBuilder(entityValue, this._queryBuilder);
138
+ this.__reset();
139
+ return toLi;
140
+ }
141
+
142
+ asQueryable(){
143
+ // returns the sql created and does not make a call to DB
144
+ }
145
+
146
+ add(entityValue){
147
+ // This will call context API to REMOVE entity to update list
148
+ tools.clearAllProto(entityValue);
149
+ entityValue.__state = "insert";
150
+ entityValue.__entity = this.__entity;
151
+ entityValue.__context = this.__context;
152
+ this.__context.__track(entityValue);
153
+ }
154
+
155
+ remove(entityValue){
156
+ entityValue.__state = "delete";
157
+ entityValue.__entity = this.__entity;
158
+ entityValue.__context = this.__context;
159
+ }
160
+
161
+ track(entityValue){
162
+ entityValue.__state = "track";
163
+ tools.clearAllProto(entityValue);
164
+ entityValue.__entity = this.__entity;
165
+ entityValue.__context = this.__context;
166
+ this.__context.__track(entityValue);
167
+ }
168
+ }
169
+
170
+ module.exports = queryMethods;
171
+
@@ -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;