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,320 @@
1
+ // Total.js NoSQL QueryBuilder
2
+ // The MIT License
3
+ // Copyright 2020-2023 (c) Peter Širka <petersirka@gmail.com>
4
+
5
+ const REG_NULLABLE = /\./g;
6
+ const REG_LANGUAGE = /[a-z0-9]+§/gi;
7
+ const REG_ABSOLUTE = /\/|\\/;
8
+ const LOGGER = '-- NoSQL -->';
9
+ const FILTER = { find: 1, read: 1, count: 1, scalar: 1, check: 1, list: 1, update: 1, remove: 1, query: 1 };
10
+ const Open = {};
11
+
12
+ function db_where(where, opt, filter, operator, args) {
13
+
14
+ var tmp;
15
+
16
+ for (var item of filter) {
17
+
18
+ if (item.comparer) {
19
+ switch (item.comparer) {
20
+ case '=':
21
+ item.comparer = '==';
22
+ break;
23
+ case '<>':
24
+ item.comparer = '!=';
25
+ break;
26
+ }
27
+ }
28
+
29
+ if (opt.language != null && item.name && item.name[item.name.length - 1] === '§')
30
+ item.name = item.name.substring(0, item.name.length - 1) + opt.language;
31
+
32
+ switch (item.type) {
33
+ case 'or':
34
+ tmp = [];
35
+ db_where(tmp, opt, item.value, '||', args);
36
+ where.length && where.push(operator);
37
+ where.push('(' + tmp.join(' ') + ')');
38
+ break;
39
+ case 'in':
40
+ case 'notin':
41
+ where.length && where.push(operator);
42
+ where.push((item.type === 'notin' ? '!' : '') + 'func.in(doc.' + item.name.replace(REG_NULLABLE, '?.') + ',arg.params[' + args(item.value) + '])');
43
+ break;
44
+ case 'query':
45
+ where.length && where.push(operator);
46
+ where.push('(' + item.value + ')');
47
+ break;
48
+ case 'where':
49
+ where.length && where.push(operator);
50
+ where.push('doc.' + item.name.replace(REG_NULLABLE, '?.') + item.comparer + 'arg.params[' + args(item.value) + ']');
51
+ break;
52
+ case 'contains':
53
+ where.length && where.push(operator);
54
+ where.push('(doc.{0} instanceof Array?!!doc.{0}.length:!!doc.{0})'.format(item.name.replace(REG_NULLABLE, '?.')));
55
+ break;
56
+ case 'search':
57
+ var paramindex = args(item.value.replace(/%/g, ''));
58
+ where.length && where.push(operator);
59
+ where.push('func.search(doc.' + item.name.replace(REG_NULLABLE, '?.') + ',arg.params[' + paramindex + ']' + (item.comparer == 'beg' ? ',1' : item.comparer == 'end' ? ',2' : '') + ')');
60
+ break;
61
+ case 'month':
62
+ case 'year':
63
+ case 'day':
64
+ case 'hour':
65
+ case 'minute':
66
+ where.length && where.push(operator);
67
+ where.push(compare_datetype(item.type, item.name, args(item.value), item.comparer));
68
+ break;
69
+ case 'empty':
70
+ where.length && where.push(operator);
71
+ where.push('(doc.{0} instanceof Array?!doc.{0}.length:!doc.{0})'.format(item.name.replace(REG_NULLABLE, '?.')));
72
+ break;
73
+ case 'between':
74
+ var ia = args(item.a);
75
+ var ib = args(item.b);
76
+ where.length && where.push(operator);
77
+ where.push('(doc.' + item.name.replace(REG_NULLABLE, '?.') + '>=arg.params[' + ia + ']&&doc.' + item.name + '<=arg.params[' + ib + '])');
78
+ break;
79
+ }
80
+ }
81
+ }
82
+
83
+ function db_insertupdate(filter, insert) {
84
+
85
+ var query = insert ? null : [];
86
+ var params = {};
87
+
88
+ for (var key in filter.payload) {
89
+ var val = filter.payload[key];
90
+ var c = key[0];
91
+
92
+ switch (c) {
93
+ case '-':
94
+ case '+':
95
+ case '*':
96
+ case '/':
97
+ key = key.substring(1);
98
+ params[key] = val ? val : 0;
99
+ if (!insert)
100
+ query.push('doc.{0}=(doc.{0}==null?0:doc.{0})+arg.{0}'.format(key));
101
+ break;
102
+ case '>':
103
+ case '<':
104
+ key = key.substring(1);
105
+ params[key] = val ? val : 0;
106
+ if (!insert)
107
+ query.push('doc.{0}=(doc.{0}==null?arg.{0}:doc.{0}' + (c === '>' ? '<' : '>') + 'arg.{0}?arg.{0}:doc.{0})'.format(key));
108
+ break;
109
+ case '!':
110
+ // toggle
111
+ key = key.substring(1);
112
+ if (insert)
113
+ params[key] = true;
114
+ else
115
+ query.push('doc.{0}=!doc.{0}'.format(key));
116
+ break;
117
+ case '=':
118
+ case '#':
119
+ // raw
120
+ key = key.substring(1);
121
+ if (insert)
122
+ params[key] = val;
123
+ else
124
+ query.push('doc.' + key + '=' + val);
125
+ break;
126
+ default:
127
+ params[key] = val;
128
+ if (!insert)
129
+ query.push('doc.{0}=arg.{0}'.format(key));
130
+ break;
131
+ }
132
+ }
133
+
134
+ return { query, params };
135
+ }
136
+
137
+ function makefilter(db, opt, callback) {
138
+
139
+ var where = [];
140
+ var model = {};
141
+ var isread = false;
142
+ var args = [];
143
+ var exec = opt.exec;
144
+
145
+ db_where(where, opt, opt.filter, '&&', val => args.push(val) - 1);
146
+
147
+ var builder = {};
148
+ var insert = exec === 'insert';
149
+
150
+ if (insert || exec === 'update') {
151
+ var iu = db_insertupdate(opt, insert);
152
+ if (iu) {
153
+ if (insert) {
154
+ builder.payload = iu.params;
155
+ } else {
156
+ builder.modify = iu.query ? iu.query.join(';') : null;
157
+ builder.modifyarg = iu.params;
158
+ }
159
+ }
160
+ }
161
+
162
+ if (FILTER[exec]) {
163
+ builder.filter = where.join('') || 'true';
164
+ builder.filterarg = { params: args };
165
+ builder.take = opt.take;
166
+ builder.skip = opt.skip;
167
+ builder.first = opt.first;
168
+ if (opt.sort && opt.sort.length) {
169
+ builder.sort = opt.sort.join(',');
170
+ if (opt.language != null)
171
+ builder.sort = builder.sort.replace(REG_LANGUAGE, val => (val.substring(0, val.length - 1) + opt.language));
172
+ }
173
+ }
174
+
175
+ if (opt.fields) {
176
+ builder.fields = opt.fields.join(',');
177
+ if (opt.language != null && builder.fields) {
178
+ builder.fields = builder.fields.replace(REG_LANGUAGE, function(val) {
179
+ val = val.substring(0, val.length - 1);
180
+ return val + (opt.language ? (opt.language + ' as ' + val) : '');
181
+ });
182
+ }
183
+ }
184
+
185
+ switch (exec) {
186
+ case 'find':
187
+ isread = true;
188
+ db.find2().assign(builder).$callback = callback;
189
+ break;
190
+ case 'count':
191
+ isread = true;
192
+ builder.scalar = 'arg.count+=1';
193
+ builder.scalararg = { count: 0 };
194
+ db.find().assign(builder).$callback = callback;
195
+ break;
196
+ case 'check':
197
+ builder.first = true;
198
+ isread = true;
199
+ db.find().assign(builder).$callback = (err, response) => callback(err, !!response);
200
+ break;
201
+ case 'list':
202
+ db.find().assign(builder).$callback = (err, response, meta) => callback(err, err ? null : { items: response, count: meta.count });
203
+ isread = true;
204
+ break;
205
+ case 'read':
206
+ db.find2().assign(builder).$callback = callback;
207
+ isread = true;
208
+ break;
209
+ case 'insert':
210
+ db.insert().assign(builder).$callback = callback;
211
+ break;
212
+ case 'update':
213
+ db.update().assign(builder).$callback = callback;
214
+ break;
215
+ case 'remove':
216
+ db.remove().assign(builder).$callback = callback;
217
+ break;
218
+ case 'truncate':
219
+ db.clear(callback);
220
+ break;
221
+ case 'drop':
222
+ db.drop(callback);
223
+ delete Open[db.$qbkey];
224
+ break;
225
+ case 'scalar':
226
+ switch (opt.scalar.type) {
227
+ case 'avg':
228
+ case 'min':
229
+ case 'sum':
230
+ case 'max':
231
+ case 'count':
232
+ if (opt.scalar.key2) {
233
+ builder.scalar = 'var k=doc.' + opt.scalar.key + '+\'\';if (arg[k]){tmp.bk=doc.' + opt.scalar.key2 + '||0;' + (opt.scalar.type === 'max' ? 'if(tmp.bk>arg[k])arg[k]=tmp.bk' : opt.scalar.type === 'min' ? 'if(tmp.bk<arg[k])arg[k]=tmp.bk' : 'arg[k]+=tmp.bk') + '}else{arg[k]=doc.' + opt.scalar.key2 + '||0}';
234
+ } else {
235
+ builder.scalar = 'if (doc.{0}!=null){tmp.val=doc.{0};arg.count+=1;arg.min=arg.min==null?tmp.val:arg.min>tmp.val?tmp.val:arg.min;arg.max=arg.max==null?tmp.val:arg.max<tmp.val?tmp.val:arg.max;if(!(tmp.val instanceof Date))arg.sum+=tmp.val}'.format(opt.scalar.key);
236
+ builder.scalararg = { count: 0, sum: 0 };
237
+ }
238
+ db.find().assign(builder).$callback = function(err, response) {
239
+ var output = {};
240
+ if (response)
241
+ output.value = opt.scalar.type === 'avg' ? ((response.min + response.max) / 2) : response[opt.scalar.type];
242
+ callback(err, output);
243
+ };
244
+ break;
245
+ case 'group':
246
+ builder.scalar = opt.scalar.key2 ? 'if (doc.{0}!=null){tmp.val=doc.{0};arg[tmp.val]=(arg[tmp.val]||0)+(doc.{1}||0)}'.format(opt.scalar.key, opt.scalar.key2) : 'if (doc.{0}!=null){tmp.val=doc.{0};arg[tmp.val]=(arg[tmp.val]||0)+1}'.format(opt.scalar.key);
247
+ builder.scalararg = {};
248
+ db.find().assign(builder).$callback = function(err, response) {
249
+ var output = [];
250
+ for (var key in response) {
251
+ var val = response[key];
252
+ var mod = {};
253
+ mod[opt.scalar.key] = key;
254
+ mod.value = val;
255
+ output.push(mod);
256
+ }
257
+ callback(err, output);
258
+ };
259
+ break;
260
+ }
261
+ isread = true;
262
+ break;
263
+ case 'command':
264
+ if (opt.command === 'clean')
265
+ db.clean(callback);
266
+ break;
267
+ }
268
+
269
+ if (opt.debug)
270
+ console.log(LOGGER, db.filename, exec, builder);
271
+
272
+ if (isread)
273
+ F.stats.performance.dbrm++;
274
+ else
275
+ F.stats.performance.dbwm++;
276
+
277
+ return model;
278
+ }
279
+
280
+ function compare_datetype(type, key, paramindex, operator) {
281
+ switch (operator) {
282
+ case '=':
283
+ operator = '==';
284
+ break;
285
+ case '<>':
286
+ operator = '!=';
287
+ break;
288
+ }
289
+ switch (type) {
290
+ case 'day':
291
+ type = 'getDate()';
292
+ break;
293
+ case 'month':
294
+ type = 'getMonth()+1';
295
+ break;
296
+ case 'year':
297
+ type = 'getFullYear()';
298
+ break;
299
+ case 'hour':
300
+ type = 'getHour()';
301
+ break;
302
+ case 'minute':
303
+ type = 'getMinute()';
304
+ break;
305
+ }
306
+ return 'doc.{0}&&doc.{0}.getTime?doc.{0}.{3}{2}arg.params[{1}]:false'.format(key.replace(REG_NULLABLE, '?.'), paramindex, operator, type);
307
+ }
308
+
309
+ F.TQueryBuilder.create('nosql', function($, next) {
310
+
311
+ let key = 'nosql_' + $.table;
312
+
313
+ if (!Open[key]) {
314
+ let filename = REG_ABSOLUTE.test($.table) ? $.table : F.path.databases($.table + '.nosql');
315
+ Open[key] = F.TNoSQL.create(filename);
316
+ Open[key].$qbkey = key;
317
+ }
318
+
319
+ makefilter(Open[key], $, next);
320
+ });
@@ -0,0 +1,353 @@
1
+ // Total.js NoSQL Data reader
2
+ // The MIT License
3
+ // Copyright 2020-2023 (c) Peter Širka <petersirka@gmail.com>
4
+
5
+ function NoSQLReader(builder) {
6
+ var self = this;
7
+ self.ts = Date.now();
8
+ self.cancelable = true;
9
+ self.builders = [];
10
+ self.canceled = 0;
11
+ self.total = 0;
12
+
13
+ if (builder) {
14
+ self.add(builder);
15
+ self.prepare();
16
+ }
17
+ }
18
+
19
+ NoSQLReader.prototype.add = function(builder) {
20
+ var self = this;
21
+ if (builder instanceof Array) {
22
+ for (var i = 0; i < builder.length; i++)
23
+ self.add(builder[i]);
24
+ } else {
25
+ builder.$NoSQLReader = self;
26
+ if (builder.$sort)
27
+ self.cancelable = false;
28
+ self.builders.push(builder);
29
+ }
30
+ return self;
31
+ };
32
+
33
+ NoSQLReader.prototype.compare2 = function(docs, custom, done) {
34
+
35
+ var self = this;
36
+
37
+ for (var i = 0; i < docs.length; i++) {
38
+
39
+ var doc = docs[i];
40
+ if (doc === EMPTYOBJECT)
41
+ continue;
42
+
43
+ if (self.builders.length === self.canceled) {
44
+ self.total = 0;
45
+ return false;
46
+ }
47
+
48
+ self.total++;
49
+ var is = false;
50
+
51
+ for (var j = 0; j < self.builders.length; j++) {
52
+
53
+ var builder = self.builders[j];
54
+ if (builder.canceled)
55
+ continue;
56
+
57
+ builder.scanned++;
58
+
59
+ var can = false;
60
+
61
+ try {
62
+ can = builder.filterrule(doc, builder.filterarg, builder.tmp, builder.func);
63
+ } catch (e) {
64
+ can = false;
65
+ builder.canceled = true;
66
+ builder.error = e + '';
67
+ }
68
+
69
+ if (can) {
70
+
71
+ builder.count++;
72
+
73
+ if (!builder.$sort && ((builder.$skip && builder.$skip >= builder.count) || (builder.$take && builder.$take <= builder.counter)))
74
+ continue;
75
+
76
+ if (!is)
77
+ is = true;
78
+
79
+ builder.counter++;
80
+
81
+ var canceled = builder.canceled;
82
+ var c = custom(docs, doc, i, builder, j);
83
+
84
+ if (builder.$take === 1) {
85
+ builder.canceled = true;
86
+ self.canceled++;
87
+ } else if (!canceled && builder.canceled)
88
+ self.canceled++;
89
+
90
+ if (c === 1)
91
+ break;
92
+ else
93
+ continue;
94
+ }
95
+ }
96
+
97
+ is && done && done(docs, doc, i, self.builders);
98
+ }
99
+ };
100
+
101
+ // For FILEDB
102
+ NoSQLReader.prototype.compare3 = function(docs, custom) {
103
+
104
+ var self = this;
105
+ var changed = false;
106
+
107
+ for (var i = 0; i < docs.length; i++) {
108
+
109
+ var doc = docs[i];
110
+ if (doc === EMPTYOBJECT)
111
+ continue;
112
+
113
+ if (self.builders.length === self.canceled) {
114
+ self.total = 0;
115
+ return 0;
116
+ }
117
+
118
+ self.total++;
119
+
120
+ for (var j = 0; j < self.builders.length; j++) {
121
+
122
+ var builder = self.builders[j];
123
+ if (builder.canceled)
124
+ continue;
125
+
126
+ builder.scanned++;
127
+
128
+ var can = false;
129
+
130
+ try {
131
+ can = builder.filterrule(doc, builder.filterarg, builder.tmp, builder.func);
132
+ } catch (e) {
133
+ can = false;
134
+ builder.canceled = true;
135
+ builder.error = e + '';
136
+ }
137
+
138
+ if (can) {
139
+
140
+ builder.count++;
141
+
142
+ if (!builder.$sort && ((builder.$skip && builder.$skip >= builder.count) || (builder.$take && builder.$take <= builder.counter)))
143
+ continue;
144
+
145
+ if (!changed)
146
+ changed = true;
147
+
148
+ builder.counter++;
149
+
150
+ var canceled = builder.canceled;
151
+ var c = custom(docs, doc, i, builder, j);
152
+
153
+ if (builder.$take === 1) {
154
+ builder.canceled = true;
155
+ self.canceled++;
156
+ } else if (!canceled && builder.canceled)
157
+ self.canceled++;
158
+
159
+ if (c === 1)
160
+ break;
161
+ else
162
+ continue;
163
+ }
164
+ }
165
+ }
166
+
167
+ return changed ? 2 : 1;
168
+ };
169
+
170
+ NoSQLReader.prototype.compare = function(docs) {
171
+
172
+ var self = this;
173
+ self.total += docs.length;
174
+
175
+ for (var i = 0; i < docs.length; i++) {
176
+ var doc = docs[i];
177
+
178
+ if (self.builders.length === self.canceled) {
179
+ self.total = 0;
180
+ return false;
181
+ }
182
+
183
+ for (var j = 0; j < self.builders.length; j++) {
184
+
185
+ var builder = self.builders[j];
186
+ if (builder.canceled)
187
+ continue;
188
+
189
+ builder.scanned++;
190
+
191
+ var is = false;
192
+
193
+ try {
194
+ is = builder.filterrule(doc, builder.filterarg, builder.tmp, builder.func);
195
+ } catch (e) {
196
+ is = false;
197
+ builder.canceled = true;
198
+ builder.error = e + '';
199
+ }
200
+
201
+ if (is) {
202
+
203
+ builder.count++;
204
+
205
+ if (builder.scalarrule) {
206
+ builder.counter++;
207
+ try {
208
+ builder.scalarrule(doc, builder.scalararg, builder.tmp, builder.func);
209
+ } catch (e) {
210
+ builder.canceled = true;
211
+ builder.error = e + '';
212
+ }
213
+ continue;
214
+ }
215
+
216
+ if (!builder.$sort && ((builder.$skip && builder.$skip >= builder.count) || (builder.$take && builder.$take <= builder.counter)))
217
+ continue;
218
+
219
+ builder.counter++;
220
+ builder.push(doc);
221
+
222
+ if (self.cancelable && !builder.$sort && !builder.$paginate && builder.response.length === builder.$take) {
223
+ builder.canceled = true;
224
+ self.canceled++;
225
+ }
226
+ }
227
+ }
228
+ }
229
+ };
230
+
231
+ NoSQLReader.prototype.comparereverse = function(docs) {
232
+
233
+ var self = this;
234
+
235
+ self.total += docs.length;
236
+
237
+ for (var i = docs.length - 1; i > -1; i--) {
238
+
239
+ var doc = docs[i];
240
+
241
+ if (self.builders.length === self.canceled) {
242
+ self.total = 0;
243
+ return false;
244
+ }
245
+
246
+ for (var j = 0; j < self.builders.length; j++) {
247
+
248
+ var builder = self.builders[j];
249
+ if (builder.canceled)
250
+ continue;
251
+
252
+ builder.scanned++;
253
+
254
+ var is = false;
255
+
256
+ try {
257
+ is = builder.filterrule(doc, builder.filterarg, builder.tmp, builder.func);
258
+ } catch (e) {
259
+ is = false;
260
+ builder.canceled = true;
261
+ builder.error = e + '';
262
+ }
263
+
264
+ if (is) {
265
+
266
+ builder.count++;
267
+
268
+ if (builder.scalarrule) {
269
+ builder.counter++;
270
+ try {
271
+ builder.scalarrule(doc, builder.scalararg, builder.tmp, builder.func);
272
+ } catch (e) {
273
+ builder.canceled = true;
274
+ builder.error = e + '';
275
+ }
276
+ continue;
277
+ }
278
+
279
+ if (!builder.$sort && ((builder.$skip && builder.$skip >= builder.count) || (builder.$take && builder.$take <= builder.counter)))
280
+ continue;
281
+
282
+ builder.counter++;
283
+ builder.push(doc);
284
+
285
+ if (self.cancelable && !builder.$sort && builder.response.length === builder.$take) {
286
+ builder.canceled = true;
287
+ self.canceled++;
288
+ }
289
+ }
290
+ }
291
+ }
292
+ };
293
+
294
+ NoSQLReader.prototype.callback = function(builder) {
295
+ var self = this;
296
+
297
+ if (builder.$sort && !builder.$sorted)
298
+ sortfinal(builder);
299
+
300
+ if (builder.$sort && builder.$take2 && builder.response.length >= builder.$take)
301
+ builder.response = builder.$skip ? builder.response.splice(builder.$skip, builder.$take) : builder.response.splice(0, builder.$take);
302
+
303
+ for (var i = 0; i < builder.response.length; i++)
304
+ builder.response[i] = builder.prepare(builder.response[i]);
305
+
306
+ builder.logrule && builder.logrule();
307
+ builder.done();
308
+ return self;
309
+ };
310
+
311
+ NoSQLReader.prototype.prepare = function() {
312
+ var self = this;
313
+ for (var i = 0; i < self.builders.length; i++) {
314
+ var builder = self.builders[i];
315
+ if (builder.$take)
316
+ builder.$take2 = builder.$sort ? ((builder.$skip || 1) + builder.$take) : builder.$take;
317
+ else
318
+ builder.$take2 = 0;
319
+ }
320
+ return self;
321
+ };
322
+
323
+ NoSQLReader.prototype.done = function() {
324
+
325
+ var self = this;
326
+ var diff = Date.now() - self.ts;
327
+
328
+ if (self.db && self.db.duration) {
329
+ if (self.total > 0)
330
+ self.db.total = self.total;
331
+ if (self.db.duration.push({ type: self.type, duration: diff }) > 20)
332
+ self.db.duration.shift();
333
+ }
334
+
335
+ for (var i = 0; i < self.builders.length; i++) {
336
+ var builder = self.builders[i];
337
+ builder.duration = diff;
338
+ builder.inmemory = self.inmemory;
339
+ self.callback(builder);
340
+ }
341
+
342
+ self.diff = diff;
343
+ self.canceled = 0;
344
+ return self;
345
+ };
346
+
347
+ function sortfinal(builder) {
348
+ builder.response.sort(builder.$sort);
349
+ }
350
+
351
+ exports.make = function(builder) {
352
+ return new NoSQLReader(builder);
353
+ };