@abaplint/runtime 2.13.92 → 2.13.94

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.
Files changed (40) hide show
  1. package/build/src/builtin/_extremum.d.ts +9 -0
  2. package/build/src/builtin/_extremum.js +75 -0
  3. package/build/src/builtin/escape.d.ts +2 -2
  4. package/build/src/builtin/escape.js +29 -4
  5. package/build/src/builtin/nmax.d.ts +1 -2
  6. package/build/src/builtin/nmax.js +3 -28
  7. package/build/src/builtin/nmin.d.ts +1 -2
  8. package/build/src/builtin/nmin.js +3 -28
  9. package/build/src/builtin/round.d.ts +14 -5
  10. package/build/src/builtin/round.js +69 -21
  11. package/build/src/compare/eq.js +20 -3
  12. package/build/src/compare/gt.js +8 -2
  13. package/build/src/compare/in.d.ts +3 -1
  14. package/build/src/compare/in.js +35 -18
  15. package/build/src/expand_in.js +66 -28
  16. package/build/src/operators/_bit_operations.d.ts +1 -5
  17. package/build/src/operators/_bit_operations.js +24 -23
  18. package/build/src/operators/bit-and.js +1 -11
  19. package/build/src/operators/bit-or.js +1 -11
  20. package/build/src/operators/bit-xor.js +1 -11
  21. package/build/src/primary_key.d.ts +2 -0
  22. package/build/src/primary_key.js +49 -0
  23. package/build/src/statements/concatenate.js +13 -3
  24. package/build/src/statements/create_data.js +14 -2
  25. package/build/src/statements/delete_database.js +15 -0
  26. package/build/src/statements/delete_internal.d.ts +1 -0
  27. package/build/src/statements/delete_internal.js +14 -3
  28. package/build/src/statements/describe.js +17 -1
  29. package/build/src/statements/insert_database.d.ts +1 -0
  30. package/build/src/statements/insert_database.js +11 -0
  31. package/build/src/statements/read_table.js +93 -7
  32. package/build/src/statements/shift.js +22 -4
  33. package/build/src/statements/sort.js +22 -0
  34. package/build/src/statements/write.js +9 -6
  35. package/build/src/template_formatting.js +18 -4
  36. package/build/src/types/date.js +6 -0
  37. package/build/src/types/hex.js +7 -4
  38. package/build/src/types/integer.js +5 -8
  39. package/build/src/types/table.js +11 -1
  40. package/package.json +1 -1
@@ -0,0 +1,9 @@
1
+ import { DecFloat34, Float, Integer, Integer8, Packed } from "../types";
2
+ import { INumeric } from "../types/_numeric";
3
+ export type ExtremumArgument = number | INumeric | undefined;
4
+ /** nmax( ) and nmin( ): the result has the calculation type of the arguments,
5
+ * as an arithmetic expression would determine it - decfloat34 before f before
6
+ * p before int8 before i. So nmin( val1 = i1 val2 = i2 ) is an i, which DO
7
+ * nmin( ... ) TIMES and every other integer position rely on, and a p result
8
+ * keeps the most decimals of its arguments. */
9
+ export declare function extremum(args: ExtremumArgument[], isBetter: (candidate: number, best: number) => boolean): Float | Integer8 | Integer | DecFloat34 | Packed;
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extremum = extremum;
4
+ const _parse_1 = require("../operators/_parse");
5
+ const types_1 = require("../types");
6
+ // the calculation types in the order an arithmetic expression ranks them
7
+ const INT = 0;
8
+ const INT8 = 1;
9
+ const PACKED = 2;
10
+ const FLOAT = 3;
11
+ const DECFLOAT = 4;
12
+ /** nmax( ) and nmin( ): the result has the calculation type of the arguments,
13
+ * as an arithmetic expression would determine it - decfloat34 before f before
14
+ * p before int8 before i. So nmin( val1 = i1 val2 = i2 ) is an i, which DO
15
+ * nmin( ... ) TIMES and every other integer position rely on, and a p result
16
+ * keeps the most decimals of its arguments. */
17
+ function extremum(args, isBetter) {
18
+ let best = undefined;
19
+ let bestValue = 0;
20
+ let type = INT;
21
+ let decimals = 0;
22
+ for (let arg of args) {
23
+ if (arg === undefined) {
24
+ continue;
25
+ }
26
+ if (arg instanceof types_1.FieldSymbol) {
27
+ arg = arg.getPointer();
28
+ }
29
+ if (arg instanceof types_1.DecFloat34) {
30
+ type = Math.max(type, DECFLOAT);
31
+ }
32
+ else if (arg instanceof types_1.Float) {
33
+ type = Math.max(type, FLOAT);
34
+ }
35
+ else if (arg instanceof types_1.Packed) {
36
+ type = Math.max(type, PACKED);
37
+ decimals = Math.max(decimals, arg.getDecimals());
38
+ }
39
+ else if (arg instanceof types_1.Integer8) {
40
+ type = Math.max(type, INT8);
41
+ }
42
+ else if (arg instanceof types_1.Integer || (typeof arg === "number" && Number.isInteger(arg))) {
43
+ // i, the lowest type
44
+ }
45
+ else {
46
+ // character-like and other arguments, as before: f
47
+ type = Math.max(type, FLOAT);
48
+ }
49
+ const value = (0, _parse_1.parse)(arg);
50
+ if (best === undefined || isBetter(value, bestValue)) {
51
+ best = arg;
52
+ bestValue = value;
53
+ }
54
+ }
55
+ switch (type) {
56
+ case DECFLOAT:
57
+ return new types_1.DecFloat34().set(bestValue);
58
+ case FLOAT:
59
+ return new types_1.Float().set(bestValue);
60
+ case PACKED:
61
+ if (best instanceof types_1.Packed) {
62
+ // through the digits, not through a binary float
63
+ return new types_1.Packed({ length: 16, decimals }).set(best.toFixed(best.getDecimals()));
64
+ }
65
+ return new types_1.Packed({ length: 16, decimals }).set(bestValue);
66
+ case INT8:
67
+ if (best instanceof types_1.Integer8) {
68
+ return new types_1.Integer8().set(best.get());
69
+ }
70
+ return new types_1.Integer8().set(bestValue);
71
+ default:
72
+ return new types_1.Integer().set(bestValue);
73
+ }
74
+ }
75
+ //# sourceMappingURL=_extremum.js.map
@@ -1,7 +1,7 @@
1
- import { String } from "../types";
1
+ import { FieldSymbol, String } from "../types";
2
2
  import { ICharacter } from "../types/_character";
3
3
  import { INumeric } from "../types/_numeric";
4
4
  export declare function escape(input: {
5
- val: ICharacter | string;
5
+ val: ICharacter | FieldSymbol | string;
6
6
  format: INumeric | number;
7
7
  }): String;
@@ -3,8 +3,35 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.escape = escape;
4
4
  const types_1 = require("../types");
5
5
  const _position_1 = require("./_position");
6
+ const JSON_SHORT = {
7
+ "\\": "\\\\",
8
+ "\"": "\\\"",
9
+ "\b": "\\b",
10
+ "\t": "\\t",
11
+ "\n": "\\n",
12
+ "\f": "\\f",
13
+ "\r": "\\r",
14
+ };
15
+ // backslash, quote, and \b \t \n \f \r by their short forms; the other control
16
+ // characters below U+0020 as \u00XX in upper case hex; U+007F and non-ASCII unchanged
17
+ function escapeJsonCharacter(char) {
18
+ return JSON_SHORT[char] ?? "\\u" + char.charCodeAt(0).toString(16).toUpperCase().padStart(4, "0");
19
+ }
6
20
  function escape(input) {
7
- let val = typeof input.val === "string" ? input.val : input.val.get();
21
+ let source;
22
+ if (input.val instanceof types_1.FieldSymbol) {
23
+ const pointer = input.val.getPointer();
24
+ if (pointer === undefined) {
25
+ throw new Error("GETWA_NOT_ASSIGNED");
26
+ }
27
+ source = pointer;
28
+ }
29
+ else {
30
+ source = input.val;
31
+ }
32
+ // a c operand counts without its trailing blanks, as in the other string functions
33
+ let val = typeof source === "string" ? source
34
+ : source instanceof types_1.Character ? source.getTrimEnd() : source.get();
8
35
  const format = (0, _position_1.position)(input.format);
9
36
  // todo, optimize/cache regexes
10
37
  switch (format) {
@@ -34,9 +61,7 @@ function escape(input) {
34
61
  val = val.replace(/'/g, "\\'");
35
62
  break;
36
63
  case 24: // e_json_string
37
- val = val.replace(/\\/g, "\\\\");
38
- val = val.replace(/"/g, "\\\"");
39
- val = val.replace(/\n/g, "\\n");
64
+ val = val.replace(/[\\"\u0000-\u001F]/g, escapeJsonCharacter);
40
65
  break;
41
66
  default:
42
67
  // todo, runtime error
@@ -1,5 +1,4 @@
1
1
  import { INumeric } from "../types/_numeric";
2
- import { Float } from "../types";
3
2
  export interface INmaxInput {
4
3
  val1: number | INumeric;
5
4
  val2: number | INumeric;
@@ -11,4 +10,4 @@ export interface INmaxInput {
11
10
  val8?: number | INumeric;
12
11
  val9?: number | INumeric;
13
12
  }
14
- export declare function nmax(input: INmaxInput): Float;
13
+ export declare function nmax(input: INmaxInput): import("../types").Float | import("../types").Integer8 | import("../types").Integer | import("../types").DecFloat34 | import("../types").Packed;
@@ -1,34 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.nmax = nmax;
4
- const _parse_1 = require("../operators/_parse");
5
- const types_1 = require("../types");
4
+ const _extremum_1 = require("./_extremum");
6
5
  function nmax(input) {
7
- const values = [];
8
- values.push((0, _parse_1.parse)(input.val1));
9
- values.push((0, _parse_1.parse)(input.val2));
10
- if (input.val3) {
11
- values.push((0, _parse_1.parse)(input.val3));
12
- }
13
- if (input.val4) {
14
- values.push((0, _parse_1.parse)(input.val4));
15
- }
16
- if (input.val5) {
17
- values.push((0, _parse_1.parse)(input.val5));
18
- }
19
- if (input.val6) {
20
- values.push((0, _parse_1.parse)(input.val6));
21
- }
22
- if (input.val7) {
23
- values.push((0, _parse_1.parse)(input.val7));
24
- }
25
- if (input.val8) {
26
- values.push((0, _parse_1.parse)(input.val8));
27
- }
28
- if (input.val9) {
29
- values.push((0, _parse_1.parse)(input.val9));
30
- }
31
- values.sort((a, b) => (b - a));
32
- return new types_1.Float().set(values[0]);
6
+ return (0, _extremum_1.extremum)([input.val1, input.val2, input.val3, input.val4, input.val5,
7
+ input.val6, input.val7, input.val8, input.val9], (candidate, best) => candidate > best);
33
8
  }
34
9
  //# sourceMappingURL=nmax.js.map
@@ -1,5 +1,4 @@
1
1
  import { INumeric } from "../types/_numeric";
2
- import { Float } from "../types";
3
2
  export interface INminInput {
4
3
  val1: number | INumeric;
5
4
  val2: number | INumeric;
@@ -11,4 +10,4 @@ export interface INminInput {
11
10
  val8?: number | INumeric;
12
11
  val9?: number | INumeric;
13
12
  }
14
- export declare function nmin(input: INminInput): Float;
13
+ export declare function nmin(input: INminInput): import("../types").Float | import("../types").Integer8 | import("../types").Integer | import("../types").DecFloat34 | import("../types").Packed;
@@ -1,34 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.nmin = nmin;
4
- const _parse_1 = require("../operators/_parse");
5
- const types_1 = require("../types");
4
+ const _extremum_1 = require("./_extremum");
6
5
  function nmin(input) {
7
- const values = [];
8
- values.push((0, _parse_1.parse)(input.val1));
9
- values.push((0, _parse_1.parse)(input.val2));
10
- if (input.val3) {
11
- values.push((0, _parse_1.parse)(input.val3));
12
- }
13
- if (input.val4) {
14
- values.push((0, _parse_1.parse)(input.val4));
15
- }
16
- if (input.val5) {
17
- values.push((0, _parse_1.parse)(input.val5));
18
- }
19
- if (input.val6) {
20
- values.push((0, _parse_1.parse)(input.val6));
21
- }
22
- if (input.val7) {
23
- values.push((0, _parse_1.parse)(input.val7));
24
- }
25
- if (input.val8) {
26
- values.push((0, _parse_1.parse)(input.val8));
27
- }
28
- if (input.val9) {
29
- values.push((0, _parse_1.parse)(input.val9));
30
- }
31
- values.sort((a, b) => (a - b));
32
- return new types_1.Float().set(values[0]);
6
+ return (0, _extremum_1.extremum)([input.val1, input.val2, input.val3, input.val4, input.val5,
7
+ input.val6, input.val7, input.val8, input.val9], (candidate, best) => candidate < best);
33
8
  }
34
9
  //# sourceMappingURL=nmin.js.map
@@ -1,8 +1,17 @@
1
- import { Float } from "../types";
1
+ import { DecFloat34 } from "../types";
2
2
  import { ICharacter } from "../types/_character";
3
3
  import { INumeric } from "../types/_numeric";
4
+ type Input = INumeric | ICharacter | string | number;
5
+ /** round( val = arg {dec = n}|{prec = n} [mode = m] )
6
+ *
7
+ * The argument is converted to decfloat34 and rounded as a decimal number, so
8
+ * round( val = '2.675' dec = 2 ) is 2.68 - not 2.67, which is what scaling the
9
+ * nearest binary float would give. A binary float argument brings its full
10
+ * binary expansion along, the way converting f to decfloat34 does. */
4
11
  export declare function round(input: {
5
- val: ICharacter | string;
6
- dec: INumeric | number;
7
- mode?: INumeric | number;
8
- }): Float;
12
+ val: Input;
13
+ dec?: Input;
14
+ prec?: Input;
15
+ mode?: Input;
16
+ }): DecFloat34;
17
+ export {};
@@ -3,39 +3,87 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.round = round;
4
4
  const _parse_1 = require("../operators/_parse");
5
5
  const types_1 = require("../types");
6
+ // the rounding modes of CL_ABAP_MATH, the decNumber enumeration
7
+ const ROUND_CEILING = 0;
8
+ const ROUND_UP = 1;
9
+ const ROUND_HALF_UP = 2;
10
+ const ROUND_HALF_EVEN = 3;
11
+ const ROUND_HALF_DOWN = 4;
12
+ const ROUND_DOWN = 5;
13
+ const ROUND_FLOOR = 6;
14
+ /** round( val = arg {dec = n}|{prec = n} [mode = m] )
15
+ *
16
+ * The argument is converted to decfloat34 and rounded as a decimal number, so
17
+ * round( val = '2.675' dec = 2 ) is 2.68 - not 2.67, which is what scaling the
18
+ * nearest binary float would give. A binary float argument brings its full
19
+ * binary expansion along, the way converting f to decfloat34 does. */
6
20
  function round(input) {
7
- let mode = input.mode;
8
- if (mode === undefined) {
9
- mode = 2;
21
+ const mode = input.mode === undefined ? ROUND_HALF_UP : (0, _parse_1.parse)(input.mode);
22
+ let arg = input.val;
23
+ if (arg instanceof types_1.FieldSymbol) {
24
+ arg = arg.getPointer();
10
25
  }
11
- else if (typeof mode !== "number") {
12
- mode = mode?.get();
26
+ const val = (0, _parse_1.parse)(arg);
27
+ const text = arg instanceof types_1.Float ? val.toPrecision(34) : String(val);
28
+ const match = /^(-?)(\d*)\.?(\d*)(?:e([+-]?\d+))?$/i.exec(text);
29
+ if (match === null || !Number.isFinite(val)) {
30
+ return new types_1.DecFloat34().set(val);
13
31
  }
14
- const val = (0, _parse_1.parse)(input.val);
15
- const dec = (0, _parse_1.parse)(input.dec);
16
- if (dec !== 0) {
17
- throw new Error("round(), todo, handle decimals");
32
+ const negative = match[1] === "-";
33
+ const digits = BigInt((match[2] + match[3]).replace(/^0+/, "") || "0");
34
+ // the value is digits * 10^exponent
35
+ const exponent = parseInt(match[4] || "0", 10) - match[3].length;
36
+ let dec;
37
+ if (input.prec !== undefined) {
38
+ const prec = (0, _parse_1.parse)(input.prec);
39
+ if (prec <= 0) {
40
+ throw new Error("CX_SY_ARITHMETIC_ERROR, round( ) prec must be positive");
41
+ }
42
+ // position of the most significant digit
43
+ const top = digits.toString().length - 1 + exponent;
44
+ dec = prec - 1 - top;
18
45
  }
19
- const ret = new types_1.Float();
46
+ else {
47
+ dec = input.dec === undefined ? 0 : (0, _parse_1.parse)(input.dec);
48
+ }
49
+ const drop = -exponent - dec;
50
+ if (drop <= 0 || digits === 0n) {
51
+ return new types_1.DecFloat34().set(val);
52
+ }
53
+ const divisor = 10n ** BigInt(drop);
54
+ let kept = digits / divisor;
55
+ const rest = digits % divisor;
56
+ // compare the dropped part with one half of the last kept digit
57
+ const half = rest * 2n === divisor ? 0 : (rest * 2n > divisor ? 1 : -1);
58
+ let away;
20
59
  switch (mode) {
21
- case 1:
22
- ret.set(Math.ceil(val));
60
+ case ROUND_CEILING:
61
+ away = rest > 0n && negative === false;
62
+ break;
63
+ case ROUND_UP:
64
+ away = rest > 0n;
23
65
  break;
24
- case 2:
25
- ret.set(Math.round(val));
66
+ case ROUND_HALF_UP:
67
+ away = half >= 0;
26
68
  break;
27
- case 4:
28
- ret.set(-Math.round(-val));
69
+ case ROUND_HALF_EVEN:
70
+ away = half > 0 || (half === 0 && kept % 2n === 1n);
29
71
  break;
30
- case 5:
31
- ret.set(Math.trunc(val));
72
+ case ROUND_HALF_DOWN:
73
+ away = half > 0;
32
74
  break;
33
- case 6:
34
- ret.set(Math.floor(val));
75
+ case ROUND_DOWN:
76
+ away = false;
77
+ break;
78
+ case ROUND_FLOOR:
79
+ away = rest > 0n && negative === true;
35
80
  break;
36
81
  default:
37
82
  throw new Error("round(), unknown mode: " + mode);
38
83
  }
39
- return ret;
84
+ if (away) {
85
+ kept += 1n;
86
+ }
87
+ return new types_1.DecFloat34().set(Number((negative ? "-" : "") + kept.toString() + "e" + (-dec)));
40
88
  }
41
89
  //# sourceMappingURL=round.js.map
@@ -4,7 +4,6 @@ exports.eq = eq;
4
4
  /* eslint-disable max-len */
5
5
  const types_1 = require("../types");
6
6
  const _parse_1 = require("../operators/_parse");
7
- const initial_1 = require("./initial");
8
7
  function compareTables(left, right) {
9
8
  const leftArray = left.array();
10
9
  const rightArray = right.array();
@@ -35,6 +34,14 @@ function compareStructures(left, right) {
35
34
  }
36
35
  return true;
37
36
  }
37
+ // two x fields of different lengths: the shorter one is padded with 00 on the
38
+ // right, so x'AB' = x'AB00'
39
+ function eqHexPadded(left, right) {
40
+ const l = left.get();
41
+ const r = right.get();
42
+ const length = Math.max(l.length, r.length);
43
+ return l.padEnd(length, "0") === r.padEnd(length, "0");
44
+ }
38
45
  // module locals instead of the imported bindings, as the CommonJS re-export
39
46
  // getters add overhead on every access in the hot path below
40
47
  const IntegerC = types_1.Integer;
@@ -107,7 +114,7 @@ function eq(left, right) {
107
114
  }
108
115
  else if (leftConstructor === HexC || leftConstructor === HexUInt8C) {
109
116
  if (left.getLength() !== right.getLength()) {
110
- return (0, initial_1.initial)(left) && (0, initial_1.initial)(right);
117
+ return eqHexPadded(left, right);
111
118
  }
112
119
  return left.get() === right.get();
113
120
  }
@@ -211,7 +218,7 @@ function eq(left, right) {
211
218
  if (left instanceof types_1.Hex || left instanceof types_1.HexUInt8) {
212
219
  // @ts-ignore
213
220
  if (right.getLength && right.getLength() !== left.getLength()) {
214
- return (0, initial_1.initial)(left) && (0, initial_1.initial)(right);
221
+ return eqHexPadded(left, right);
215
222
  }
216
223
  return right.get() === left.get();
217
224
  }
@@ -340,6 +347,16 @@ function eq(left, right) {
340
347
  else if (right instanceof types_1.Float && typeof l === "number") {
341
348
  r = right.getRaw();
342
349
  }
350
+ else if ((right instanceof types_1.Float || right instanceof types_1.DecFloat34) && typeof l === "string") {
351
+ // a character-like operand is compared as a number: get( ) of a float
352
+ // writes 1,4800000000000000E+02, which no text compares equal with
353
+ r = right.getRaw();
354
+ l = Number(l);
355
+ }
356
+ else if (left instanceof types_1.DecFloat34 && typeof r === "string") {
357
+ l = left.getRaw();
358
+ r = Number(r);
359
+ }
343
360
  else if (left instanceof types_1.Float) {
344
361
  if (typeof r === "number") {
345
362
  l = left.getRaw();
@@ -112,8 +112,14 @@ function gt(left, right) {
112
112
  }
113
113
  ///////////////////////////////////////////////////////////////////
114
114
  function gt_with_hex(left, right) {
115
- const left_hex = get_hex_from_parameter(left);
116
- const right_hex = get_hex_from_parameter(right);
115
+ let left_hex = get_hex_from_parameter(left);
116
+ let right_hex = get_hex_from_parameter(right);
117
+ if ((left instanceof types_1.Hex || left instanceof types_1.HexUInt8) && (right instanceof types_1.Hex || right instanceof types_1.HexUInt8)) {
118
+ // two x fields of different lengths: the shorter one is padded with 00 on the right
119
+ const length = Math.max(left_hex.length, right_hex.length);
120
+ left_hex = left_hex.padEnd(length, "0");
121
+ right_hex = right_hex.padEnd(length, "0");
122
+ }
117
123
  return left_hex > right_hex;
118
124
  }
119
125
  function get_hex_from_parameter(comparison_part) {
@@ -1,4 +1,6 @@
1
1
  import { Table } from "../types";
2
2
  import { ICharacter } from "../types/_character";
3
3
  import { INumeric } from "../types/_numeric";
4
- export declare function compareIn(left: number | string | ICharacter | INumeric, right: Table): boolean;
4
+ type Operand = number | string | ICharacter | INumeric;
5
+ export declare function compareIn(left: Operand, right: Table): boolean;
6
+ export {};
@@ -3,32 +3,49 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.compareIn = compareIn;
4
4
  const cp_1 = require("./cp");
5
5
  const eq_1 = require("./eq");
6
+ const ge_1 = require("./ge");
7
+ const gt_1 = require("./gt");
8
+ const le_1 = require("./le");
9
+ const lt_1 = require("./lt");
6
10
  const ne_1 = require("./ne");
7
- function compareIn(left, right) {
8
- if (right.array().length === 0) {
9
- return true;
11
+ function matches(left, option, low, high) {
12
+ switch (option) {
13
+ case "EQ": return (0, eq_1.eq)(left, low);
14
+ case "NE": return (0, ne_1.ne)(left, low);
15
+ case "GT": return (0, gt_1.gt)(left, low);
16
+ case "GE": return (0, ge_1.ge)(left, low);
17
+ case "LT": return (0, lt_1.lt)(left, low);
18
+ case "LE": return (0, le_1.le)(left, low);
19
+ case "BT": return (0, ge_1.ge)(left, low) && (0, le_1.le)(left, high);
20
+ case "NB": return !((0, ge_1.ge)(left, low) && (0, le_1.le)(left, high));
21
+ case "CP": return (0, cp_1.cp)(left, low);
22
+ case "NP": return !(0, cp_1.cp)(left, low);
23
+ default: throw new Error("compareIn, unknown option " + option);
10
24
  }
25
+ }
26
+ // A value is in a range table when some I row admits it, or there is no I
27
+ // row at all, and no E row admits it. An empty table admits everything.
28
+ function compareIn(left, right) {
29
+ let included = false;
30
+ let hasInclude = false;
11
31
  for (const row of right.array()) {
12
- if ((0, eq_1.eq)(row.get()["sign"], "I") && (0, eq_1.eq)(row.get()["option"], "EQ")) {
13
- if ((0, eq_1.eq)(row.get()["low"], left)) {
14
- return true;
15
- }
16
- }
17
- else if ((0, eq_1.eq)(row.get()["sign"], "E") && (0, eq_1.eq)(row.get()["option"], "EQ")) {
18
- if ((0, ne_1.ne)(row.get()["low"], left)) {
19
- return true;
20
- }
32
+ const r = row.get();
33
+ const sign = r["sign"].get().toString().toUpperCase().trim();
34
+ const option = r["option"].get().toString().toUpperCase().trim();
35
+ const hit = matches(left, option, r["low"], r["high"]);
36
+ if (sign === "I") {
37
+ hasInclude = true;
38
+ included = included || hit;
21
39
  }
22
- else if ((0, eq_1.eq)(row.get()["sign"], "I") && (0, eq_1.eq)(row.get()["option"], "CP")) {
23
- if ((0, cp_1.cp)(left, row.get()["low"])) {
24
- return true;
40
+ else if (sign === "E") {
41
+ if (hit) {
42
+ return false;
25
43
  }
26
44
  }
27
45
  else {
28
- console.dir(row);
29
- throw new Error("compareIn todo");
46
+ throw new Error("compareIn, unknown sign " + sign);
30
47
  }
31
48
  }
32
- return false;
49
+ return hasInclude === false || included;
33
50
  }
34
51
  //# sourceMappingURL=in.js.map
@@ -1,42 +1,80 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.expandIN = expandIN;
4
+ function toSQLValue(value) {
5
+ if (typeof value === "number") {
6
+ return value.toString();
7
+ }
8
+ return `'` + String(value ?? "").replace(/'/g, "''") + "'";
9
+ }
10
+ // one row of a ranges table as a condition that is true when the row matches
11
+ function rowCondition(field, sign, option, low, high) {
12
+ const lowValue = toSQLValue(low);
13
+ switch (option) {
14
+ case "EQ":
15
+ return `${field} = ${lowValue}`;
16
+ case "NE":
17
+ return `${field} <> ${lowValue}`;
18
+ case "GT":
19
+ return `${field} > ${lowValue}`;
20
+ case "GE":
21
+ return `${field} >= ${lowValue}`;
22
+ case "LT":
23
+ return `${field} < ${lowValue}`;
24
+ case "LE":
25
+ return `${field} <= ${lowValue}`;
26
+ case "BT":
27
+ return `(${field} >= ${lowValue} AND ${field} <= ${toSQLValue(high)})`;
28
+ case "NB":
29
+ return `NOT (${field} >= ${lowValue} AND ${field} <= ${toSQLValue(high)})`;
30
+ case "CP":
31
+ case "NP":
32
+ {
33
+ if (sign !== "I" || option !== "CP") {
34
+ // the pattern rules come with a separate change; until then only I CP, as before
35
+ throw new Error(`IN, ${sign} ${option} not supported`);
36
+ }
37
+ const like = `${field} LIKE '` + String(low ?? "").trimEnd().replace(/'/g, "''").replace(/\*/g, "%") + "'";
38
+ return option === "CP" ? like : `NOT ${like}`;
39
+ }
40
+ default:
41
+ throw new Error(`IN, ${sign} ${option} not supported`);
42
+ }
43
+ }
4
44
  // note: must always return an expression, never return empty string
5
45
  // https://www.sqlite.org/lang_select.html
46
+ // The rows with SIGN I are ORed, AND NOT the OR of the rows with SIGN E; a
47
+ // table with E rows only excludes them from everything.
6
48
  function expandIN(fieldName, table) {
7
- let ret = "";
8
49
  if (table.array().length === 0) {
9
50
  // " NOT IN ()" does not work on postgres
10
51
  // LIKE '%' does not work in snowflake with RTRIM collation
11
- ret = `true`;
52
+ return `true`;
12
53
  }
13
- else {
14
- ret = `(`;
15
- const values = [];
16
- fieldName = fieldName.replace("~", `"."`);
17
- for (const row of table.array()) {
18
- const val = `'` + row.get().low?.get().replace(/'/g, "''") + "'";
19
- if (row.get().sign?.get() === "I" && row.get().option?.get() === "EQ") {
20
- values.push(`"${fieldName}" = ` + val);
21
- }
22
- else if (row.get().sign?.get() === "I" && row.get().option?.get() === "NE") {
23
- values.push(`"${fieldName}" <> ` + val);
24
- }
25
- else if (row.get().sign?.get() === "I" && row.get().option?.get() === "GE") {
26
- values.push(`"${fieldName}" >= ` + val);
27
- }
28
- else if (row.get().sign?.get() === "I" && row.get().option?.get() === "LE") {
29
- values.push(`"${fieldName}" <= ` + val);
30
- }
31
- else if (row.get().sign?.get() === "I" && row.get().option?.get() === "CP") {
32
- values.push(`"${fieldName}" LIKE '` + row.get().low?.get().trimEnd().replace(/'/g, "''").replace(/\*/g, "%") + "'");
33
- }
34
- else {
35
- throw new Error(`IN, ${row.get().sign?.get()} ${row.get().option?.get()} not supported`);
36
- }
54
+ const field = `"${fieldName.replace("~", `"."`)}"`;
55
+ const include = [];
56
+ const exclude = [];
57
+ for (const row of table.array()) {
58
+ const sign = row.get().sign?.get();
59
+ const option = row.get().option?.get();
60
+ if (sign !== "I" && sign !== "E") {
61
+ throw new Error(`IN, ${sign} ${option} not supported`);
62
+ }
63
+ const cond = rowCondition(field, sign, option, row.get().low?.get(), row.get().high?.get());
64
+ if (sign === "I") {
65
+ include.push(cond);
37
66
  }
38
- ret += values.join(" OR ") + ")";
67
+ else {
68
+ exclude.push(cond);
69
+ }
70
+ }
71
+ const parts = [];
72
+ if (include.length > 0) {
73
+ parts.push("(" + include.join(" OR ") + ")");
74
+ }
75
+ if (exclude.length > 0) {
76
+ parts.push("NOT (" + exclude.join(" OR ") + ")");
39
77
  }
40
- return ret;
78
+ return "(" + parts.join(" AND ") + ")";
41
79
  }
42
80
  //# sourceMappingURL=expand_in.js.map
@@ -1,6 +1,2 @@
1
1
  import { XString } from "../types";
2
- export declare function get_bit_operation_chunks(left: XString, right: XString): {
3
- leftChunk: number;
4
- rightChunk: number;
5
- chunkLen: number;
6
- }[];
2
+ export declare function bit_operation(left: XString, right: XString, op: (l: number, r: number) => number): XString;