total5 0.0.1 → 0.0.2

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,1220 @@
1
+ // Total.js QueryBuilder
2
+ // The MIT License
3
+ // Copyright 2023 (c) Peter Širka <petersirka@gmail.com>
4
+
5
+ const REG_FIELDS_CLEANER = /"|`|\||'|\s/g;
6
+
7
+ var LANGUAGE_SKIP = '_';
8
+ var LANGUAGE_PREFIX = '';
9
+
10
+ function QueryBuilderOptions() {}
11
+
12
+ function Controller(singleton) {
13
+ var t = this;
14
+ if (!singleton) {
15
+ t.commands = [];
16
+ t.response = {};
17
+ t.error = null;
18
+ setImmediate(t.next, t);
19
+ }
20
+ }
21
+
22
+ function DB(conn) {
23
+ var t = this;
24
+ t.conn = conn;
25
+ t.options = new QueryBuilderOptions();
26
+ // t.options.db = String; -- database/collection/table
27
+ // t.options.exec = String; -- operation name (find/insert/remove/etc..)
28
+ // t.options.payload = {};
29
+ // t.options.upsert = Boolean;
30
+ // t.options.fields = String Array;
31
+ // t.options.sort = String Array; -- in the form: field_asc, field_desc
32
+ // t.options.take = Number;
33
+ // t.options.skip = Number;
34
+ // t.options.filter = Object Array -- types: where/in/notin/or/between/contains/empty
35
+ t.options.filter = [];
36
+ }
37
+
38
+ function execdb(db) {
39
+ var conn = F.querybuilders[db.conn] || F.querybuilders['*'];
40
+ if (conn) {
41
+ if (db.options.checksum)
42
+ db.options.checksum = HASH(db.options.checksum).toString(36);
43
+ conn.call(db, db.options, (err, response) => db.evaluate(err, response));
44
+ } else
45
+ db.evaluate('Database is not initialized');
46
+ }
47
+
48
+ function QueryBuilder(main, table, exec) {
49
+
50
+ var t = this;
51
+
52
+ t.main = main;
53
+ t.options = main.options;
54
+ t.options.checksum = '';
55
+ t.options.table = table;
56
+ t.options.exec = exec;
57
+ t.filter = t.options.filter;
58
+
59
+ if (exec === 'list') {
60
+ t.options.skip = 0;
61
+ t.options.take = 100;
62
+ }
63
+
64
+ if (exec === 'read') {
65
+ t.options.take = 1;
66
+ t.options.first = true;
67
+ }
68
+
69
+ var ctrl = main.controller;
70
+
71
+ if (!ctrl.commands) {
72
+ setImmediate(execdb, main);
73
+ return;
74
+ }
75
+
76
+ if (ctrl.$debug)
77
+ t.options.debug = true;
78
+
79
+ if (ctrl.$end) {
80
+ ctrl.$end = false;
81
+ setImmediate(ctrl.next, ctrl);
82
+ }
83
+ }
84
+
85
+ var CTP = Controller.prototype;
86
+ var DBP = DB.prototype;
87
+ var QBP = QueryBuilder.prototype;
88
+
89
+ function parsedb(table) {
90
+ var index = table.indexOf('/');
91
+ return index === -1 ? { db: 'default', table: table } : { db: table.substring(0, index), table: table.substring(index + 1) };
92
+ }
93
+
94
+ CTP.language = function(prefix, skip) {
95
+ LANGUAGE_PREFIX = prefix;
96
+ LANGUAGE_SKIP = skip;
97
+ return this;
98
+ };
99
+
100
+ CTP.exec = function(filter, callback) {
101
+
102
+ var t = this;
103
+ var builder;
104
+
105
+ switch (filter.exec) {
106
+ case 'find':
107
+ case 'list':
108
+ case 'read':
109
+ case 'count':
110
+ case 'truncate':
111
+ case 'drop':
112
+ case 'remove':
113
+ case 'insert':
114
+ case 'update':
115
+ case 'scalar':
116
+ case 'command':
117
+ builder = t[filter.exec](filter.table);
118
+ for (var key in filter) {
119
+ if (key !== 'table')
120
+ builder.options[key] = filter[key];
121
+ }
122
+ builder.callback(callback);
123
+ break;
124
+ case 'query':
125
+ builder = t[filter.exec](filter.table, filter.query);
126
+ for (var key in filter) {
127
+ if (key !== 'table' && key !== 'query')
128
+ builder.options[key] = filter[key];
129
+ }
130
+ builder.callback(callback);
131
+ break;
132
+ }
133
+ };
134
+
135
+ CTP.next = function(t) {
136
+
137
+ if (t.error) {
138
+ t.$callback && t.$callback(t.error, null);
139
+ t.free();
140
+ return;
141
+ }
142
+
143
+ if (t.commands) {
144
+ var item = t.commands.shift();
145
+ if (item) {
146
+ execdb(item);
147
+ return;
148
+ }
149
+ }
150
+
151
+ t.$callback && t.$callback(t.error, t.response);
152
+ t.$end = true;
153
+
154
+ };
155
+
156
+ CTP.callback = function($) {
157
+ var t = this;
158
+ t.$callback = typeof($) === 'function' ? $ : $.callback();
159
+ return t;
160
+ };
161
+
162
+ CTP.promise = function($) {
163
+ var t = this;
164
+ var promise = new Promise(function(resolve, reject) {
165
+ t.$callback = function(err, response) {
166
+ if (err) {
167
+ if ($ && $.invalid) {
168
+ $.invalid(err);
169
+ t.free();
170
+ } else {
171
+ reject(err);
172
+ }
173
+ } else
174
+ resolve(response);
175
+ };
176
+ });
177
+ return promise;
178
+ };
179
+
180
+ CTP.done = function($, callback) {
181
+ var t = this;
182
+ t.$callback = function(err, response) {
183
+ if (err)
184
+ $.invalid(err);
185
+ else
186
+ callback && callback(response);
187
+ t.free();
188
+ };
189
+ return t;
190
+ };
191
+
192
+ CTP.free = function() {
193
+ var t = this;
194
+ t.commands = t.$callback = t.$fail = t.$data = t.response = t.error = null;
195
+ };
196
+
197
+ CTP.load = function(conn, opt) {
198
+
199
+ if (!opt) {
200
+ opt = conn;
201
+ conn = 'default';
202
+ }
203
+
204
+ var t = this;
205
+ var db = new DB(conn);
206
+
207
+ db.controller = t;
208
+ t.commands && t.commands.push(db);
209
+
210
+ var builder = new QueryBuilder(db, opt.table, opt.exec);
211
+
212
+ builder.options.fields = opt.fields && opt.fields instanceof Array && opt.fields.length ? opt.fields : null;
213
+ builder.options.skip = opt.skip;
214
+ builder.options.take = opt.take;
215
+ builder.options.query = opt.query;
216
+ builder.options.sort = opt.sort && opt.sort instanceof Array && opt.sort.length ? opt.sort : null;
217
+ builder.options.payload = opt.payload;
218
+ builder.options.upsert = opt.upsert;
219
+ builder.options.returning = opt.returning;
220
+ builder.options.filter = opt.filter && opt.filter instanceof Array ? opt.filter : EMPTYARRAY;
221
+
222
+ return builder;
223
+ };
224
+
225
+ CTP.find = CTP.all = function(table) {
226
+ var meta = F.temporary.querybuilders[table] || (F.temporary.querybuilders[table] = parsedb(table));
227
+ var t = this;
228
+ var db = new DB(meta.db);
229
+
230
+ db.controller = t;
231
+ t.commands && t.commands.push(db);
232
+ return new QueryBuilder(db, meta.table, 'find');
233
+ };
234
+
235
+ CTP.debug = function() {
236
+ this.$debug = true;
237
+ return this;
238
+ };
239
+
240
+ CTP.list = function(table) {
241
+ var meta = F.temporary.querybuilders[table] || (F.temporary.querybuilders[table] = parsedb(table));
242
+ var db = new DB(meta.db);
243
+ var t = this;
244
+ db.controller = t;
245
+ t.commands && t.commands.push(db);
246
+ return new QueryBuilder(db, meta.table, 'list');
247
+ };
248
+
249
+ CTP.check = function(table) {
250
+ var meta = F.temporary.querybuilders[table] || (F.temporary.querybuilders[table] = parsedb(table));
251
+ var t = this;
252
+ var db = new DB(meta.db);
253
+ db.controller = t;
254
+ t.commands && t.commands.push(db);
255
+ var builder = new QueryBuilder(db, meta.table, 'check');
256
+ builder.options.take = builder.options.first = 1;
257
+ return builder;
258
+ };
259
+
260
+ CTP.read = CTP.one = function(table) {
261
+ var meta = F.temporary.querybuilders[table] || (F.temporary.querybuilders[table] = parsedb(table));
262
+ var t = this;
263
+ var db = new DB(meta.db);
264
+ db.controller = t;
265
+ t.commands && t.commands.push(db);
266
+ return new QueryBuilder(db, meta.table, 'read');
267
+ };
268
+
269
+ CTP.count = function(table) {
270
+ var meta = F.temporary.querybuilders[table] || (F.temporary.querybuilders[table] = parsedb(table));
271
+ var t = this;
272
+ var db = new DB(meta.db);
273
+ db.controller = t;
274
+ t.commands && t.commands.push(db);
275
+ return new QueryBuilder(db, meta.table, 'count');
276
+ };
277
+
278
+ CTP.scalar = function(table, type, key, key2) {
279
+
280
+ var meta = F.temporary.querybuilders[table] || (F.temporary.querybuilders[table] = parsedb(table));
281
+ var t = this;
282
+
283
+ if (key == null)
284
+ key = '*';
285
+
286
+ var db = new DB(meta.db);
287
+ db.options.scalar = {};
288
+ db.options.scalar.type = type;
289
+
290
+ if (key)
291
+ db.options.scalar.key = key;
292
+
293
+ if (key2)
294
+ db.options.scalar.key2 = key2;
295
+
296
+ db.controller = t;
297
+ t.commands && t.commands.push(db);
298
+ return new QueryBuilder(db, meta.table, 'scalar');
299
+ };
300
+
301
+ CTP.insert = CTP.ins = function(table, data) {
302
+ var meta = F.temporary.querybuilders[table] || (F.temporary.querybuilders[table] = parsedb(table));
303
+ var t = this;
304
+ var db = new DB(meta.db);
305
+
306
+ db.controller = t;
307
+ t.commands && t.commands.push(db);
308
+
309
+ db.options.payload = data;
310
+ return new QueryBuilder(db, meta.table, 'insert');
311
+ };
312
+
313
+ CTP.update = CTP.modify = CTP.mod = CTP.upd = function(table, data, upsert) {
314
+
315
+ var meta = F.temporary.querybuilders[table] || (F.temporary.querybuilders[table] = parsedb(table));
316
+ var t = this;
317
+ var db = new DB(meta.db);
318
+
319
+ db.options.payload = data;
320
+ db.options.upsert = upsert;
321
+ db.controller = t;
322
+ t.commands && t.commands.push(db);
323
+
324
+ return new QueryBuilder(db, meta.table, 'update');
325
+ };
326
+
327
+ CTP.remove = CTP.rem = function(table) {
328
+ var meta = F.temporary.querybuilders[table] || (F.temporary.querybuilders[table] = parsedb(table));
329
+ var t = this;
330
+ var db = new DB(meta.db);
331
+ db.controller = t;
332
+ t.commands && t.commands.push(db);
333
+ return new QueryBuilder(db, meta.table, 'remove');
334
+ };
335
+
336
+ CTP.query = function(table, query, params) {
337
+
338
+ if (query == null) {
339
+ query = table;
340
+ table = 'default/';
341
+ } else
342
+ table += '/';
343
+
344
+ var meta = F.temporary.querybuilders[table] || (F.temporary.querybuilders[table] = parsedb(table));
345
+ var t = this;
346
+ var db = new DB(meta.db);
347
+ db.controller = t;
348
+ t.commands && t.commands.push(db);
349
+ db.options.query = query;
350
+ db.options.params = params;
351
+ return new QueryBuilder(db, '', 'query');
352
+ };
353
+
354
+ CTP.drop = function(table) {
355
+ var meta = F.temporary.querybuilders[table] || (F.temporary.querybuilders[table] = parsedb(table));
356
+ var t = this;
357
+ var db = new DB(meta.db);
358
+ db.controller = t;
359
+ t.commands && t.commands.push(db);
360
+ return new QueryBuilder(db, meta.table, 'drop');
361
+ };
362
+
363
+ CTP.truncate = CTP.clear = function(table) {
364
+ var meta = F.temporary.querybuilders[table] || (F.temporary.querybuilders[table] = parsedb(table));
365
+ var db = new DB(meta.db);
366
+ var t = this;
367
+ db.controller = t;
368
+ t.commands && t.commands.push(db);
369
+ return new QueryBuilder(db, meta.table, 'truncate');
370
+ };
371
+
372
+ CTP.command = function(table, name) {
373
+ var meta = F.temporary.querybuilders[table] || (F.temporary.querybuilders[table] = parsedb(table));
374
+ var db = new DB(meta.db);
375
+ var t = this;
376
+ db.controller = t;
377
+ t.commands && t.commands.push(db);
378
+ db.options.command = name;
379
+ return new QueryBuilder(db, meta.table, 'command');
380
+ };
381
+
382
+ DBP.evaluate = function(err, response) {
383
+ var t = this;
384
+
385
+ if (t.options.first && response instanceof Array)
386
+ response = response.length ? response[0] : null;
387
+
388
+ if (!err && t.error) {
389
+ if (t.error_reverse) {
390
+ if (response)
391
+ err = t.error;
392
+ else if (!t.options.first && response instanceof Array && response.length)
393
+ err = t.error;
394
+ } else if (!response)
395
+ err = t.error;
396
+ else if (!t.options.first && response instanceof Array && !response.length)
397
+ err = t.error;
398
+ }
399
+
400
+ // Upsert
401
+ if (!err && t.options.exec === 'update' && t.options.upsert) {
402
+
403
+ var is = false;
404
+
405
+ if (t.options.returning) {
406
+
407
+ if (t.options.first) {
408
+ if (!response)
409
+ is = true;
410
+ } else {
411
+ if (!response.length)
412
+ is = true;
413
+ }
414
+
415
+
416
+ } else if (!response)
417
+ is = true;
418
+
419
+ if (is) {
420
+ t.$insert && t.$insert(t.options.payload, t.$insertparam);
421
+ t.options.exec = 'insert';
422
+ t.options.filter.length = 0;
423
+ execdb(t);
424
+ return;
425
+ }
426
+ }
427
+
428
+ if (!err && t.options.exec === 'list') {
429
+ response.page = (t.options.skip / t.options.take) + 1;
430
+ response.limit = t.options.take;
431
+ response.pages = Math.ceil(response.count / t.options.take);
432
+ }
433
+
434
+ if (t.controller) {
435
+ t.controller.error = err;
436
+ if (!t.$nobind) {
437
+ if (t.output)
438
+ t.controller.response[t.output] = response;
439
+ else
440
+ t.controller.response = response;
441
+ }
442
+ }
443
+
444
+ if (err) {
445
+ t.callback_fail && t.callback_fail(err);
446
+ } else {
447
+ if (t.$audit) {
448
+ t.$audit();
449
+ t.$audit = null;
450
+ }
451
+ t.callback_data && t.callback_data(response);
452
+ }
453
+
454
+ t.callback && t.callback(err, response);
455
+ t.controller && setImmediate(t.controller.next, t.controller);
456
+ };
457
+
458
+ QBP.audit = function($, message, type) {
459
+ var self = this;
460
+ self.main.$audit = function() {
461
+
462
+ // Dynamic arguments
463
+ if (message)
464
+ message = $.variables(message, self.options.payload);
465
+
466
+ $.audit(message, type);
467
+ };
468
+ return self;
469
+ };
470
+
471
+ QBP.promise = function($) {
472
+ var t = this;
473
+ var promise = new Promise(function(resolve, reject) {
474
+ t.main.callback = function(err, response) {
475
+ if (err) {
476
+ if ($ && $.invalid) {
477
+ $.invalid(err);
478
+ t.main.controller && t.main.controller.free();
479
+ } else {
480
+ err.name = 'QueryBuilder(' + t.options.table + ' --> ' + t.options.exec + ')';
481
+ reject(err);
482
+ }
483
+ } else
484
+ resolve(response);
485
+ };
486
+ });
487
+ return promise;
488
+ };
489
+
490
+ QBP.insert = function(callback, param) {
491
+ this.main.$insert = callback;
492
+ this.main.$insertparam = param;
493
+ return this;
494
+ };
495
+
496
+ QBP.set = function(name) {
497
+ this.main.output = name;
498
+ return this;
499
+ };
500
+
501
+ QBP.callback = function($) {
502
+ var t = this;
503
+ t.main.callback = typeof($) === 'function' ? $ : $.callback();
504
+ return t;
505
+ };
506
+
507
+ QBP.returning = function(fields) {
508
+
509
+ var key = '_' + fields;
510
+
511
+ if (!F.temporary.querybuilders[key]) {
512
+ var arr = [];
513
+ fields = fields.split(',');
514
+ for (var field of fields) {
515
+ field = field.trim();
516
+ arr.push(field);
517
+ }
518
+ F.temporary.querybuilders[key] = arr;
519
+ }
520
+
521
+ this.options.returning = F.temporary.querybuilders[key];
522
+ return this;
523
+ };
524
+
525
+ QBP.nobind = function() {
526
+ this.main.$nobind = true;
527
+ return this;
528
+ };
529
+
530
+ QBP.data = function(cb) {
531
+ this.main.callback_data = cb;
532
+ return this;
533
+ };
534
+
535
+ QBP.fail = function(cb) {
536
+ this.main.callback_fail = cb;
537
+ return this;
538
+ };
539
+
540
+ QBP.error = QBP.err = function(err, reverse) {
541
+ this.main.error = err + '';
542
+ this.main.error_reverse = reverse;
543
+ return this;
544
+ };
545
+
546
+ QBP.done = function($, callback, param) {
547
+ this.main.callback = function(err, response) {
548
+ if (err)
549
+ $.invalid(err);
550
+ else
551
+ callback(response, param);
552
+ };
553
+ return this;
554
+ };
555
+
556
+ QBP.id = function(id) {
557
+ return id instanceof Array ? this.in('id', id) : this.where('id', id);
558
+ };
559
+
560
+ QBP.userid = function(id) {
561
+ return id instanceof Array ? this.in('userid', id) : this.where('userid', id);
562
+ };
563
+
564
+ QBP.equal = function(obj) {
565
+ for (var key in obj)
566
+ this.where(key, obj[key]);
567
+ return this;
568
+ };
569
+
570
+ QBP.where = function(name, comparer, value) {
571
+
572
+ var t = this;
573
+
574
+ if (comparer === undefined && value === undefined)
575
+ return t.query(name);
576
+
577
+ if (value === undefined) {
578
+ value = comparer;
579
+ comparer = '=';
580
+ }
581
+
582
+ switch (comparer) {
583
+ case '==':
584
+ comparer = '=';
585
+ break;
586
+ case '!=':
587
+ comparer = '<>';
588
+ break;
589
+ }
590
+
591
+ t.options.checksum += (t.options.checksum ? ' ' : '') + 'where' + comparer + name;
592
+ t.filter.push({ type: 'where', name: name, comparer: comparer, value: value });
593
+ return t;
594
+ };
595
+
596
+ QBP.array = function(name, comparer, value) {
597
+
598
+ var t = this;
599
+
600
+ if (value === undefined) {
601
+ value = comparer;
602
+ comparer = '&&';
603
+ }
604
+
605
+ t.options.checksum += (t.options.checksum ? ' ' : '') + 'array' + comparer + name;
606
+ t.filter.push({ type: 'array', name: name, comparer: comparer, value: value });
607
+ return t;
608
+ };
609
+
610
+ QBP.take = function(count) {
611
+ this.options.take = count;
612
+ return this;
613
+ };
614
+
615
+ QBP.first = function() {
616
+ this.options.take = this.options.first = 1;
617
+ return this;
618
+ };
619
+
620
+ QBP.limit = function(count) {
621
+ this.options.take = count;
622
+ return this;
623
+ };
624
+
625
+ QBP.language = function(val, prefix, skip) {
626
+
627
+ var self = this;
628
+
629
+ if (!skip)
630
+ skip = LANGUAGE_SKIP;
631
+
632
+ if (val && typeof(val) === 'object')
633
+ val = val.language;
634
+
635
+ if (skip && val && val === skip) {
636
+ val = '';
637
+ prefix = '';
638
+ }
639
+
640
+ if (val != null)
641
+ self.options.language = (prefix == null ? LANGUAGE_PREFIX : prefix) + val;
642
+
643
+ return self;
644
+ };
645
+
646
+ QBP.debug = function() {
647
+ this.options.debug = true;
648
+ return this;
649
+ };
650
+
651
+ QBP.page = function(page, limit) {
652
+ if (limit)
653
+ this.options.take = limit;
654
+ this.options.skip = (page - 1) * this.options.take;
655
+ return this;
656
+ };
657
+
658
+ QBP.paginate = function(page, limit, maxlimit) {
659
+
660
+ var limit2 = +(limit || 0);
661
+ var page2 = (+(page || 0)) - 1;
662
+
663
+ if (page2 < 0)
664
+ page2 = 0;
665
+
666
+ if (maxlimit && limit2 > maxlimit)
667
+ limit2 = maxlimit;
668
+
669
+ if (!limit2)
670
+ limit2 = maxlimit;
671
+
672
+ this.options.skip = page2 * limit2;
673
+ this.options.take = limit2;
674
+ return this;
675
+ };
676
+
677
+ QBP.primarykey = function(val) {
678
+ this.options.primarykey = val;
679
+ return this;
680
+ };
681
+
682
+ QBP.skip = function(count) {
683
+ this.options.skip = count;
684
+ return this;
685
+ };
686
+
687
+ QBP.in = function(name, value, id) {
688
+ var t = this;
689
+
690
+ if (id) {
691
+ var arr = [];
692
+ for (var i = 0; i < value.length; i++)
693
+ arr.push(value[i][id]);
694
+ value = arr;
695
+ }
696
+
697
+ if (!(value instanceof Array))
698
+ value = [value];
699
+
700
+ t.options.checksum += (t.options.checksum ? ' ' : '') + 'in=' + name;
701
+ t.filter.push({ type: 'in', name: name, value: value });
702
+ return t;
703
+ };
704
+
705
+ QBP.notin = function(name, value, id) {
706
+ var t = this;
707
+
708
+ if (id) {
709
+ var arr = [];
710
+ for (var i = 0; i < value.length; i++)
711
+ arr.push(value[i][id]);
712
+ value = arr;
713
+ }
714
+
715
+ if (!(value instanceof Array))
716
+ value = [value];
717
+
718
+ t.options.checksum += (t.options.checksum ? ' ' : '') + 'notin=' + name;
719
+ t.filter.push({ type: 'notin', name: name, value: value });
720
+ return t;
721
+ };
722
+
723
+ QBP.between = function(name, a, b) {
724
+ var t = this;
725
+ t.options.checksum += (t.options.checksum ? ' ' : '') + 'between=' + name;
726
+ t.filter.push({ type: 'between', name: name, a: a, b: b });
727
+ return t;
728
+ };
729
+
730
+ QBP.or = function(callback) {
731
+ var t = this;
732
+ var filter = t.filter;
733
+ t.filter = [];
734
+ t.options.checksum += (t.options.checksum ? ' ' : '') + 'or(';
735
+ callback.call(t, t);
736
+ if (t.filter.length) {
737
+ filter.push({ type: 'or', value: t.filter });
738
+ }
739
+ t.options.checksum += ')';
740
+ t.filter = filter;
741
+ return t;
742
+ };
743
+
744
+ QBP.fields = function(fields) {
745
+
746
+ var t = this;
747
+ var key = '_' + fields;
748
+
749
+ if (!F.temporary.querybuilders[key]) {
750
+ var arr = [];
751
+ fields = fields.split(',');
752
+ for (var field of fields) {
753
+ field = field.trim();
754
+ arr.push(field);
755
+ }
756
+ F.temporary.querybuilders[key] = arr;
757
+ }
758
+
759
+ t.options.fields = F.temporary.querybuilders[key];
760
+ return t;
761
+ };
762
+
763
+ QBP.month = function(name, comparer, value) {
764
+ var t = this;
765
+
766
+ if (value === undefined) {
767
+ value = comparer;
768
+ comparer = '=';
769
+ }
770
+
771
+ t.options.checksum += (t.options.checksum ? ' ' : '') + 'month' + comparer + name;
772
+ t.filter.push({ type: 'month', name: name, comparer: comparer, value: value });
773
+ return t;
774
+ };
775
+
776
+ QBP.day = function(name, comparer, value) {
777
+ var t = this;
778
+
779
+ if (value === undefined) {
780
+ value = comparer;
781
+ comparer = '=';
782
+ }
783
+
784
+ t.options.checksum += (t.options.checksum ? ' ' : '') + 'day' + comparer + name;
785
+ t.filter.push({ type: 'day', name: name, comparer: comparer, value: value });
786
+ return t;
787
+ };
788
+
789
+ QBP.year = function(name, comparer, value) {
790
+ var t = this;
791
+
792
+ if (value === undefined) {
793
+ value = comparer;
794
+ comparer = '=';
795
+ }
796
+
797
+ t.options.checksum += (t.options.checksum ? ' ' : '') + 'year' + comparer + name;
798
+ t.filter.push({ type: 'year', name: name, comparer: comparer, value: value });
799
+ return t;
800
+ };
801
+
802
+ QBP.hour = function(name, comparer, value) {
803
+ var t = this;
804
+
805
+ if (value === undefined) {
806
+ value = comparer;
807
+ comparer = '=';
808
+ }
809
+
810
+ t.options.checksum += (t.options.checksum ? ' ' : '') + 'hour' + comparer + name;
811
+ t.filter.push({ type: 'hour', name: name, comparer: comparer, value: value });
812
+ return t;
813
+ };
814
+
815
+ QBP.minute = function(name, comparer, value) {
816
+ var t = this;
817
+
818
+ if (value === undefined) {
819
+ value = comparer;
820
+ comparer = '=';
821
+ }
822
+
823
+ t.options.checksum += (t.options.checksum ? ' ' : '') + 'minute' + comparer + name;
824
+ t.filter.push({ type: 'minute', name: name, comparer: comparer, value: value });
825
+ return t;
826
+ };
827
+
828
+ QBP.search = function(name, value, where) {
829
+ var t = this;
830
+ t.options.checksum += (t.options.checksum ? ' ' : '') + 'search=' + name + '=' + (where || '');
831
+ t.filter.push({ type: 'search', name: name, comparer: where, value: value });
832
+ return t;
833
+ };
834
+
835
+ QBP.contains = function(name) {
836
+ var t = this;
837
+ t.options.checksum += (t.options.checksum ? ' ' : '') + 'contains=' + name;
838
+ t.filter.push({ type: 'contains', name: name });
839
+ return t;
840
+ };
841
+
842
+ QBP.empty = function(name) {
843
+ var t = this;
844
+ t.options.checksum += (t.options.checksum ? ' ' : '') + 'empty=' + name;
845
+ t.filter.push({ type: 'empty', name: name });
846
+ return t;
847
+ };
848
+
849
+ // Converting values
850
+ var convert = function(value, type) {
851
+
852
+ if (type === undefined || type === String)
853
+ return value;
854
+
855
+ if (type === Number)
856
+ return value.trim().parseFloat();
857
+
858
+ if (type === Date) {
859
+ value = value.trim();
860
+ if (value.indexOf(' ') !== -1)
861
+ return NOW.add('-' + value);
862
+ if (value.length < 8) {
863
+ var tmp;
864
+ var index = value.indexOf('-');
865
+ if (index !== -1) {
866
+ tmp = value.split('-');
867
+ value = NOW.getFullYear() + '-' + (tmp[0].length > 1 ? '' : '0') + tmp[0] + '-' + (tmp[1].length > 1 ? '' : '0') + tmp[1];
868
+ } else {
869
+ index = value.indexOf('.');
870
+ if (index !== -1) {
871
+ tmp = value.split('.');
872
+ value = NOW.getFullYear() + '-' + (tmp[1].length > 1 ? '' : '0') + tmp[0] + '-' + (tmp[0].length > 1 ? '' : '0') + tmp[1];
873
+ } else {
874
+ index = value.indexOf(':');
875
+ if (index !== -1) {
876
+ // hours
877
+ } else if (value.length <= 4) {
878
+ value = +value;
879
+ return value || 0;
880
+ }
881
+ }
882
+ }
883
+ }
884
+
885
+ return value.trim().parseDate();
886
+ }
887
+
888
+ if (type === Boolean)
889
+ return value.trim().parseBoolean();
890
+
891
+ return value;
892
+ };
893
+
894
+ QBP.gridfields = function(fields, allowed) {
895
+
896
+ var t = this;
897
+ var count = 0;
898
+ var newfields = [];
899
+
900
+ fields = fields.replace(REG_FIELDS_CLEANER, '').split(',');
901
+
902
+ if (allowed)
903
+ allowed = allowed.split(',');
904
+
905
+ for (var i = 0; i < fields.length; i++) {
906
+ var field = fields[i];
907
+ var can = !allowed;
908
+ if (!can) {
909
+ for (var j = 0; j < allowed.length; j++) {
910
+ if (allowed[j] === field) {
911
+ can = true;
912
+ break;
913
+ }
914
+ }
915
+ }
916
+ if (can) {
917
+ newfields.push(fields[i]);
918
+ count++;
919
+ }
920
+ }
921
+
922
+ if (!count)
923
+ t.options.fields = newfields;
924
+
925
+ return t;
926
+ };
927
+
928
+ // Grid filtering
929
+ QBP.gridfilter = function(name, obj, type, key) {
930
+
931
+ var builder = this;
932
+ var value = obj[name] || '';
933
+
934
+ if (!value || typeof(value) !== 'string')
935
+ return builder;
936
+
937
+ var arr, val;
938
+
939
+ if (!key)
940
+ key = name;
941
+
942
+ if (typeof(type) === 'string') {
943
+ switch (type) {
944
+ case 'string':
945
+ type = String;
946
+ break;
947
+ case 'date':
948
+ case 'datetime':
949
+ type = Date;
950
+ break;
951
+ case 'number':
952
+ case 'decimal':
953
+ case 'float':
954
+ type = Number;
955
+ break;
956
+ case 'boolean':
957
+ case 'bool':
958
+ type = Boolean;
959
+ break;
960
+ case '[string]':
961
+ return builder.array(key, value);
962
+ case 'json':
963
+ return builder.search(key, value);
964
+ }
965
+ }
966
+
967
+ // Between
968
+ var index = value.indexOf(' - ');
969
+ if (index !== -1) {
970
+
971
+ arr = value.split(' - ');
972
+
973
+ for (var i = 0, length = arr.length; i < length; i++) {
974
+ var item = arr[i].trim();
975
+ arr[i] = convert(item, type);
976
+ }
977
+
978
+ if (type === Date) {
979
+ if (typeof(arr[0]) === 'number') {
980
+ arr[0] = new Date(arr[0], 1, 1, 0, 0, 0);
981
+ arr[1] = new Date(arr[1], 11, 31, 23, 59, 59);
982
+ } else
983
+ arr[1] = arr[1].extend('23:59:59');
984
+ }
985
+
986
+ return builder.between(key, arr[0], arr[1]);
987
+ }
988
+
989
+ // Multiple values
990
+ index = value.indexOf(',');
991
+ if (index !== -1) {
992
+
993
+ var arr = value.split(',');
994
+
995
+ if (type === undefined || type === String) {
996
+ builder.or(function() {
997
+ for (var i = 0; i < arr.length; i++) {
998
+ var item = arr[i].trim();
999
+ builder.search(key, item);
1000
+ }
1001
+ });
1002
+ return builder;
1003
+ }
1004
+
1005
+ for (var i = 0; i < arr.length; i++)
1006
+ arr[i] = convert(arr[i], type);
1007
+
1008
+ return builder.in(key, arr);
1009
+ }
1010
+
1011
+ if (type === undefined || type === String)
1012
+ return value[0] === '!' ? builder.where(key, '=', value.substring(1)) : builder.search(key, value);
1013
+
1014
+ var comparer = '=';
1015
+
1016
+ switch (value[0]) {
1017
+ case '>':
1018
+ case '<':
1019
+ comparer = value[0];
1020
+ value = value.substring(1);
1021
+ break;
1022
+ }
1023
+
1024
+ if (type === Date) {
1025
+
1026
+ if (value === 'yesterday')
1027
+ val = NOW.add('-1 day');
1028
+ else if (value === 'today')
1029
+ val = NOW;
1030
+ else
1031
+ val = convert(value, type);
1032
+
1033
+ if (typeof(val) === 'number') {
1034
+ if (val > 1000)
1035
+ return builder.year(key, comparer, val);
1036
+ else
1037
+ return builder.month(key, comparer, val);
1038
+ }
1039
+
1040
+ if (!(val instanceof Date) || !val.getTime())
1041
+ val = NOW;
1042
+
1043
+ return comparer === '=' ? builder.between(key, val.extend('00:00:00'), val.extend('23:59:59')) : builder.where(key, comparer, val);
1044
+ }
1045
+
1046
+ return builder.where(key, comparer, convert(value, type));
1047
+ };
1048
+
1049
+ QBP.sort = function(sort, type) {
1050
+ var t = this;
1051
+ if (!t.options.sort)
1052
+ t.options.sort = [];
1053
+ t.options.sort.push(sort + '_' + (type === true || type === 'desc' ? 'desc' : 'asc'));
1054
+ return t;
1055
+ };
1056
+
1057
+ QBP.gridsort = function(sort, localized) {
1058
+
1059
+ var t = this;
1060
+
1061
+ if (!t.options.sort)
1062
+ t.options.sort = [];
1063
+
1064
+ var keys = sort.split(',');
1065
+ for (var key of keys) {
1066
+ key = key.trim();
1067
+
1068
+ var index = key.lastIndexOf('_');
1069
+ var field = '';
1070
+ var sort = '';
1071
+
1072
+ if (index === -1) {
1073
+ field = key;
1074
+ sort = 'asc';
1075
+ } else {
1076
+ field = key.substring(0, index);
1077
+ sort = key.substring(index + 1);
1078
+ }
1079
+
1080
+ if (localized && localized[field])
1081
+ field = localized[field];
1082
+
1083
+ //t.options.sort.push(index === -1 ? (key + '_asc') : key);
1084
+ t.options.sort.push(field + '_' + sort);
1085
+ }
1086
+
1087
+ return t;
1088
+ };
1089
+
1090
+ QBP.schema = function(value) {
1091
+ this.options.schema = value || '';
1092
+ return this;
1093
+ };
1094
+
1095
+ QBP.autoquery = function(query, schema, defsort, maxlimit) {
1096
+
1097
+ var t = this;
1098
+ var skipped;
1099
+ var key = 'QBF' + schema;
1100
+ var allowed = F.temporary.querybuilders[key];
1101
+ var tmp;
1102
+
1103
+ if (!allowed) {
1104
+ var obj = {};
1105
+ var arr = [];
1106
+ var filter = [];
1107
+ var localized = {};
1108
+ tmp = schema.split(',').trim();
1109
+
1110
+ for (var i = 0; i < tmp.length; i++) {
1111
+ var k = tmp[i].split(':').trim();
1112
+ arr.push(k[0]);
1113
+ var cleaned = k[0].replace(/§/g, '');
1114
+ obj[cleaned] = 1;
1115
+ localized[cleaned] = k[0];
1116
+ filter.push({ name: cleaned, type: (k[1] || 'string').toLowerCase() });
1117
+ }
1118
+
1119
+ allowed = F.temporary.querybuilders[key] = { keys: arr, meta: obj, filter: filter, fields: localized };
1120
+ }
1121
+
1122
+ var fields = query.fields;
1123
+ var fieldscount = 0;
1124
+
1125
+ if (!t.options.fields)
1126
+ t.options.fields = [];
1127
+
1128
+ if (fields) {
1129
+ fields = fields.replace(REG_FIELDS_CLEANER, '').split(',');
1130
+ for (var field of fields) {
1131
+ if (allowed && allowed.meta[field]) {
1132
+ t.options.fields.push(field);
1133
+ fieldscount++;
1134
+ }
1135
+ }
1136
+ }
1137
+
1138
+ if (!fieldscount) {
1139
+ for (var field of allowed.keys)
1140
+ t.options.fields.push(field);
1141
+ }
1142
+
1143
+ if (allowed && allowed.filter) {
1144
+ for (var item of allowed.filter)
1145
+ t.gridfilter(item.name, query, item.type, allowed.fields[item.name]);
1146
+ }
1147
+
1148
+ if (query.sort) {
1149
+
1150
+ tmp = query.sort.split(',');
1151
+ var count = 0;
1152
+
1153
+ for (var item of tmp) {
1154
+ var index = item.lastIndexOf('_');
1155
+ var name = index === - 1 ? item : item.substring(0, index);
1156
+
1157
+ if ((skipped && skipped[name]) || (!allowed.meta[name]))
1158
+ continue;
1159
+
1160
+ t.sort(allowed.fields[name], item[index + 1] === 'd');
1161
+ count++;
1162
+ }
1163
+
1164
+ if (!count && defsort)
1165
+ t.gridsort(defsort, allowed.fields);
1166
+
1167
+ } else if (defsort)
1168
+ t.gridsort(defsort, allowed.fields);
1169
+
1170
+ maxlimit && t.paginate(query.page, query.limit, maxlimit);
1171
+ return t;
1172
+ };
1173
+
1174
+ QBP.query = function(value) {
1175
+ this.filter.push({ type: 'query', value: value });
1176
+ return this;
1177
+ };
1178
+
1179
+ QBP.join = function(name, table, jointype, a, b) {
1180
+ this.filter.push({ type: 'join', table: table, name: name, join: jointype, on: [a, b] });
1181
+ return this;
1182
+ };
1183
+
1184
+ QBP.permit = function(name, type, value, userid, required) {
1185
+
1186
+ // type: R read
1187
+ // type: W write
1188
+ // type: D delete
1189
+
1190
+ var t = this;
1191
+ var types = type.split('');
1192
+ var arr = [];
1193
+
1194
+ for (let m of value) {
1195
+ for (let n of types)
1196
+ arr.push(n + m);
1197
+ }
1198
+
1199
+ t.options.checksum += (t.options.checksum ? ' ' : '') + 'permit' + type + arr.join('');
1200
+ t.filter.push({ type: 'permit', name: name, value: arr, userid: userid, required: required != false });
1201
+
1202
+ return t;
1203
+ };
1204
+
1205
+ exports.create = function(type, callback) {
1206
+
1207
+ if (typeof(type) === 'function') {
1208
+ callback = type;
1209
+ type = 'default';
1210
+ }
1211
+
1212
+ if (callback)
1213
+ F.querybuilders[type] = callback;
1214
+ else
1215
+ delete F.querybuilders[type];
1216
+
1217
+ };
1218
+
1219
+ exports.Controller = Controller;
1220
+ exports.QueryBuilder = QueryBuilder;