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,386 +1,386 @@
1
-
2
- var Expression = require("masterrecord/Expression");
3
- // TODO: support for MySQL and Postgres Comming
4
- /// TODO: Adding a ! ads not to the query
5
-
6
- // IDEAS
7
- // https://stackoverflow.com/questions/10455414/with-entity-framework-is-it-better-to-use-first-or-take1-for-top-1
8
-
9
- // NEXT VERSION ADD LAMBDA SUPPORT
10
-
11
-
12
- class QueryLanguage{
13
- constructor(model, modelName, context) {
14
- this.__info__ = {};
15
- this.__info__.context = context;
16
- this.__info__.sexpress = new Expression();
17
- this.__info__.name = modelName;
18
- this.__info__.model = model;
19
- this.__info__.selectFields = [];
20
- this.__info__.orders = [];
21
- this.__info__.groups = [];
22
- this.__info__.where = [];
23
- this.__info__.joins = [];
24
- this.__info__.skipValue = null;
25
- this.__info__.except = null;
26
- this.__info__.limitValue = null;
27
-
28
- }
29
-
30
- skip(amount){
31
- /*
32
-
33
- SELECT Name,
34
- ProductNumber,
35
- StandardCost
36
- FROM Production.Product
37
- ORDER BY StandardCost
38
- OFFSET 10 ROWS
39
- FETCH NEXT 10 ROWS ONLY
40
-
41
- // You can use OFFSET without FETCH, but FETCH can’t be used by itself.
42
- // Regardless, OFFSET must be used with an ORDER BY clause.
43
- // The reason is simple as OFFSET and FETCH are part of the ORDER BY clause
44
-
45
- */
46
- let skip = Math.floor(amount);
47
- if (skip < 0) {
48
- throw new Error("Negative values are not allowed.");
49
- }
50
- this.__info__.skipValue = skip === 0 ? null : skip;
51
- return this;
52
- }
53
-
54
- take(amount){
55
- // SELECT * FROM Table ORDER BY ID DESC LIMIT AMOUNT
56
- let take = Math.floor(amount);
57
- if (take < 0) {
58
- throw new Error("Negative values are not allowed.");
59
- }
60
- this.__info__.limitValue = take === 0 ? null : take;
61
- return this;
62
- }
63
-
64
- last(exp){
65
- // SELECT * FROM Table ORDER BY ID DESC LIMIT 1
66
- const expr = this.__info__.sexpress.matchExpression(exp); // will return selectFields
67
- this.__info__.orders.push({ name: "LAST", func: expr.selectFields + " DESC", arg: "DESC" });
68
- this.__info__.limitValue = 1;
69
- return this;
70
- }
71
-
72
- orderByDescending(expr){
73
- // SELECT * FROM Table ORDER BY ID DESC
74
- const expr = this.__info__.sexpress.matchExpression(exp);
75
- this.__info__.orders.push({ name: "DESC", func: expr.selectFields + " DESC", arg: "DESC" });
76
- return this;
77
- }
78
-
79
- orderBy(expr){
80
- // SELECT * FROM Table ORDER BY ID ASC
81
- const expr = this.__info__.sexpress.matchExpression(exp);
82
- this.__info__.orders.push({ name: "ORDER BY", func:"ORDER BY " + expr.selectFields + " ASC", arg: "ASC" });
83
- return this;
84
- }
85
-
86
- groupBy(exp){
87
- /*
88
- SELECT column_name(s)
89
- FROM table_name
90
- WHERE condition
91
- GROUP BY column1, column2
92
- ORDER BY column_name(s);
93
- */
94
- const expr = this.__info__.sexpress.matchExpression(exp);
95
- this.__info__.groups.push({name: "GROUP BY", func:"GROUP BY " + expr.selectFields + " ASC", order: "ASC" });
96
- return this;
97
- }
98
-
99
- union(expr){
100
- // https://www.tabsoverspaces.com/233043-union-and-concat-in-linq-to-entities
101
- // https://weblogs.asp.net/dixin/entity-framework-core-and-linq-to-entities-4-query-methods
102
- }
103
-
104
- find(id){
105
- // Select * where id = "yaho"
106
- this.__info__.where.push({ ame: "ID", func: "ID = " + id, arg: "=" , value: id});
107
- return this;
108
- }
109
-
110
- where(exp, ...args){
111
- // TODO: MUST PARSE CONTAINS AND LIKE FUNCTIONS
112
- //https://github.com/Hookyns/unimapperjs/blob/master/src/Query.js;
113
- this.__info__.sexpress.addExpression(exp, ...args);
114
- var where = this.__info__.sexpress.whereArgs;
115
- var conditions = this.__info__.sexpress.conditions
116
- return this;
117
- }
118
-
119
- except(exp){
120
- /*
121
- The SQL EXCEPT clause/operator is used to combine two SELECT statements and returns rows
122
- from the first SELECT statement that are not returned by the second SELECT statement
123
- This means EXCEPT returns only rows, which are not available in the second SELECT statement.
124
- */
125
-
126
- /*
127
- SELECT ID, NAME, AMOUNT, DATE
128
- FROM CUSTOMERS
129
- LEFT JOIN ORDERS
130
- ON CUSTOMERS.ID = ORDERS.CUSTOMER_ID
131
- EXCEPT
132
- SELECT ID, NAME, AMOUNT, DATE
133
- FROM CUSTOMERS
134
- RIGHT JOIN ORDERS
135
- ON CUSTOMERS.ID = ORDERS.CUSTOMER_ID;
136
- */
137
- this.__info__.except = this.__info__.sexpress.matchExpression(exp);
138
- return this;
139
- }
140
-
141
- any(exp, ...args){
142
- // https://stackoverflow.com/questions/12429185/linq-to-entities-any-vs-first-vs-exists
143
- // checks is this expression exist
144
- // this.__info__.where = null;
145
- // SELECT *
146
- // FROM customers
147
- // WHERE EXISTS (SELECT *
148
- // FROM order_details
149
- // WHERE customers.customer_id = order_details.customer_id);
150
-
151
- this.__info__.where = [{name: "EXISTS", func: "EXISTS(" + this.__info__.sexpress.addExpression(exp, ...args) + ")"}];
152
- return this;
153
-
154
- }
155
-
156
-
157
- //============================================================================================
158
- // ============================== */ Aggregate functions /* ===============================
159
- //============================================================================================
160
-
161
- // function returns the number of rows that matches a specified criteria.
162
- select(exp){
163
- // nested selects,
164
- // https://benjii.me/2018/01/expression-projection-magic-entity-framework-core/
165
-
166
- const expr = this.__info__.sexpress.initExpression(exp, this.__info__.model,this.__info__.name); // will return selectFields
167
- var entity = expr.entity;
168
-
169
- // loop through fields
170
- for (const field of expr.selectFields) {
171
- this.__info__.selectFields.push({func: "[" + entity + "]." + "[" + field + "]"});
172
- }
173
-
174
- for (const virtualObj of expr.virtualFields) {
175
- var nestedField = []
176
- // if context has many/collection of the field name the next item after context should be an arg
177
- // if context has on of the field it's not a collection then the next field should be a field of context.
178
- var virtualObjff = this.__info__.sexpress.getContext(virtualObj, this.__info__.context);
179
- // virtualObjff returns the next item with the context
180
- // todo does it pass the rule
181
- if(virtualObjff.type === "collection"){
182
- // next item should be an argument
183
- // TODO: this will create a new instance of query language and call all its arguments and return context values.
184
- var nestedInstance = this.__info__.sexpress.nestedQueryBuilder(virtualObjff);
185
- nestedField.push(nestedInstance);
186
- // or throw an error
187
-
188
- }
189
- else{
190
- // TODO: run loop aagain and build nested objects
191
- }
192
- var name = "";
193
- }
194
-
195
- // TODO : all nested fields of that specific context should have an argument on the next call
196
-
197
- // TODO:
198
- // loop through virtualFields
199
- // create new object using the virtual name
200
- // if it doesn't exist then throw error
201
- // then get the next element on the string
202
-
203
- // check if the next element is a field of that context.
204
- // if not then check if its a nested object
205
- // if its not a nested object and not field then throw error
206
- // if it is then call that object with the inner expression.
207
- // if it is a field then get the next element after that
208
-
209
- // then check if the element is a nested arguments
210
- // if it is then get the inside of that string and pass it to the nested arguemnt
211
- // then run build query
212
- // return that query and add it the select fields func name.
213
- // loop through nestedFields
214
-
215
- return this;
216
- }
217
-
218
- distinct(){
219
- // SELECT DISTINCT
220
- this.__info__.selectFields.push({name: "DISTINCT", func: "DISTINCT", arg: ""});
221
- return this;
222
- }
223
-
224
- count(columnName){
225
- // todo: if columnName not added put *
226
- // SELECT COUNT(column_name)
227
- this.__info__.selectFields.push({ name: "COUNT", func: "COUNT(" + columnName + ")", arg: columnName});
228
- return this;
229
- }
230
-
231
- // function returns the average value of a numeric column.
232
- average(columnName){
233
- // SELECT AVG(column_name)
234
- this.__info__.selectFields.push({ name: "AVG", func: "AVG(" + columnName + ")", arg: columnName});
235
- return this;
236
- }
237
-
238
- // function returns the total sum of a numeric column.
239
- sum(columnName){
240
- // SELECT SUM(column_name)
241
- this.__info__.selectFields.push({ name: "SUM", func: "SUM(" + columnName + ")", arg: columnName});
242
- return this;
243
- }
244
-
245
- // function returns the largest value of the selected column.
246
- max(columnName){
247
- //SELECT MAX(column_name)
248
- this.__info__.selectFields.push({ name: "MAX", func: "MAX(" + columnName + ")", arg: columnName});
249
- return this;
250
- }
251
-
252
- // function returns the smallest value of the selected column.
253
- min(columnName){
254
- // SELECT MIN(column_name)
255
- this.__info__.selectFields.push({ name: "MIN", func: "MIN(" + columnName + ")", arg: columnName});
256
- return this;
257
- }
258
-
259
-
260
- //============================================================================================
261
- // ============================== */ Join functions /* ===============================
262
- //============================================================================================
263
-
264
- join(tableName, primaryKeyExp, foreignKeyExp ){
265
- // SELECT Orders.OrderID, Customers.CustomerName, Orders.OrderDate
266
- // FROM Orders
267
- // INNER JOIN Customers ON Orders.CustomerID=Customers.CustomerID;
268
- const primaryKeyExpr = this.__info__.sexpress.matchExpression(primaryKeyExp);
269
- const ForeignKeyExpr = this.__info__.sexpress.matchExpression(foreignKeyExp);
270
-
271
- this.__info__.joins.push({ func: "JOIN", arg:{primaryKeyExpr : primaryKeyExpr, ForeignKeyExpr: ForeignKeyExpr} });
272
- // RETURNS AN ARRAY OBJECTS
273
- // [{
274
- // FIRSTNAME: RICHARD,
275
- // NICKNAME : JAMES
276
- // },
277
- // {
278
- // FIRSTNAME: ROBERT,
279
- // NICKNAME : ALEX
280
- // }]
281
- return this;
282
- }
283
-
284
- groupJoin(tableName, primaryKeyExp, foreignKeyExp ){
285
- // https://sqlzoo.net/wiki/The_JOIN_operation
286
- //https://arnhem.luminis.eu/linq-and-entity-framework-some-dos-and-donts/
287
- //IMPORTANT https://weblogs.thinktecture.com/pawel/2018/04/entity-framework-core-performance-beware-of-n1-queries.html
288
- // SELECT Orders.OrderID, Customers.CustomerName, Orders.OrderDate
289
- // FROM Orders
290
- // INNER JOIN Customers ON Orders.CustomerID=Customers.CustomerID;
291
- const primaryKeyExpr = this.__info__.sexpress.matchExpression(primaryKeyExp);
292
- const ForeignKeyExpr = this.__info__.sexpress.matchExpression(foreignKeyExp);
293
-
294
- this.__info__.joins.push({ func: "GROUPJOIN", arg:{primaryKeyExpr : primaryKeyExpr, ForeignKeyExpr: ForeignKeyExpr} });
295
- // https://stackoverflow.com/questions/15595289/linq-to-entities-join-vs-groupjoin
296
- // RETURNS AN ARRAY OF GROUPED ARRAYS OBJECTS BY WHATEVER PRIMARY KEY YOU USED
297
- // [
298
- //[{
299
- // FIRSTNAME: RICHARD,
300
- // NICKNAME : JAMES
301
- // }
302
- //],
303
- // [{
304
- // FIRSTNAME: ROBERT,
305
- // NICKNAME : ALEX
306
- // }]
307
- // ]
308
- return this;
309
- }
310
-
311
- //============================================================================================
312
- // ============================== */ trigger will make call /* ===============================
313
- //============================================================================================
314
-
315
- // Anything that returns a concrete object or data structure
316
- // (Count, Sum Single, First, ToList, ToArray, etc.) is evaluated immediately, so
317
- // SingleOrDefault certainly does.
318
-
319
- // Anything that returns an IQueryable<T> (Select, GroupBy, Take) will be deferred
320
- // (so that operations can be chained), so Queryable.Union will be deferred.
321
-
322
- // Anything that returns an IEnumerable<T> will also be deferred, but subsequent queries
323
- // will be done in Linq-to-objects, so subsequent operations
324
- // won't be translated to SQL. (Empty is an exception since there's not really
325
- // anything to defer - it just returns an empty collection)
326
-
327
- // Entity Framework
328
- // SqlQuery
329
-
330
-
331
- // THESE ARE RETURN TYPES METHOD'S: these dont return this;
332
- // ToArray does the exact thing as tolist just syntax suger.
333
- // ToDictionary(kvp => kvp.Key, kvp => kvp.Value) // this will turn it into an object literal with column name and value.
334
- // ToList<TSource> return array list
335
- // single // return a single object literal.
336
-
337
- // https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/ef/language-reference/supported-and-unsupported-linq-methods-linq-to-entities
338
- toArray(){
339
- // TODO: run query and parse results
340
- }
341
-
342
- toDictionary(){
343
- // TODO: run query and parse results
344
- }
345
-
346
- toList(){
347
- // TODO: run query and parse results
348
-
349
-
350
- }
351
-
352
- single(){
353
- // TODO: run query and parse results
354
- }
355
-
356
- }
357
-
358
-
359
- module.exports = QueryLanguage;
360
-
361
-
362
- // this.trigger = function(queryName, query){
363
- // let queryString = "";
364
- // switch(queryName) {
365
- // case "count":
366
- // queryString += query;
367
- // break;
368
- // case undefined:
369
- // queryString += `SELECT ${this.name}.* FROM ${this.name}`;
370
- // break;
371
-
372
- // }
373
-
374
- // for (var i = 0; i < this.query.length; i++) {
375
- // queryString += " " + this.query[i];
376
- // }
377
-
378
- // var select = selectColumns(this._model);
379
- // // TODO: COMBINE THIS_MODEL WITH THE MODEL THAT IS BEING RETURNED
380
- // // loop though model
381
- // //
382
- // var qq = "select "+ select +" "+query;
383
- // var data = Masterrecord.db.prepare(qq).get();
384
- // return callGets(data, this._model);
385
-
1
+
2
+ var Expression = require("masterrecord/Expression");
3
+ // TODO: support for MySQL and Postgres Comming
4
+ /// TODO: Adding a ! ads not to the query
5
+
6
+ // IDEAS
7
+ // https://stackoverflow.com/questions/10455414/with-entity-framework-is-it-better-to-use-first-or-take1-for-top-1
8
+
9
+ // NEXT VERSION ADD LAMBDA SUPPORT
10
+
11
+
12
+ class QueryLanguage{
13
+ constructor(model, modelName, context) {
14
+ this.__info__ = {};
15
+ this.__info__.context = context;
16
+ this.__info__.sexpress = new Expression();
17
+ this.__info__.name = modelName;
18
+ this.__info__.model = model;
19
+ this.__info__.selectFields = [];
20
+ this.__info__.orders = [];
21
+ this.__info__.groups = [];
22
+ this.__info__.where = [];
23
+ this.__info__.joins = [];
24
+ this.__info__.skipValue = null;
25
+ this.__info__.except = null;
26
+ this.__info__.limitValue = null;
27
+
28
+ }
29
+
30
+ skip(amount){
31
+ /*
32
+
33
+ SELECT Name,
34
+ ProductNumber,
35
+ StandardCost
36
+ FROM Production.Product
37
+ ORDER BY StandardCost
38
+ OFFSET 10 ROWS
39
+ FETCH NEXT 10 ROWS ONLY
40
+
41
+ // You can use OFFSET without FETCH, but FETCH can’t be used by itself.
42
+ // Regardless, OFFSET must be used with an ORDER BY clause.
43
+ // The reason is simple as OFFSET and FETCH are part of the ORDER BY clause
44
+
45
+ */
46
+ let skip = Math.floor(amount);
47
+ if (skip < 0) {
48
+ throw new Error("Negative values are not allowed.");
49
+ }
50
+ this.__info__.skipValue = skip === 0 ? null : skip;
51
+ return this;
52
+ }
53
+
54
+ take(amount){
55
+ // SELECT * FROM Table ORDER BY ID DESC LIMIT AMOUNT
56
+ let take = Math.floor(amount);
57
+ if (take < 0) {
58
+ throw new Error("Negative values are not allowed.");
59
+ }
60
+ this.__info__.limitValue = take === 0 ? null : take;
61
+ return this;
62
+ }
63
+
64
+ last(exp){
65
+ // SELECT * FROM Table ORDER BY ID DESC LIMIT 1
66
+ const expr = this.__info__.sexpress.matchExpression(exp); // will return selectFields
67
+ this.__info__.orders.push({ name: "LAST", func: expr.selectFields + " DESC", arg: "DESC" });
68
+ this.__info__.limitValue = 1;
69
+ return this;
70
+ }
71
+
72
+ orderByDescending(expr){
73
+ // SELECT * FROM Table ORDER BY ID DESC
74
+ const expr = this.__info__.sexpress.matchExpression(exp);
75
+ this.__info__.orders.push({ name: "DESC", func: expr.selectFields + " DESC", arg: "DESC" });
76
+ return this;
77
+ }
78
+
79
+ orderBy(expr){
80
+ // SELECT * FROM Table ORDER BY ID ASC
81
+ const expr = this.__info__.sexpress.matchExpression(exp);
82
+ this.__info__.orders.push({ name: "ORDER BY", func:"ORDER BY " + expr.selectFields + " ASC", arg: "ASC" });
83
+ return this;
84
+ }
85
+
86
+ groupBy(exp){
87
+ /*
88
+ SELECT column_name(s)
89
+ FROM table_name
90
+ WHERE condition
91
+ GROUP BY column1, column2
92
+ ORDER BY column_name(s);
93
+ */
94
+ const expr = this.__info__.sexpress.matchExpression(exp);
95
+ this.__info__.groups.push({name: "GROUP BY", func:"GROUP BY " + expr.selectFields + " ASC", order: "ASC" });
96
+ return this;
97
+ }
98
+
99
+ union(expr){
100
+ // https://www.tabsoverspaces.com/233043-union-and-concat-in-linq-to-entities
101
+ // https://weblogs.asp.net/dixin/entity-framework-core-and-linq-to-entities-4-query-methods
102
+ }
103
+
104
+ find(id){
105
+ // Select * where id = "yaho"
106
+ this.__info__.where.push({ ame: "ID", func: "ID = " + id, arg: "=" , value: id});
107
+ return this;
108
+ }
109
+
110
+ where(exp, ...args){
111
+ // TODO: MUST PARSE CONTAINS AND LIKE FUNCTIONS
112
+ //https://github.com/Hookyns/unimapperjs/blob/master/src/Query.js;
113
+ this.__info__.sexpress.addExpression(exp, ...args);
114
+ var where = this.__info__.sexpress.whereArgs;
115
+ var conditions = this.__info__.sexpress.conditions
116
+ return this;
117
+ }
118
+
119
+ except(exp){
120
+ /*
121
+ The SQL EXCEPT clause/operator is used to combine two SELECT statements and returns rows
122
+ from the first SELECT statement that are not returned by the second SELECT statement
123
+ This means EXCEPT returns only rows, which are not available in the second SELECT statement.
124
+ */
125
+
126
+ /*
127
+ SELECT ID, NAME, AMOUNT, DATE
128
+ FROM CUSTOMERS
129
+ LEFT JOIN ORDERS
130
+ ON CUSTOMERS.ID = ORDERS.CUSTOMER_ID
131
+ EXCEPT
132
+ SELECT ID, NAME, AMOUNT, DATE
133
+ FROM CUSTOMERS
134
+ RIGHT JOIN ORDERS
135
+ ON CUSTOMERS.ID = ORDERS.CUSTOMER_ID;
136
+ */
137
+ this.__info__.except = this.__info__.sexpress.matchExpression(exp);
138
+ return this;
139
+ }
140
+
141
+ any(exp, ...args){
142
+ // https://stackoverflow.com/questions/12429185/linq-to-entities-any-vs-first-vs-exists
143
+ // checks is this expression exist
144
+ // this.__info__.where = null;
145
+ // SELECT *
146
+ // FROM customers
147
+ // WHERE EXISTS (SELECT *
148
+ // FROM order_details
149
+ // WHERE customers.customer_id = order_details.customer_id);
150
+
151
+ this.__info__.where = [{name: "EXISTS", func: "EXISTS(" + this.__info__.sexpress.addExpression(exp, ...args) + ")"}];
152
+ return this;
153
+
154
+ }
155
+
156
+
157
+ //============================================================================================
158
+ // ============================== */ Aggregate functions /* ===============================
159
+ //============================================================================================
160
+
161
+ // function returns the number of rows that matches a specified criteria.
162
+ select(exp){
163
+ // nested selects,
164
+ // https://benjii.me/2018/01/expression-projection-magic-entity-framework-core/
165
+
166
+ const expr = this.__info__.sexpress.initExpression(exp, this.__info__.model,this.__info__.name); // will return selectFields
167
+ var entity = expr.entity;
168
+
169
+ // loop through fields
170
+ for (const field of expr.selectFields) {
171
+ this.__info__.selectFields.push({func: "[" + entity + "]." + "[" + field + "]"});
172
+ }
173
+
174
+ for (const virtualObj of expr.virtualFields) {
175
+ var nestedField = []
176
+ // if context has many/collection of the field name the next item after context should be an arg
177
+ // if context has on of the field it's not a collection then the next field should be a field of context.
178
+ var virtualObjff = this.__info__.sexpress.getContext(virtualObj, this.__info__.context);
179
+ // virtualObjff returns the next item with the context
180
+ // todo does it pass the rule
181
+ if(virtualObjff.type === "collection"){
182
+ // next item should be an argument
183
+ // TODO: this will create a new instance of query language and call all its arguments and return context values.
184
+ var nestedInstance = this.__info__.sexpress.nestedQueryBuilder(virtualObjff);
185
+ nestedField.push(nestedInstance);
186
+ // or throw an error
187
+
188
+ }
189
+ else{
190
+ // TODO: run loop aagain and build nested objects
191
+ }
192
+ var name = "";
193
+ }
194
+
195
+ // TODO : all nested fields of that specific context should have an argument on the next call
196
+
197
+ // TODO:
198
+ // loop through virtualFields
199
+ // create new object using the virtual name
200
+ // if it doesn't exist then throw error
201
+ // then get the next element on the string
202
+
203
+ // check if the next element is a field of that context.
204
+ // if not then check if its a nested object
205
+ // if its not a nested object and not field then throw error
206
+ // if it is then call that object with the inner expression.
207
+ // if it is a field then get the next element after that
208
+
209
+ // then check if the element is a nested arguments
210
+ // if it is then get the inside of that string and pass it to the nested arguemnt
211
+ // then run build query
212
+ // return that query and add it the select fields func name.
213
+ // loop through nestedFields
214
+
215
+ return this;
216
+ }
217
+
218
+ distinct(){
219
+ // SELECT DISTINCT
220
+ this.__info__.selectFields.push({name: "DISTINCT", func: "DISTINCT", arg: ""});
221
+ return this;
222
+ }
223
+
224
+ count(columnName){
225
+ // todo: if columnName not added put *
226
+ // SELECT COUNT(column_name)
227
+ this.__info__.selectFields.push({ name: "COUNT", func: "COUNT(" + columnName + ")", arg: columnName});
228
+ return this;
229
+ }
230
+
231
+ // function returns the average value of a numeric column.
232
+ average(columnName){
233
+ // SELECT AVG(column_name)
234
+ this.__info__.selectFields.push({ name: "AVG", func: "AVG(" + columnName + ")", arg: columnName});
235
+ return this;
236
+ }
237
+
238
+ // function returns the total sum of a numeric column.
239
+ sum(columnName){
240
+ // SELECT SUM(column_name)
241
+ this.__info__.selectFields.push({ name: "SUM", func: "SUM(" + columnName + ")", arg: columnName});
242
+ return this;
243
+ }
244
+
245
+ // function returns the largest value of the selected column.
246
+ max(columnName){
247
+ //SELECT MAX(column_name)
248
+ this.__info__.selectFields.push({ name: "MAX", func: "MAX(" + columnName + ")", arg: columnName});
249
+ return this;
250
+ }
251
+
252
+ // function returns the smallest value of the selected column.
253
+ min(columnName){
254
+ // SELECT MIN(column_name)
255
+ this.__info__.selectFields.push({ name: "MIN", func: "MIN(" + columnName + ")", arg: columnName});
256
+ return this;
257
+ }
258
+
259
+
260
+ //============================================================================================
261
+ // ============================== */ Join functions /* ===============================
262
+ //============================================================================================
263
+
264
+ join(tableName, primaryKeyExp, foreignKeyExp ){
265
+ // SELECT Orders.OrderID, Customers.CustomerName, Orders.OrderDate
266
+ // FROM Orders
267
+ // INNER JOIN Customers ON Orders.CustomerID=Customers.CustomerID;
268
+ const primaryKeyExpr = this.__info__.sexpress.matchExpression(primaryKeyExp);
269
+ const ForeignKeyExpr = this.__info__.sexpress.matchExpression(foreignKeyExp);
270
+
271
+ this.__info__.joins.push({ func: "JOIN", arg:{primaryKeyExpr : primaryKeyExpr, ForeignKeyExpr: ForeignKeyExpr} });
272
+ // RETURNS AN ARRAY OBJECTS
273
+ // [{
274
+ // FIRSTNAME: RICHARD,
275
+ // NICKNAME : JAMES
276
+ // },
277
+ // {
278
+ // FIRSTNAME: ROBERT,
279
+ // NICKNAME : ALEX
280
+ // }]
281
+ return this;
282
+ }
283
+
284
+ groupJoin(tableName, primaryKeyExp, foreignKeyExp ){
285
+ // https://sqlzoo.net/wiki/The_JOIN_operation
286
+ //https://arnhem.luminis.eu/linq-and-entity-framework-some-dos-and-donts/
287
+ //IMPORTANT https://weblogs.thinktecture.com/pawel/2018/04/entity-framework-core-performance-beware-of-n1-queries.html
288
+ // SELECT Orders.OrderID, Customers.CustomerName, Orders.OrderDate
289
+ // FROM Orders
290
+ // INNER JOIN Customers ON Orders.CustomerID=Customers.CustomerID;
291
+ const primaryKeyExpr = this.__info__.sexpress.matchExpression(primaryKeyExp);
292
+ const ForeignKeyExpr = this.__info__.sexpress.matchExpression(foreignKeyExp);
293
+
294
+ this.__info__.joins.push({ func: "GROUPJOIN", arg:{primaryKeyExpr : primaryKeyExpr, ForeignKeyExpr: ForeignKeyExpr} });
295
+ // https://stackoverflow.com/questions/15595289/linq-to-entities-join-vs-groupjoin
296
+ // RETURNS AN ARRAY OF GROUPED ARRAYS OBJECTS BY WHATEVER PRIMARY KEY YOU USED
297
+ // [
298
+ //[{
299
+ // FIRSTNAME: RICHARD,
300
+ // NICKNAME : JAMES
301
+ // }
302
+ //],
303
+ // [{
304
+ // FIRSTNAME: ROBERT,
305
+ // NICKNAME : ALEX
306
+ // }]
307
+ // ]
308
+ return this;
309
+ }
310
+
311
+ //============================================================================================
312
+ // ============================== */ trigger will make call /* ===============================
313
+ //============================================================================================
314
+
315
+ // Anything that returns a concrete object or data structure
316
+ // (Count, Sum Single, First, ToList, ToArray, etc.) is evaluated immediately, so
317
+ // SingleOrDefault certainly does.
318
+
319
+ // Anything that returns an IQueryable<T> (Select, GroupBy, Take) will be deferred
320
+ // (so that operations can be chained), so Queryable.Union will be deferred.
321
+
322
+ // Anything that returns an IEnumerable<T> will also be deferred, but subsequent queries
323
+ // will be done in Linq-to-objects, so subsequent operations
324
+ // won't be translated to SQL. (Empty is an exception since there's not really
325
+ // anything to defer - it just returns an empty collection)
326
+
327
+ // Entity Framework
328
+ // SqlQuery
329
+
330
+
331
+ // THESE ARE RETURN TYPES METHOD'S: these dont return this;
332
+ // ToArray does the exact thing as tolist just syntax suger.
333
+ // ToDictionary(kvp => kvp.Key, kvp => kvp.Value) // this will turn it into an object literal with column name and value.
334
+ // ToList<TSource> return array list
335
+ // single // return a single object literal.
336
+
337
+ // https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/ef/language-reference/supported-and-unsupported-linq-methods-linq-to-entities
338
+ toArray(){
339
+ // TODO: run query and parse results
340
+ }
341
+
342
+ toDictionary(){
343
+ // TODO: run query and parse results
344
+ }
345
+
346
+ toList(){
347
+ // TODO: run query and parse results
348
+
349
+
350
+ }
351
+
352
+ single(){
353
+ // TODO: run query and parse results
354
+ }
355
+
356
+ }
357
+
358
+
359
+ module.exports = QueryLanguage;
360
+
361
+
362
+ // this.trigger = function(queryName, query){
363
+ // let queryString = "";
364
+ // switch(queryName) {
365
+ // case "count":
366
+ // queryString += query;
367
+ // break;
368
+ // case undefined:
369
+ // queryString += `SELECT ${this.name}.* FROM ${this.name}`;
370
+ // break;
371
+
372
+ // }
373
+
374
+ // for (var i = 0; i < this.query.length; i++) {
375
+ // queryString += " " + this.query[i];
376
+ // }
377
+
378
+ // var select = selectColumns(this._model);
379
+ // // TODO: COMBINE THIS_MODEL WITH THE MODEL THAT IS BEING RETURNED
380
+ // // loop though model
381
+ // //
382
+ // var qq = "select "+ select +" "+query;
383
+ // var data = Masterrecord.db.prepare(qq).get();
384
+ // return callGets(data, this._model);
385
+
386
386
  // }