@abaplint/runtime 2.13.96 → 2.13.98
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/build/src/context.d.ts +10 -0
- package/build/src/context.js +4 -0
- package/build/src/operators/divide.d.ts +3 -0
- package/build/src/operators/divide.js +19 -0
- package/build/src/statements/call_function.d.ts +1 -0
- package/build/src/statements/call_function.js +27 -2
- package/build/src/statements/get_run_time.d.ts +2 -1
- package/build/src/statements/get_run_time.js +20 -9
- package/build/src/statements/index.d.ts +1 -2
- package/build/src/statements/index.js +3 -1
- package/build/src/statements/loop.js +8 -9
- package/build/src/statements/read_table.js +5 -0
- package/build/src/types/table.d.ts +5 -0
- package/build/src/types/table.js +17 -8
- package/package.json +1 -1
package/build/src/context.d.ts
CHANGED
|
@@ -14,9 +14,19 @@ export declare class Context {
|
|
|
14
14
|
RFCDestinations: {
|
|
15
15
|
[name: string]: RFC.RFCClient;
|
|
16
16
|
};
|
|
17
|
+
updateTask: {
|
|
18
|
+
register(name: string, param: {
|
|
19
|
+
exporting?: any;
|
|
20
|
+
tables?: any;
|
|
21
|
+
}): Promise<void> | void;
|
|
22
|
+
} | undefined;
|
|
17
23
|
dataset: DatasetHost | undefined;
|
|
18
24
|
datasets: {
|
|
19
25
|
[name: string]: OpenDataset;
|
|
20
26
|
};
|
|
27
|
+
runTime: {
|
|
28
|
+
start: number;
|
|
29
|
+
last: number;
|
|
30
|
+
} | undefined;
|
|
21
31
|
defaultDB(): DatabaseClient;
|
|
22
32
|
}
|
package/build/src/context.js
CHANGED
|
@@ -8,10 +8,14 @@ class Context {
|
|
|
8
8
|
// DEFAULT and secondary database connections
|
|
9
9
|
databaseConnections = {};
|
|
10
10
|
RFCDestinations = {};
|
|
11
|
+
// CALL FUNCTION IN UPDATE TASK hands the copied parameters to the host, if one is set
|
|
12
|
+
updateTask = undefined;
|
|
11
13
|
// the file system OPEN DATASET and friends read and write; none by default,
|
|
12
14
|
// and then every DATASET statement throws
|
|
13
15
|
dataset = undefined;
|
|
14
16
|
datasets = {};
|
|
17
|
+
// GET RUN TIME, the clock reading of the first call, and the last value returned
|
|
18
|
+
runTime = undefined;
|
|
15
19
|
defaultDB() {
|
|
16
20
|
if (this.databaseConnections["DEFAULT"] === undefined) {
|
|
17
21
|
throw new Error("Runtime, database not initialized");
|
|
@@ -2,3 +2,6 @@ import { Float, Integer, Integer8 } from "../types";
|
|
|
2
2
|
import { ICharacter } from "../types/_character";
|
|
3
3
|
import { INumeric } from "../types/_numeric";
|
|
4
4
|
export declare function divide(left: INumeric | ICharacter | Integer8 | string | number, right: INumeric | ICharacter | Integer8 | string | number): Float | Integer8 | Integer;
|
|
5
|
+
/** "/" in calculation type int8, which the transpiler knows from an int8 target: the
|
|
6
|
+
* operands are int8 and the quotient is rounded half away from zero, 7 / 2 = 4, -7 / 2 = -4 */
|
|
7
|
+
export declare function divideInt8(left: INumeric | ICharacter | Integer8 | string | number, right: INumeric | ICharacter | Integer8 | string | number): Integer8;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.divide = divide;
|
|
4
|
+
exports.divideInt8 = divideInt8;
|
|
4
5
|
const throw_error_1 = require("../throw_error");
|
|
5
6
|
const types_1 = require("../types");
|
|
6
7
|
const _parse_1 = require("./_parse");
|
|
@@ -42,4 +43,22 @@ function isIntegerOperand(val) {
|
|
|
42
43
|
}
|
|
43
44
|
return val instanceof types_1.Integer8;
|
|
44
45
|
}
|
|
46
|
+
/** "/" in calculation type int8, which the transpiler knows from an int8 target: the
|
|
47
|
+
* operands are int8 and the quotient is rounded half away from zero, 7 / 2 = 4, -7 / 2 = -4 */
|
|
48
|
+
function divideInt8(left, right) {
|
|
49
|
+
const l = left instanceof types_1.Integer8 ? left.get() : new types_1.Integer8().set(left).get();
|
|
50
|
+
const r = right instanceof types_1.Integer8 ? right.get() : new types_1.Integer8().set(right).get();
|
|
51
|
+
if (r === 0n) {
|
|
52
|
+
if (l === 0n) {
|
|
53
|
+
return new types_1.Integer8().set(0n);
|
|
54
|
+
}
|
|
55
|
+
(0, throw_error_1.throwError)("CX_SY_ZERODIVIDE");
|
|
56
|
+
}
|
|
57
|
+
let q = l / r;
|
|
58
|
+
const rem = l % r;
|
|
59
|
+
if ((rem < 0n ? -rem : rem) * 2n >= (r < 0n ? -r : r)) {
|
|
60
|
+
q = (l < 0n) === (r < 0n) ? q + 1n : q - 1n;
|
|
61
|
+
}
|
|
62
|
+
return new types_1.Integer8().set(q);
|
|
63
|
+
}
|
|
45
64
|
//# sourceMappingURL=divide.js.map
|
|
@@ -9,7 +9,7 @@ class CallFunction {
|
|
|
9
9
|
constructor(context) {
|
|
10
10
|
this.context = context;
|
|
11
11
|
}
|
|
12
|
-
//
|
|
12
|
+
// called for DESTINATION, CALLING or IN UPDATE TASK
|
|
13
13
|
async callFunction(options) {
|
|
14
14
|
const param = {
|
|
15
15
|
exporting: options.exporting,
|
|
@@ -20,7 +20,32 @@ class CallFunction {
|
|
|
20
20
|
};
|
|
21
21
|
options.name = options.name.trimEnd();
|
|
22
22
|
const fm = abap.FunctionModules[options.name];
|
|
23
|
-
if (options.
|
|
23
|
+
if (options.updateTask) {
|
|
24
|
+
if (fm === undefined) {
|
|
25
|
+
(0, throw_error_1.throwError)("CX_SY_DYN_CALL_ILLEGAL_FUNC");
|
|
26
|
+
}
|
|
27
|
+
const copy = (values) => {
|
|
28
|
+
if (values === undefined) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
const result = {};
|
|
32
|
+
for (const key of Object.keys(values)) {
|
|
33
|
+
const value = values[key];
|
|
34
|
+
result[key] = value instanceof types_1.FieldSymbol ? value.getPointer().clone() : value.clone();
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
// IMPORTING and CHANGING do not apply to update modules.
|
|
39
|
+
const copied = { exporting: copy(options.exporting), tables: copy(options.tables) };
|
|
40
|
+
if (this.context.updateTask) {
|
|
41
|
+
await this.context.updateTask.register(options.name, copied);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
await fm(copied);
|
|
45
|
+
}
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
else if (options.destination) {
|
|
24
49
|
if (options.destination.trim() === "") {
|
|
25
50
|
if (fm === undefined) {
|
|
26
51
|
(0, throw_error_1.throwError)("CX_SY_DYN_CALL_ILLEGAL_FUNC");
|
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getRunTime = getRunTime;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
// milliseconds with a fraction, from a monotonic clock where there is one:
|
|
5
|
+
// performance.now() in Node, Bun and browsers, Date.now() otherwise
|
|
6
|
+
function now() {
|
|
7
|
+
if (typeof performance === "object" && typeof performance?.now === "function") {
|
|
8
|
+
return performance.now();
|
|
9
9
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
return Date.now();
|
|
11
|
+
}
|
|
12
|
+
// GET RUN TIME FIELD: microseconds since the first call in the internal
|
|
13
|
+
// session, which gives 0. The first call is per context, so per ABAP instance
|
|
14
|
+
function getRunTime(context, value) {
|
|
15
|
+
const t = now();
|
|
16
|
+
if (context.runTime === undefined) {
|
|
17
|
+
context.runTime = { start: t, last: 0 };
|
|
18
|
+
}
|
|
19
|
+
let micro = Math.floor((t - context.runTime.start) * 1000);
|
|
20
|
+
// never backwards, also when the clock is Date.now()
|
|
21
|
+
if (micro < context.runTime.last) {
|
|
22
|
+
micro = context.runTime.last;
|
|
14
23
|
}
|
|
24
|
+
context.runTime.last = micro;
|
|
25
|
+
value.set(micro);
|
|
15
26
|
}
|
|
16
27
|
//# sourceMappingURL=get_run_time.js.map
|
|
@@ -23,7 +23,6 @@ import { getLocale } from "./get_locale";
|
|
|
23
23
|
import { unpack } from "./unpack";
|
|
24
24
|
import { getParameter } from "./get_parameter";
|
|
25
25
|
import { setLocale } from "./set_locale";
|
|
26
|
-
import { getRunTime } from "./get_run_time";
|
|
27
26
|
import { getTime } from "./get_time";
|
|
28
27
|
import { IInsertDatabaseOptions } from "./insert_database";
|
|
29
28
|
import { insertInternal } from "./insert_internal";
|
|
@@ -73,7 +72,6 @@ export declare class Statements {
|
|
|
73
72
|
getBit: typeof getBit;
|
|
74
73
|
getLocale: typeof getLocale;
|
|
75
74
|
getParameter: typeof getParameter;
|
|
76
|
-
getRunTime: typeof getRunTime;
|
|
77
75
|
getTime: typeof getTime;
|
|
78
76
|
insertInternal: typeof insertInternal;
|
|
79
77
|
loop: typeof loop;
|
|
@@ -96,6 +94,7 @@ export declare class Statements {
|
|
|
96
94
|
private readonly context;
|
|
97
95
|
constructor(context: Context);
|
|
98
96
|
_setTrace(min?: number, totals?: boolean): Trace;
|
|
97
|
+
getRunTime(value: INumeric): void;
|
|
99
98
|
openCursor(target: INumeric, select: string, options: IOpenCursorDatabaseOptions): Promise<void>;
|
|
100
99
|
fetchNextCursor(cursor: INumeric, target: any, packageSize?: INumeric): Promise<void>;
|
|
101
100
|
closeCursor(cursor: INumeric): Promise<void>;
|
|
@@ -76,7 +76,6 @@ class Statements {
|
|
|
76
76
|
getBit = get_bit_1.getBit;
|
|
77
77
|
getLocale = get_locale_1.getLocale;
|
|
78
78
|
getParameter = get_parameter_1.getParameter;
|
|
79
|
-
getRunTime = get_run_time_1.getRunTime;
|
|
80
79
|
getTime = get_time_1.getTime;
|
|
81
80
|
insertInternal = insert_internal_1.insertInternal;
|
|
82
81
|
loop = loop_1.loop;
|
|
@@ -103,6 +102,9 @@ class Statements {
|
|
|
103
102
|
_setTrace(min = 10, totals = false) {
|
|
104
103
|
return new trace_1.Trace().setTrace(min, totals, this);
|
|
105
104
|
}
|
|
105
|
+
getRunTime(value) {
|
|
106
|
+
(0, get_run_time_1.getRunTime)(this.context, value);
|
|
107
|
+
}
|
|
106
108
|
async openCursor(target, select, options) {
|
|
107
109
|
const num = await (0, open_cursor_1.openCursor)(this.context, select, options);
|
|
108
110
|
target.set(num);
|
|
@@ -152,11 +152,12 @@ async function* loop(table, options) {
|
|
|
152
152
|
let loopTo = options?.to && options.to.get() < length ? options.to.get() : length;
|
|
153
153
|
let array = [];
|
|
154
154
|
let block = undefined;
|
|
155
|
-
//
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
155
|
+
// the secondary key the loop runs over; undefined is the primary key, also
|
|
156
|
+
// when it is named - USING KEY PRIMARY_KEY, or a dynamic name holding it
|
|
157
|
+
const usingKey = (0, types_1.secondaryKeyName)(options?.usingKey);
|
|
158
|
+
if (usingKey !== undefined) {
|
|
159
|
+
array = table.getSecondaryIndex(usingKey);
|
|
160
|
+
const { from, to } = determineFromTo(array, options?.topEquals, table.getKeyByName(usingKey));
|
|
160
161
|
loopFrom = Math.max(loopFrom, from) - 1;
|
|
161
162
|
loopTo = Math.min(loopTo, to);
|
|
162
163
|
}
|
|
@@ -195,9 +196,7 @@ async function* loop(table, options) {
|
|
|
195
196
|
// The same goes for a loop that reads an index table through a hash
|
|
196
197
|
// secondary key. Handing out 1, 2, 3 there looks helpful and is a lie the
|
|
197
198
|
// caller cannot tell from the truth.
|
|
198
|
-
const usedKey =
|
|
199
|
-
? undefined
|
|
200
|
-
: table.getKeyByName(options.usingKey);
|
|
199
|
+
const usedKey = usingKey === undefined ? undefined : table.getKeyByName(usingKey);
|
|
201
200
|
const hasRowNumber = usedKey !== undefined
|
|
202
201
|
? usedKey.type !== types_1.TableAccessType.hashed
|
|
203
202
|
: !(table instanceof types_1.HashedTable);
|
|
@@ -226,7 +225,7 @@ async function* loop(table, options) {
|
|
|
226
225
|
options?.atLast?.(loopController.index + 1 >= loopController.loopTo);
|
|
227
226
|
yield current;
|
|
228
227
|
loopController.index++;
|
|
229
|
-
if (options?.to === undefined &&
|
|
228
|
+
if (options?.to === undefined && usingKey === undefined) {
|
|
230
229
|
// extra rows might have been inserted inside the loop
|
|
231
230
|
loopController.loopTo = array.length;
|
|
232
231
|
}
|
|
@@ -169,6 +169,11 @@ function readTable(table, options) {
|
|
|
169
169
|
// return readTable(table.getPointer(), options);
|
|
170
170
|
table = table.getPointer();
|
|
171
171
|
}
|
|
172
|
+
// WITH [TABLE] KEY primary_key COMPONENTS reads as the same READ without
|
|
173
|
+
// the key name; any other name, as ABAP reads it (secondaryKeyName)
|
|
174
|
+
if (options?.keyName !== undefined && (0, types_1.secondaryKeyName)(options.keyName) !== options.keyName) {
|
|
175
|
+
options = { ...options, keyName: (0, types_1.secondaryKeyName)(options.keyName) };
|
|
176
|
+
}
|
|
172
177
|
// check if it is a primary index read specified with WITH KEY instead of WITH TABLE KEY
|
|
173
178
|
if (options?.withTableKey === undefined
|
|
174
179
|
&& options?.withKeySimple
|
|
@@ -45,6 +45,11 @@ interface ITable {
|
|
|
45
45
|
export declare class TableFactory {
|
|
46
46
|
static construct(rowType: TableRowType, options?: ITableOptions, qualifiedName?: string): Table | HashedTable;
|
|
47
47
|
}
|
|
48
|
+
/** The secondary key a key name selects, as ABAP reads the name: without the
|
|
49
|
+
* blanks a c field pads it with, in any case - and undefined for the primary
|
|
50
|
+
* key, which primary_key names however it is written, and so does an initial
|
|
51
|
+
* name (a dynamic USING KEY ( name ) that is empty). */
|
|
52
|
+
export declare function secondaryKeyName(name: string | undefined): string | undefined;
|
|
48
53
|
export declare class HashedTable implements ITable {
|
|
49
54
|
private value;
|
|
50
55
|
private readonly header;
|
package/build/src/types/table.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Table = exports.HashedTable = exports.TableFactory = exports.LoopController = exports.TableKeyType = exports.TableAccessType = void 0;
|
|
4
|
+
exports.secondaryKeyName = secondaryKeyName;
|
|
4
5
|
const integer_1 = require("./integer");
|
|
5
6
|
const float_1 = require("./float");
|
|
6
7
|
const abap_object_1 = require("./abap_object");
|
|
@@ -75,6 +76,14 @@ export class SortedTable {
|
|
|
75
76
|
// todo
|
|
76
77
|
}
|
|
77
78
|
*/
|
|
79
|
+
/** The secondary key a key name selects, as ABAP reads the name: without the
|
|
80
|
+
* blanks a c field pads it with, in any case - and undefined for the primary
|
|
81
|
+
* key, which primary_key names however it is written, and so does an initial
|
|
82
|
+
* name (a dynamic USING KEY ( name ) that is empty). */
|
|
83
|
+
function secondaryKeyName(name) {
|
|
84
|
+
const trimmed = name?.trimEnd();
|
|
85
|
+
return trimmed === undefined || trimmed === "" || trimmed.toLowerCase() === "primary_key" ? undefined : trimmed;
|
|
86
|
+
}
|
|
78
87
|
class HashedTable {
|
|
79
88
|
value;
|
|
80
89
|
header;
|
|
@@ -107,11 +116,11 @@ class HashedTable {
|
|
|
107
116
|
return Object.keys(this.value).length;
|
|
108
117
|
}
|
|
109
118
|
getKeyByName(name) {
|
|
110
|
-
return this.getOptions()?.secondary?.find(s => s.name.toUpperCase() === name.toUpperCase());
|
|
119
|
+
return this.getOptions()?.secondary?.find(s => s.name.toUpperCase() === name.trimEnd().toUpperCase());
|
|
111
120
|
}
|
|
112
121
|
getSecondaryIndex(name) {
|
|
113
|
-
if (this.secondaryIndexes[name.toUpperCase()]) {
|
|
114
|
-
return this.secondaryIndexes[name.toUpperCase()];
|
|
122
|
+
if (this.secondaryIndexes[name.trimEnd().toUpperCase()]) {
|
|
123
|
+
return this.secondaryIndexes[name.trimEnd().toUpperCase()];
|
|
115
124
|
}
|
|
116
125
|
const secondary = this.getKeyByName(name);
|
|
117
126
|
if (secondary === undefined) {
|
|
@@ -120,7 +129,7 @@ class HashedTable {
|
|
|
120
129
|
// note, array() already is a copy, so it can be used,
|
|
121
130
|
const copy = secondaryDuplicatesFirst(this.array(), secondary);
|
|
122
131
|
(0, sort_1.sort)(copy, { by: secondary.keyFields.map(k => { return { component: k.toLowerCase() }; }) });
|
|
123
|
-
this.secondaryIndexes[name.toUpperCase()] = copy;
|
|
132
|
+
this.secondaryIndexes[name.trimEnd().toUpperCase()] = copy;
|
|
124
133
|
return copy;
|
|
125
134
|
}
|
|
126
135
|
buildHashFromData(data) {
|
|
@@ -364,11 +373,11 @@ class Table {
|
|
|
364
373
|
return this.value.length;
|
|
365
374
|
}
|
|
366
375
|
getKeyByName(name) {
|
|
367
|
-
return this.getOptions()?.secondary?.find(s => s.name.toUpperCase() === name.toUpperCase());
|
|
376
|
+
return this.getOptions()?.secondary?.find(s => s.name.toUpperCase() === name.trimEnd().toUpperCase());
|
|
368
377
|
}
|
|
369
378
|
getSecondaryIndex(name) {
|
|
370
|
-
if (this.secondaryIndexes[name.toUpperCase()]) {
|
|
371
|
-
return this.secondaryIndexes[name.toUpperCase()];
|
|
379
|
+
if (this.secondaryIndexes[name.trimEnd().toUpperCase()]) {
|
|
380
|
+
return this.secondaryIndexes[name.trimEnd().toUpperCase()];
|
|
372
381
|
}
|
|
373
382
|
const secondary = this.getKeyByName(name);
|
|
374
383
|
if (secondary === undefined) {
|
|
@@ -376,7 +385,7 @@ class Table {
|
|
|
376
385
|
}
|
|
377
386
|
const copy = secondaryDuplicatesFirst([...this.value], secondary);
|
|
378
387
|
(0, sort_1.sort)(copy, { by: secondary.keyFields.map(k => { return { component: k.toLowerCase() }; }), skipSortedCheck: true });
|
|
379
|
-
this.secondaryIndexes[name.toUpperCase()] = copy;
|
|
388
|
+
this.secondaryIndexes[name.trimEnd().toUpperCase()] = copy;
|
|
380
389
|
return copy;
|
|
381
390
|
}
|
|
382
391
|
getQualifiedName() {
|