@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.
@@ -1,7 +1,10 @@
1
1
  import {Service} from '@e22m4u/js-service';
2
- import {stringToRegexp} from '../utils/index.js';
3
- import {InvalidArgumentError} from '../errors/index.js';
4
- import {InvalidOperatorValueError} from '../errors/index.js';
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
- if (typeof val1 === 'number') {
22
- if (
23
- typeof val2 === 'number' ||
24
- typeof val2 === 'string' ||
25
- typeof val2 === 'boolean'
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
- if (typeof val1 === 'string') {
33
- const isDigits = /^\d+$/.test(val1);
34
- if (isDigits) return this.compare(Number(val1), val2);
35
- try {
36
- if (val1 > val2) return 1;
37
- if (val1 < val2) return -1;
38
- if (val1 == val2) return 0;
39
- } catch (e) {
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
- if (typeof val1 === 'boolean') {
45
- return Number(val1) - Number(val2);
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
- // Return NaN if we don't know how to compare.
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
- // {eq: ...}
67
- // {neq: ...}
68
- const eqNeqTest = this.testEqNeq(clause, value);
69
- if (eqNeqTest !== undefined) return eqNeqTest;
70
-
71
- // {gt: ...}
72
- // {gte: ...}
73
- // {lt: ...}
74
- // {lte: ...}
75
- const gtLtTest = this.testGtLt(clause, value);
76
- if (gtLtTest !== undefined) return gtLtTest;
77
-
78
- // {inc: ...}
79
- const incTest = this.testInq(clause, value);
80
- if (incTest !== undefined) return incTest;
81
-
82
- // {nin: ...}
83
- const ninTest = this.testNin(clause, value);
84
- if (ninTest !== undefined) return ninTest;
85
-
86
- // {between: ...}
87
- const betweenTest = this.testBetween(clause, value);
88
- if (betweenTest !== undefined) return betweenTest;
89
-
90
- // {exists: ...}
91
- const existsTest = this.testExists(clause, value);
92
- if (existsTest !== undefined) return existsTest;
93
-
94
- // {like: ...}
95
- const likeTest = this.testLike(clause, value);
96
- if (likeTest !== undefined) return likeTest;
97
-
98
- // {nlike: ...}
99
- const nlikeTest = this.testNlike(clause, value);
100
- if (nlikeTest !== undefined) return nlikeTest;
101
-
102
- // {ilike: ...}
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] == value) return true;
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
- for (let i = 0; i < clause.nin.length; i++) {
261
- if (clause.nin[i] == value) return false;
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' && !(clause.like instanceof RegExp))
355
+ if (typeof clause.like !== 'string')
359
356
  throw new InvalidOperatorValueError('like', 'a String', clause.like);
360
- return stringToRegexp(clause.like).test(value);
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 !stringToRegexp(clause.nlike).test(value);
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 stringToRegexp(clause.ilike, 'i').test(value);
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 !stringToRegexp(clause.nilike, 'i').test(value);
448
+ return !likeToRegexp(clause.nilike, true).test(value);
461
449
  }
462
450
  }
463
451