@e22m4u/js-repository 0.6.1 → 0.6.3
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.
- package/README.md +299 -70
- package/dist/cjs/index.cjs +188 -139
- package/package.json +2 -2
- package/src/adapter/builtin/memory-adapter.spec.js +2 -2
- package/src/filter/filter-clause.d.ts +4 -4
- package/src/filter/operator-clause-tool.d.ts +2 -1
- package/src/filter/operator-clause-tool.js +92 -104
- package/src/filter/operator-clause-tool.spec.js +560 -315
- package/src/filter/where-clause-tool.js +39 -41
- package/src/filter/where-clause-tool.spec.js +123 -13
- package/src/utils/index.d.ts +1 -0
- package/src/utils/index.js +1 -0
- package/src/utils/like-to-regexp.d.ts +14 -0
- package/src/utils/like-to-regexp.js +57 -0
- package/src/utils/like-to-regexp.spec.js +143 -0
- package/src/utils/string-to-regexp.js +1 -10
- package/src/utils/string-to-regexp.spec.js +10 -7
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import {Service} from '@e22m4u/js-service';
|
|
2
|
-
import {stringToRegexp} from '../utils/index.js';
|
|
3
|
-
|
|
4
|
-
import {
|
|
2
|
+
import {isDeepEqual, likeToRegexp, stringToRegexp} from '../utils/index.js';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
InvalidArgumentError,
|
|
6
|
+
InvalidOperatorValueError,
|
|
7
|
+
} from '../errors/index.js';
|
|
5
8
|
|
|
6
9
|
/**
|
|
7
10
|
* Operator clause tool.
|
|
@@ -12,40 +15,43 @@ export class OperatorClauseTool extends Service {
|
|
|
12
15
|
*
|
|
13
16
|
* @param {*} val1 The 1st value
|
|
14
17
|
* @param {*} val2 The 2nd value
|
|
18
|
+
* @param {*} noTypeConversion
|
|
15
19
|
* @returns {number} 0: =, positive: >, negative <
|
|
16
20
|
*/
|
|
17
|
-
compare(val1, val2) {
|
|
21
|
+
compare(val1, val2, noTypeConversion = false) {
|
|
22
|
+
if (val1 === val2) {
|
|
23
|
+
return 0;
|
|
24
|
+
}
|
|
18
25
|
if (val1 == null || val2 == null) {
|
|
19
26
|
return val1 == val2 ? 0 : NaN;
|
|
20
27
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
) {
|
|
27
|
-
if (val1 === val2) return 0;
|
|
28
|
-
return val1 - Number(val2);
|
|
29
|
-
}
|
|
30
|
-
return NaN;
|
|
28
|
+
const type1 = typeof val1;
|
|
29
|
+
const type2 = typeof val2;
|
|
30
|
+
// объекты и массивы
|
|
31
|
+
if (type1 === 'object' || type2 === 'object') {
|
|
32
|
+
return isDeepEqual(val1, val2) ? 0 : NaN;
|
|
31
33
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
34
|
+
// числовое сравнение
|
|
35
|
+
if (
|
|
36
|
+
(type1 === 'number' || type1 === 'string' || type1 === 'boolean') &&
|
|
37
|
+
(type2 === 'number' || type2 === 'string' || type2 === 'boolean')
|
|
38
|
+
) {
|
|
39
|
+
if (noTypeConversion && type1 !== type2) {
|
|
40
|
+
return NaN;
|
|
41
|
+
}
|
|
42
|
+
const num1 = Number(val1);
|
|
43
|
+
const num2 = Number(val2);
|
|
44
|
+
if (!isNaN(num1) && !isNaN(num2)) {
|
|
45
|
+
return num1 - num2;
|
|
41
46
|
}
|
|
42
|
-
return NaN;
|
|
43
47
|
}
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
// лексикографическое сравнение
|
|
49
|
+
if (type1 === 'string' && type2 === 'string') {
|
|
50
|
+
if (val1 > val2) return 1;
|
|
51
|
+
if (val1 < val2) return -1;
|
|
52
|
+
return 0;
|
|
46
53
|
}
|
|
47
|
-
|
|
48
|
-
return val1 === val2 ? 0 : NaN;
|
|
54
|
+
return NaN;
|
|
49
55
|
}
|
|
50
56
|
|
|
51
57
|
/**
|
|
@@ -62,54 +68,44 @@ export class OperatorClauseTool extends Service {
|
|
|
62
68
|
'should be an Object, but %v was given.',
|
|
63
69
|
clause,
|
|
64
70
|
);
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const ilikeTest = this.testIlike(clause, value);
|
|
104
|
-
if (ilikeTest !== undefined) return ilikeTest;
|
|
105
|
-
|
|
106
|
-
// {nilike: ...}
|
|
107
|
-
const nilikeTest = this.testNilike(clause, value);
|
|
108
|
-
if (nilikeTest !== undefined) return nilikeTest;
|
|
109
|
-
|
|
110
|
-
// {regexp: ...}
|
|
111
|
-
const regExpTest = this.testRegexp(clause, value);
|
|
112
|
-
if (regExpTest !== undefined) return regExpTest;
|
|
71
|
+
const operatorMap = {
|
|
72
|
+
eq: this.testEqNeq,
|
|
73
|
+
neq: this.testEqNeq,
|
|
74
|
+
gt: this.testGtLt,
|
|
75
|
+
gte: this.testGtLt,
|
|
76
|
+
lt: this.testGtLt,
|
|
77
|
+
lte: this.testGtLt,
|
|
78
|
+
inq: this.testInq,
|
|
79
|
+
nin: this.testNin,
|
|
80
|
+
between: this.testBetween,
|
|
81
|
+
exists: this.testExists,
|
|
82
|
+
like: this.testLike,
|
|
83
|
+
nlike: this.testNlike,
|
|
84
|
+
ilike: this.testIlike,
|
|
85
|
+
nilike: this.testNilike,
|
|
86
|
+
regexp: this.testRegexp,
|
|
87
|
+
};
|
|
88
|
+
const clauseKeys = Object.keys(clause);
|
|
89
|
+
// поиск ключей, которые являются известными операторами
|
|
90
|
+
const knownOperators = clauseKeys.filter(key => operatorMap[key]);
|
|
91
|
+
// если в объекте clause нет ни одного известного оператора,
|
|
92
|
+
// то возвращается undefined, чтобы _test() продолжил сравнение
|
|
93
|
+
if (knownOperators.length === 0) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
// проверка каждого из операторов
|
|
97
|
+
return knownOperators.every(op => {
|
|
98
|
+
// временный объект с текущим оператором для передачи в тестер
|
|
99
|
+
const singleOpClause = {[op]: clause[op]};
|
|
100
|
+
// обработка для regexp, для передачи флагов
|
|
101
|
+
if (op === 'regexp' && 'flags' in clause) {
|
|
102
|
+
singleOpClause.flags = clause.flags;
|
|
103
|
+
}
|
|
104
|
+
// вызов тестера с передачей контекста
|
|
105
|
+
const testFn = operatorMap[op];
|
|
106
|
+
const result = testFn.call(this, singleOpClause, value);
|
|
107
|
+
return result;
|
|
108
|
+
});
|
|
113
109
|
}
|
|
114
110
|
|
|
115
111
|
/**
|
|
@@ -140,8 +136,8 @@ export class OperatorClauseTool extends Service {
|
|
|
140
136
|
'should be an Object, but %v was given.',
|
|
141
137
|
clause,
|
|
142
138
|
);
|
|
143
|
-
if ('eq' in clause) return this.compare(clause.eq, value) === 0;
|
|
144
|
-
if ('neq' in clause) return this.compare(clause.neq, value) !== 0;
|
|
139
|
+
if ('eq' in clause) return this.compare(clause.eq, value, true) === 0;
|
|
140
|
+
if ('neq' in clause) return this.compare(clause.neq, value, true) !== 0;
|
|
145
141
|
}
|
|
146
142
|
|
|
147
143
|
/**
|
|
@@ -222,7 +218,9 @@ export class OperatorClauseTool extends Service {
|
|
|
222
218
|
);
|
|
223
219
|
}
|
|
224
220
|
for (let i = 0; i < clause.inq.length; i++) {
|
|
225
|
-
if (clause.inq[i]
|
|
221
|
+
if (this.compare(clause.inq[i], value, true) === 0) {
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
226
224
|
}
|
|
227
225
|
return false;
|
|
228
226
|
}
|
|
@@ -257,10 +255,9 @@ export class OperatorClauseTool extends Service {
|
|
|
257
255
|
clause.nin,
|
|
258
256
|
);
|
|
259
257
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
}
|
|
263
|
-
return true;
|
|
258
|
+
return clause.nin.every(element => {
|
|
259
|
+
return this.compare(element, value, true) !== 0;
|
|
260
|
+
});
|
|
264
261
|
}
|
|
265
262
|
}
|
|
266
263
|
|
|
@@ -348,16 +345,16 @@ export class OperatorClauseTool extends Service {
|
|
|
348
345
|
* @returns {boolean|undefined}
|
|
349
346
|
*/
|
|
350
347
|
testLike(clause, value) {
|
|
351
|
-
if (!clause || typeof clause !== 'object')
|
|
348
|
+
if (!clause || typeof clause !== 'object' || Array.isArray(clause))
|
|
352
349
|
throw new InvalidArgumentError(
|
|
353
350
|
'The first argument of OperatorUtils.testLike ' +
|
|
354
351
|
'should be an Object, but %v was given.',
|
|
355
352
|
clause,
|
|
356
353
|
);
|
|
357
354
|
if ('like' in clause && clause.like !== undefined) {
|
|
358
|
-
if (typeof clause.like !== 'string'
|
|
355
|
+
if (typeof clause.like !== 'string')
|
|
359
356
|
throw new InvalidOperatorValueError('like', 'a String', clause.like);
|
|
360
|
-
return
|
|
357
|
+
return likeToRegexp(clause.like).test(value);
|
|
361
358
|
}
|
|
362
359
|
}
|
|
363
360
|
|
|
@@ -376,20 +373,17 @@ export class OperatorClauseTool extends Service {
|
|
|
376
373
|
* @returns {boolean|undefined}
|
|
377
374
|
*/
|
|
378
375
|
testNlike(clause, value) {
|
|
379
|
-
if (!clause || typeof clause !== 'object')
|
|
376
|
+
if (!clause || typeof clause !== 'object' || Array.isArray(clause))
|
|
380
377
|
throw new InvalidArgumentError(
|
|
381
378
|
'The first argument of OperatorUtils.testNlike ' +
|
|
382
379
|
'should be an Object, but %v was given.',
|
|
383
380
|
clause,
|
|
384
381
|
);
|
|
385
382
|
if ('nlike' in clause && clause.nlike !== undefined) {
|
|
386
|
-
if (
|
|
387
|
-
typeof clause.nlike !== 'string' &&
|
|
388
|
-
!(clause.nlike instanceof RegExp)
|
|
389
|
-
) {
|
|
383
|
+
if (typeof clause.nlike !== 'string') {
|
|
390
384
|
throw new InvalidOperatorValueError('nlike', 'a String', clause.nlike);
|
|
391
385
|
}
|
|
392
|
-
return !
|
|
386
|
+
return !likeToRegexp(clause.nlike).test(value);
|
|
393
387
|
}
|
|
394
388
|
}
|
|
395
389
|
|
|
@@ -408,20 +402,17 @@ export class OperatorClauseTool extends Service {
|
|
|
408
402
|
* @returns {boolean|undefined}
|
|
409
403
|
*/
|
|
410
404
|
testIlike(clause, value) {
|
|
411
|
-
if (!clause || typeof clause !== 'object')
|
|
405
|
+
if (!clause || typeof clause !== 'object' || Array.isArray(clause))
|
|
412
406
|
throw new InvalidArgumentError(
|
|
413
407
|
'The first argument of OperatorUtils.testIlike ' +
|
|
414
408
|
'should be an Object, but %v was given.',
|
|
415
409
|
clause,
|
|
416
410
|
);
|
|
417
411
|
if ('ilike' in clause && clause.ilike !== undefined) {
|
|
418
|
-
if (
|
|
419
|
-
typeof clause.ilike !== 'string' &&
|
|
420
|
-
!(clause.ilike instanceof RegExp)
|
|
421
|
-
) {
|
|
412
|
+
if (typeof clause.ilike !== 'string') {
|
|
422
413
|
throw new InvalidOperatorValueError('ilike', 'a String', clause.ilike);
|
|
423
414
|
}
|
|
424
|
-
return
|
|
415
|
+
return likeToRegexp(clause.ilike, true).test(value);
|
|
425
416
|
}
|
|
426
417
|
}
|
|
427
418
|
|
|
@@ -440,24 +431,21 @@ export class OperatorClauseTool extends Service {
|
|
|
440
431
|
* @returns {boolean|undefined}
|
|
441
432
|
*/
|
|
442
433
|
testNilike(clause, value) {
|
|
443
|
-
if (!clause || typeof clause !== 'object')
|
|
434
|
+
if (!clause || typeof clause !== 'object' || Array.isArray(clause))
|
|
444
435
|
throw new InvalidArgumentError(
|
|
445
436
|
'The first argument of OperatorUtils.testNilike ' +
|
|
446
437
|
'should be an Object, but %v was given.',
|
|
447
438
|
clause,
|
|
448
439
|
);
|
|
449
440
|
if ('nilike' in clause && clause.nilike !== undefined) {
|
|
450
|
-
if (
|
|
451
|
-
typeof clause.nilike !== 'string' &&
|
|
452
|
-
!(clause.nilike instanceof RegExp)
|
|
453
|
-
) {
|
|
441
|
+
if (typeof clause.nilike !== 'string') {
|
|
454
442
|
throw new InvalidOperatorValueError(
|
|
455
443
|
'nilike',
|
|
456
444
|
'a String',
|
|
457
445
|
clause.nilike,
|
|
458
446
|
);
|
|
459
447
|
}
|
|
460
|
-
return !
|
|
448
|
+
return !likeToRegexp(clause.nilike, true).test(value);
|
|
461
449
|
}
|
|
462
450
|
}
|
|
463
451
|
|