@xapi-js/core 1.5.0 → 1.6.1
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/dist/index.cjs +260 -29
- package/dist/index.d.cts +70 -6
- package/dist/index.d.ts +70 -6
- package/dist/index.js +257 -30
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -14,11 +14,16 @@ const rowType = [
|
|
|
14
14
|
const columnType = [
|
|
15
15
|
"STRING",
|
|
16
16
|
"INT",
|
|
17
|
+
"LONG",
|
|
17
18
|
"FLOAT",
|
|
19
|
+
"DOUBLE",
|
|
18
20
|
"DECIMAL",
|
|
19
21
|
"BIGDECIMAL",
|
|
22
|
+
"BIG_DECIMAL",
|
|
23
|
+
"BOOLEAN",
|
|
20
24
|
"DATE",
|
|
21
25
|
"DATETIME",
|
|
26
|
+
"DATE_TIME",
|
|
22
27
|
"TIME",
|
|
23
28
|
"BLOB"
|
|
24
29
|
];
|
|
@@ -368,8 +373,23 @@ function uint8ArrayToBase64(uint8Array) {
|
|
|
368
373
|
* @param value - The string to convert.
|
|
369
374
|
* @returns A Date object if the string is a valid date/time, otherwise undefined.
|
|
370
375
|
*/
|
|
371
|
-
function stringToDate(value) {
|
|
376
|
+
function stringToDate(value, type) {
|
|
372
377
|
if (!value) return void 0;
|
|
378
|
+
const normalizedType = type ? normalizeColumnType(type) : void 0;
|
|
379
|
+
if (normalizedType === "TIME") {
|
|
380
|
+
if (value.length !== 6 && value.length !== 9) return void 0;
|
|
381
|
+
const hours = parseInt(value.substring(0, 2), 10);
|
|
382
|
+
const minutes = parseInt(value.substring(2, 4), 10);
|
|
383
|
+
const seconds = parseInt(value.substring(4, 6), 10);
|
|
384
|
+
const milliseconds = value.length === 9 ? parseInt(value.substring(6, 9), 10) : 0;
|
|
385
|
+
if ([
|
|
386
|
+
hours,
|
|
387
|
+
minutes,
|
|
388
|
+
seconds,
|
|
389
|
+
milliseconds
|
|
390
|
+
].some(Number.isNaN) || hours > 23 || minutes > 59 || seconds > 59 || milliseconds > 999) return void 0;
|
|
391
|
+
return new Date(1970, 0, 1, hours, minutes, seconds, milliseconds);
|
|
392
|
+
}
|
|
373
393
|
let year;
|
|
374
394
|
let month;
|
|
375
395
|
let day;
|
|
@@ -377,7 +397,7 @@ function stringToDate(value) {
|
|
|
377
397
|
let minutes = 0;
|
|
378
398
|
let seconds = 0;
|
|
379
399
|
let milliseconds = 0;
|
|
380
|
-
if (value.length < 6 || value.length > 16) return;
|
|
400
|
+
if (value.length < 6 || value.length > (normalizedType ? 17 : 16)) return;
|
|
381
401
|
if (value.length >= 8) {
|
|
382
402
|
year = parseInt(value.substring(0, 4), 10);
|
|
383
403
|
month = parseInt(value.substring(4, 6), 10) - 1;
|
|
@@ -396,7 +416,10 @@ function stringToDate(value) {
|
|
|
396
416
|
minutes = parseInt(value.substring(10, 12), 10);
|
|
397
417
|
seconds = parseInt(value.substring(12, 14), 10);
|
|
398
418
|
}
|
|
399
|
-
if (value.length === 16
|
|
419
|
+
if (value.length === 16 || value.length === 17) {
|
|
420
|
+
milliseconds = parseInt(value.substring(14, value.length), 10);
|
|
421
|
+
if (value.length === 16 && normalizedType) milliseconds *= 10;
|
|
422
|
+
}
|
|
400
423
|
if (year < 1970 || year > 9999 || month < 0 || month > 11 || day < 1 || day > 31 || hours < 0 || hours > 23 || minutes < 0 || minutes > 59 || seconds < 0 || seconds > 59 || milliseconds < 0 || milliseconds > 999) return;
|
|
401
424
|
const date = new Date(year, month, day, hours, minutes, seconds, milliseconds);
|
|
402
425
|
if (isNaN(date.getTime())) return;
|
|
@@ -415,10 +438,10 @@ function dateToString(date, type) {
|
|
|
415
438
|
const hours = date.getHours().toString().padStart(2, "0");
|
|
416
439
|
const minutes = date.getMinutes().toString().padStart(2, "0");
|
|
417
440
|
const seconds = date.getSeconds().toString().padStart(2, "0");
|
|
418
|
-
switch (type) {
|
|
441
|
+
switch (normalizeColumnType(type)) {
|
|
419
442
|
case "DATE": return `${year}${month}${day}`;
|
|
420
|
-
case "DATETIME": return `${year}${month}${day}${hours}${minutes}${seconds}`;
|
|
421
|
-
case "TIME": return `${hours}${minutes}${seconds}`;
|
|
443
|
+
case "DATETIME": return `${year}${month}${day}${hours}${minutes}${seconds}${date.getMilliseconds() ? date.getMilliseconds().toString().padStart(3, "0") : ""}`;
|
|
444
|
+
case "TIME": return `${hours}${minutes}${seconds}${date.getMilliseconds() ? date.getMilliseconds().toString().padStart(3, "0") : ""}`;
|
|
422
445
|
default: return "";
|
|
423
446
|
}
|
|
424
447
|
}
|
|
@@ -466,12 +489,16 @@ function stringToReadableStream(str) {
|
|
|
466
489
|
* @throws {ColumnTypeError} if the column type is unsupported.
|
|
467
490
|
*/
|
|
468
491
|
function convertToColumnType(value, type) {
|
|
469
|
-
|
|
492
|
+
const normalizedType = normalizeColumnType(type);
|
|
493
|
+
switch (normalizeColumnType(type)) {
|
|
470
494
|
case "INT":
|
|
471
495
|
const intValue = parseInt(value, 10);
|
|
472
496
|
return isNaN(intValue) ? value : intValue;
|
|
473
497
|
case "FLOAT":
|
|
498
|
+
case "DOUBLE":
|
|
499
|
+
case "LONG":
|
|
474
500
|
case "BIGDECIMAL":
|
|
501
|
+
case "BIG_DECIMAL":
|
|
475
502
|
const floatValue = parseFloat(value);
|
|
476
503
|
return isNaN(floatValue) ? value : floatValue;
|
|
477
504
|
case "DECIMAL":
|
|
@@ -479,14 +506,29 @@ function convertToColumnType(value, type) {
|
|
|
479
506
|
return isNaN(decimalValue) ? value : decimalValue;
|
|
480
507
|
case "DATE":
|
|
481
508
|
case "DATETIME":
|
|
482
|
-
case "
|
|
509
|
+
case "DATE_TIME":
|
|
510
|
+
case "TIME": return stringToDate(value, normalizedType) || value;
|
|
511
|
+
case "BOOLEAN":
|
|
512
|
+
if (value === "true" || value === "1" || value === 1 || value === true) return true;
|
|
513
|
+
if (value === "false" || value === "0" || value === 0 || value === false) return false;
|
|
514
|
+
return value;
|
|
483
515
|
case "BLOB": try {
|
|
484
516
|
return base64ToUint8Array(value);
|
|
485
517
|
} catch {
|
|
486
518
|
return value;
|
|
487
519
|
}
|
|
488
520
|
case "STRING": return value;
|
|
489
|
-
default: throw new ColumnTypeError(`Unsupported column type: ${
|
|
521
|
+
default: throw new ColumnTypeError(`Unsupported column type: ${normalizedType}`);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
/** Normalizes X-API/Java type spellings to the names used by Dataset XML. */
|
|
525
|
+
function normalizeColumnType(type) {
|
|
526
|
+
const normalized = type?.replace(/[- ]/g, "_").toUpperCase();
|
|
527
|
+
switch (normalized) {
|
|
528
|
+
case "DATE_TIME": return "DATETIME";
|
|
529
|
+
case "BIG_DECIMAL": return "BIGDECIMAL";
|
|
530
|
+
case "BOOL": return "BOOLEAN";
|
|
531
|
+
default: return normalized || "STRING";
|
|
490
532
|
}
|
|
491
533
|
}
|
|
492
534
|
/**
|
|
@@ -498,12 +540,17 @@ function convertToColumnType(value, type) {
|
|
|
498
540
|
function convertToString(value, type) {
|
|
499
541
|
switch (type) {
|
|
500
542
|
case "INT":
|
|
543
|
+
case "LONG":
|
|
501
544
|
case "BIGDECIMAL":
|
|
545
|
+
case "BIG_DECIMAL":
|
|
502
546
|
case "FLOAT":
|
|
547
|
+
case "DOUBLE":
|
|
503
548
|
case "DECIMAL": return String(value);
|
|
549
|
+
case "BOOLEAN": return value ? "true" : "false";
|
|
504
550
|
case "DATE":
|
|
505
551
|
case "DATETIME":
|
|
506
|
-
case "
|
|
552
|
+
case "DATE_TIME":
|
|
553
|
+
case "TIME": return dateToString(value, normalizeColumnType(type));
|
|
507
554
|
case "BLOB": return uint8ArrayToBase64(value);
|
|
508
555
|
case "STRING": return String(value);
|
|
509
556
|
default: return String(value);
|
|
@@ -928,8 +975,9 @@ function parseColumnInfo(columnInfoElement, dataset) {
|
|
|
928
975
|
dataset.addConstColumn({
|
|
929
976
|
id: attrs?.id,
|
|
930
977
|
size: sizeStr ? parseInt(sizeStr, 10) : 0,
|
|
931
|
-
type: attrs?.type
|
|
932
|
-
value: parseValue(attrs?.value, attrs?.type)
|
|
978
|
+
type: normalizeColumnType(attrs?.type),
|
|
979
|
+
value: parseValue(attrs?.value, attrs?.type),
|
|
980
|
+
rawValue: attrs?.value
|
|
933
981
|
});
|
|
934
982
|
} else if (tagName === "Column") {
|
|
935
983
|
const attrs = colInfo.attributes;
|
|
@@ -937,7 +985,7 @@ function parseColumnInfo(columnInfoElement, dataset) {
|
|
|
937
985
|
dataset.addColumn({
|
|
938
986
|
id: attrs?.id,
|
|
939
987
|
size: sizeStr ? parseInt(sizeStr, 10) : 0,
|
|
940
|
-
type: attrs?.type
|
|
988
|
+
type: normalizeColumnType(attrs?.type)
|
|
941
989
|
});
|
|
942
990
|
}
|
|
943
991
|
}
|
|
@@ -967,7 +1015,8 @@ function parseRows(rowsElement, dataset) {
|
|
|
967
1015
|
const castedValue = parseValue(value, columnInfo.type);
|
|
968
1016
|
currentRow.cols.push({
|
|
969
1017
|
id: colId,
|
|
970
|
-
value: castedValue
|
|
1018
|
+
value: castedValue,
|
|
1019
|
+
rawValue: value
|
|
971
1020
|
});
|
|
972
1021
|
} else if (colTagName === "OrgRow") {
|
|
973
1022
|
const orgRow = [];
|
|
@@ -981,7 +1030,8 @@ function parseRows(rowsElement, dataset) {
|
|
|
981
1030
|
const castedValue = parseValue(value, dataset.getColumnInfo(colId).type);
|
|
982
1031
|
orgRow.push({
|
|
983
1032
|
id: colId,
|
|
984
|
-
value: castedValue
|
|
1033
|
+
value: castedValue,
|
|
1034
|
+
rawValue: value
|
|
985
1035
|
});
|
|
986
1036
|
}
|
|
987
1037
|
}
|
|
@@ -1005,8 +1055,9 @@ function parseParameters(parametersElement, xapiRoot) {
|
|
|
1005
1055
|
const value = p.children?.[0] ?? attrs?.value;
|
|
1006
1056
|
xapiRoot.addParameter({
|
|
1007
1057
|
id,
|
|
1008
|
-
type,
|
|
1009
|
-
value: parseValue(value, type)
|
|
1058
|
+
type: normalizeColumnType(type),
|
|
1059
|
+
value: parseValue(value, type),
|
|
1060
|
+
rawValue: value
|
|
1010
1061
|
});
|
|
1011
1062
|
}
|
|
1012
1063
|
}
|
|
@@ -1031,7 +1082,7 @@ function writeParameters(builder, parameters) {
|
|
|
1031
1082
|
builder.writeStartElement("Parameters");
|
|
1032
1083
|
for (const parameter of parameters) {
|
|
1033
1084
|
const attrs = { id: parameter.id };
|
|
1034
|
-
if (parameter.type !== void 0) attrs.type = parameter.type;
|
|
1085
|
+
if (parameter.type !== void 0) attrs.type = normalizeColumnType(parameter.type);
|
|
1035
1086
|
if (parameter.value !== void 0) if (typeof parameter.value === "string") attrs.value = parameter.value;
|
|
1036
1087
|
else if (parameter.value instanceof Date) attrs.value = dateToString(parameter.value, parameter.type);
|
|
1037
1088
|
else if (parameter.value instanceof Uint8Array) attrs.value = uint8ArrayToBase64(parameter.value);
|
|
@@ -1047,13 +1098,13 @@ function writeDataset(builder, dataset) {
|
|
|
1047
1098
|
for (const constCol of dataset.getConstColumns()) builder.writeStartElement("ConstColumn", {
|
|
1048
1099
|
id: constCol.id,
|
|
1049
1100
|
size: String(constCol.size),
|
|
1050
|
-
type: constCol.type,
|
|
1101
|
+
type: normalizeColumnType(constCol.type),
|
|
1051
1102
|
value: constCol.value !== void 0 ? String(constCol.value) : ""
|
|
1052
1103
|
}, true);
|
|
1053
1104
|
for (const col of dataset.getColumns()) builder.writeStartElement("Column", {
|
|
1054
1105
|
id: col.id,
|
|
1055
1106
|
size: String(col.size),
|
|
1056
|
-
type: col.type
|
|
1107
|
+
type: normalizeColumnType(col.type)
|
|
1057
1108
|
}, true);
|
|
1058
1109
|
builder.writeEndElement("ColumnInfo");
|
|
1059
1110
|
}
|
|
@@ -1080,14 +1131,30 @@ function writeColumn(builder, dataset, col) {
|
|
|
1080
1131
|
}
|
|
1081
1132
|
//#endregion
|
|
1082
1133
|
//#region src/schema.ts
|
|
1134
|
+
const schemaCache = /* @__PURE__ */ new WeakMap();
|
|
1135
|
+
function compileSchema(schema) {
|
|
1136
|
+
const cached = schemaCache.get(schema);
|
|
1137
|
+
if (cached) return cached;
|
|
1138
|
+
const compiled = {
|
|
1139
|
+
parameters: new Map(Object.entries(schema.parameters)),
|
|
1140
|
+
datasets: new Map(Object.entries(schema.datasets).map(([id, dataset]) => [id, { columns: new Map(Object.entries(dataset.columns)) }]))
|
|
1141
|
+
};
|
|
1142
|
+
schemaCache.set(schema, compiled);
|
|
1143
|
+
return compiled;
|
|
1144
|
+
}
|
|
1083
1145
|
const defaultSizes = {
|
|
1084
1146
|
STRING: 256,
|
|
1085
1147
|
INT: 10,
|
|
1148
|
+
LONG: 19,
|
|
1086
1149
|
FLOAT: 20,
|
|
1150
|
+
DOUBLE: 20,
|
|
1087
1151
|
DECIMAL: 20,
|
|
1088
1152
|
BIGDECIMAL: 30,
|
|
1153
|
+
BIG_DECIMAL: 30,
|
|
1154
|
+
BOOLEAN: 5,
|
|
1089
1155
|
DATE: 8,
|
|
1090
1156
|
DATETIME: 17,
|
|
1157
|
+
DATE_TIME: 17,
|
|
1091
1158
|
TIME: 6,
|
|
1092
1159
|
BLOB: 1e3
|
|
1093
1160
|
};
|
|
@@ -1121,11 +1188,16 @@ function defineOperation(definition) {
|
|
|
1121
1188
|
const xapi = {
|
|
1122
1189
|
string: (options) => column("STRING", options),
|
|
1123
1190
|
int: (options) => column("INT", options),
|
|
1191
|
+
long: (options) => column("LONG", options),
|
|
1124
1192
|
float: (options) => column("FLOAT", options),
|
|
1193
|
+
double: (options) => column("DOUBLE", options),
|
|
1125
1194
|
decimal: (options) => column("DECIMAL", options),
|
|
1126
1195
|
bigdecimal: (options) => column("BIGDECIMAL", options),
|
|
1196
|
+
bigDecimal: (options) => column("BIG_DECIMAL", options),
|
|
1197
|
+
boolean: (options) => column("BOOLEAN", options),
|
|
1127
1198
|
date: (options) => column("DATE", options),
|
|
1128
1199
|
datetime: (options) => column("DATETIME", options),
|
|
1200
|
+
dateTime: (options) => column("DATE_TIME", options),
|
|
1129
1201
|
time: (options) => column("TIME", options),
|
|
1130
1202
|
blob: (options) => column("BLOB", options),
|
|
1131
1203
|
dataset: defineDataset,
|
|
@@ -1134,7 +1206,8 @@ const xapi = {
|
|
|
1134
1206
|
};
|
|
1135
1207
|
function encodeRoot(schema, value) {
|
|
1136
1208
|
const root = new XapiRoot();
|
|
1137
|
-
|
|
1209
|
+
const compiled = compileSchema(schema);
|
|
1210
|
+
for (const [id, parameterSchema] of compiled.parameters) {
|
|
1138
1211
|
const parameterValue = value.parameters[id];
|
|
1139
1212
|
if (parameterValue !== void 0 || !parameterSchema.optional) root.addParameter({
|
|
1140
1213
|
id,
|
|
@@ -1142,30 +1215,39 @@ function encodeRoot(schema, value) {
|
|
|
1142
1215
|
value: parameterValue
|
|
1143
1216
|
});
|
|
1144
1217
|
}
|
|
1145
|
-
for (const [datasetId,
|
|
1218
|
+
for (const [datasetId, datasetDefinition] of compiled.datasets) {
|
|
1146
1219
|
const dataset = new Dataset(datasetId);
|
|
1147
|
-
for (const [id, columnSchema] of
|
|
1220
|
+
for (const [id, columnSchema] of datasetDefinition.columns) dataset.addColumn({
|
|
1148
1221
|
id,
|
|
1149
1222
|
type: columnSchema.type,
|
|
1150
1223
|
size: columnSchema.size
|
|
1151
1224
|
});
|
|
1152
1225
|
const rows = value.datasets[datasetId];
|
|
1226
|
+
const columnIds = [...datasetDefinition.columns.keys()];
|
|
1153
1227
|
for (const row of rows) {
|
|
1154
1228
|
const rowIndex = dataset.newRow();
|
|
1155
|
-
|
|
1229
|
+
dataset.rows[rowIndex].type = row.$rowType;
|
|
1230
|
+
for (const id of columnIds) dataset.setColumn(rowIndex, id, row[id]);
|
|
1231
|
+
if (row.$orgRow) dataset.rows[rowIndex].orgRow = Object.entries(row.$orgRow).map(([id, value]) => ({
|
|
1232
|
+
id,
|
|
1233
|
+
value
|
|
1234
|
+
}));
|
|
1156
1235
|
}
|
|
1157
1236
|
root.addDataset(dataset);
|
|
1158
1237
|
}
|
|
1159
1238
|
return root;
|
|
1160
1239
|
}
|
|
1161
1240
|
function decodeRoot(schema, root) {
|
|
1241
|
+
const compiled = compileSchema(schema);
|
|
1162
1242
|
const parameters = {};
|
|
1163
|
-
for (const id of
|
|
1164
|
-
const
|
|
1165
|
-
|
|
1243
|
+
for (const [id, parameterSchema] of compiled.parameters) {
|
|
1244
|
+
const parameter = root.getParameter(id);
|
|
1245
|
+
const value = parameter?.rawValue !== void 0 ? parameter.rawValue : parameter?.value;
|
|
1246
|
+
if (value !== void 0) parameters[id] = convertToColumnType(value, parameterSchema.type);
|
|
1166
1247
|
}
|
|
1167
1248
|
const datasets = {};
|
|
1168
|
-
for (const [datasetId,
|
|
1249
|
+
for (const [datasetId, datasetDefinition] of compiled.datasets) {
|
|
1250
|
+
const schemaColumns = datasetDefinition.columns;
|
|
1169
1251
|
const dataset = root.getDataset(datasetId);
|
|
1170
1252
|
if (!dataset) {
|
|
1171
1253
|
datasets[datasetId] = [];
|
|
@@ -1174,7 +1256,20 @@ function decodeRoot(schema, root) {
|
|
|
1174
1256
|
const constants = Object.fromEntries(dataset.getConstColumns().map(({ id, value }) => [id, value]));
|
|
1175
1257
|
datasets[datasetId] = dataset.getRows().map((row) => {
|
|
1176
1258
|
const value = { ...constants };
|
|
1177
|
-
for (const column of row.cols)
|
|
1259
|
+
for (const column of row.cols) {
|
|
1260
|
+
const columnSchema = schemaColumns.get(column.id);
|
|
1261
|
+
if (columnSchema) {
|
|
1262
|
+
const rawValue = column.rawValue !== void 0 ? column.rawValue : column.value;
|
|
1263
|
+
value[column.id] = rawValue === void 0 ? void 0 : convertToColumnType(rawValue, columnSchema.type);
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
if (row.type) value.$rowType = row.type;
|
|
1267
|
+
if (row.orgRow) value.$orgRow = Object.fromEntries(row.orgRow.flatMap((column) => {
|
|
1268
|
+
const columnSchema = schemaColumns.get(column.id);
|
|
1269
|
+
if (!columnSchema) return [];
|
|
1270
|
+
const rawValue = column.rawValue !== void 0 ? column.rawValue : column.value;
|
|
1271
|
+
return [[column.id, rawValue === void 0 ? void 0 : convertToColumnType(rawValue, columnSchema.type)]];
|
|
1272
|
+
}));
|
|
1178
1273
|
return value;
|
|
1179
1274
|
});
|
|
1180
1275
|
}
|
|
@@ -1184,6 +1279,138 @@ function decodeRoot(schema, root) {
|
|
|
1184
1279
|
};
|
|
1185
1280
|
}
|
|
1186
1281
|
//#endregion
|
|
1282
|
+
//#region src/codec.ts
|
|
1283
|
+
const rowTypes = {
|
|
1284
|
+
N: void 0,
|
|
1285
|
+
I: "insert",
|
|
1286
|
+
U: "update",
|
|
1287
|
+
D: "delete",
|
|
1288
|
+
O: void 0
|
|
1289
|
+
};
|
|
1290
|
+
function sizeOf(size, type) {
|
|
1291
|
+
if (size !== void 0) return Number(size);
|
|
1292
|
+
return type === "STRING" ? 255 : 0;
|
|
1293
|
+
}
|
|
1294
|
+
function jsonValue(value, type) {
|
|
1295
|
+
if (value === null || value === void 0) return void 0;
|
|
1296
|
+
return convertToColumnType(typeof value === "string" ? value : String(value), normalizeColumnType(type));
|
|
1297
|
+
}
|
|
1298
|
+
function jsonRawValue(value) {
|
|
1299
|
+
return value === null || value === void 0 ? void 0 : String(value);
|
|
1300
|
+
}
|
|
1301
|
+
function jsonWireValue(value, type) {
|
|
1302
|
+
if (value === void 0) return void 0;
|
|
1303
|
+
if (value instanceof Date) return dateToString(value, type);
|
|
1304
|
+
if (value instanceof Uint8Array) return uint8ArrayToBase64(value);
|
|
1305
|
+
return value;
|
|
1306
|
+
}
|
|
1307
|
+
function columnsToObject(columns) {
|
|
1308
|
+
return Object.fromEntries(columns.map((column) => [column.id, column.value]));
|
|
1309
|
+
}
|
|
1310
|
+
function readRow(dataset, row) {
|
|
1311
|
+
const rowType = rowTypes[row._RowType_ ?? "N"];
|
|
1312
|
+
if (row._RowType_ === "O") {
|
|
1313
|
+
const previous = dataset.rows[dataset.rows.length - 1];
|
|
1314
|
+
if (previous?.type !== "update") return;
|
|
1315
|
+
previous.orgRow = dataset.getColumns().filter((column) => Object.prototype.hasOwnProperty.call(row, column.id)).map((column) => ({
|
|
1316
|
+
id: column.id,
|
|
1317
|
+
value: jsonValue(row[column.id], column.type),
|
|
1318
|
+
rawValue: jsonRawValue(row[column.id])
|
|
1319
|
+
}));
|
|
1320
|
+
return;
|
|
1321
|
+
}
|
|
1322
|
+
const index = dataset.newRow();
|
|
1323
|
+
dataset.rows[index].type = rowType;
|
|
1324
|
+
for (const column of dataset.getColumns()) if (Object.prototype.hasOwnProperty.call(row, column.id)) dataset.rows[index].cols.push({
|
|
1325
|
+
id: column.id,
|
|
1326
|
+
value: jsonValue(row[column.id], column.type),
|
|
1327
|
+
rawValue: jsonRawValue(row[column.id])
|
|
1328
|
+
});
|
|
1329
|
+
}
|
|
1330
|
+
function readJson(value) {
|
|
1331
|
+
const root = new XapiRoot();
|
|
1332
|
+
for (const parameter of value.Parameters ?? []) {
|
|
1333
|
+
const type = normalizeColumnType(parameter.type);
|
|
1334
|
+
root.addParameter({
|
|
1335
|
+
id: parameter.id,
|
|
1336
|
+
type,
|
|
1337
|
+
value: jsonValue(parameter.value, type),
|
|
1338
|
+
rawValue: jsonRawValue(parameter.value)
|
|
1339
|
+
});
|
|
1340
|
+
}
|
|
1341
|
+
for (const source of value.Datasets ?? []) {
|
|
1342
|
+
const dataset = new Dataset(source.id);
|
|
1343
|
+
for (const column of source.ColumnInfo.ConstColumn ?? []) {
|
|
1344
|
+
const type = normalizeColumnType(column.type);
|
|
1345
|
+
dataset.addConstColumn({
|
|
1346
|
+
id: column.id,
|
|
1347
|
+
type,
|
|
1348
|
+
size: sizeOf(column.size, type),
|
|
1349
|
+
value: jsonValue(column.value, type),
|
|
1350
|
+
rawValue: jsonRawValue(column.value)
|
|
1351
|
+
});
|
|
1352
|
+
}
|
|
1353
|
+
for (const column of source.ColumnInfo.Column) {
|
|
1354
|
+
const type = normalizeColumnType(column.type);
|
|
1355
|
+
dataset.addColumn({
|
|
1356
|
+
id: column.id,
|
|
1357
|
+
type,
|
|
1358
|
+
size: sizeOf(column.size, type)
|
|
1359
|
+
});
|
|
1360
|
+
}
|
|
1361
|
+
for (const row of source.Rows) readRow(dataset, row);
|
|
1362
|
+
root.addDataset(dataset);
|
|
1363
|
+
}
|
|
1364
|
+
return root;
|
|
1365
|
+
}
|
|
1366
|
+
function writeJson(root) {
|
|
1367
|
+
return {
|
|
1368
|
+
version: "1.0",
|
|
1369
|
+
...root.parameterSize() ? { Parameters: root.getParameters().map((parameter) => ({
|
|
1370
|
+
id: parameter.id,
|
|
1371
|
+
...parameter.type ? { type: parameter.type } : {},
|
|
1372
|
+
...parameter.value !== void 0 ? { value: jsonWireValue(parameter.value, parameter.type ?? "STRING") } : {}
|
|
1373
|
+
})) } : {},
|
|
1374
|
+
...root.datasetSize() ? { Datasets: root.getDatasets().map((dataset) => ({
|
|
1375
|
+
id: dataset.id,
|
|
1376
|
+
ColumnInfo: {
|
|
1377
|
+
...dataset.constColumnSize() ? { ConstColumn: dataset.getConstColumns().map((column) => ({
|
|
1378
|
+
id: column.id,
|
|
1379
|
+
type: column.type,
|
|
1380
|
+
size: column.size,
|
|
1381
|
+
value: jsonWireValue(column.value, column.type)
|
|
1382
|
+
})) } : {},
|
|
1383
|
+
Column: dataset.getColumns().map((column) => ({
|
|
1384
|
+
id: column.id,
|
|
1385
|
+
type: column.type,
|
|
1386
|
+
size: column.size
|
|
1387
|
+
}))
|
|
1388
|
+
},
|
|
1389
|
+
Rows: dataset.getRows().flatMap((row) => {
|
|
1390
|
+
const current = {
|
|
1391
|
+
_RowType_: row.type === "insert" ? "I" : row.type === "update" ? "U" : row.type === "delete" ? "D" : "N",
|
|
1392
|
+
...columnsToObject(row.cols)
|
|
1393
|
+
};
|
|
1394
|
+
if (!row.orgRow) return [current];
|
|
1395
|
+
return [current, {
|
|
1396
|
+
_RowType_: "O",
|
|
1397
|
+
...columnsToObject(row.orgRow)
|
|
1398
|
+
}];
|
|
1399
|
+
})
|
|
1400
|
+
})) } : {}
|
|
1401
|
+
};
|
|
1402
|
+
}
|
|
1403
|
+
const nexacroJsonCodec = {
|
|
1404
|
+
serialize: writeJson,
|
|
1405
|
+
deserialize: readJson
|
|
1406
|
+
};
|
|
1407
|
+
function parseJson(value) {
|
|
1408
|
+
return nexacroJsonCodec.deserialize(JSON.parse(value));
|
|
1409
|
+
}
|
|
1410
|
+
function writeJsonString(root) {
|
|
1411
|
+
return JSON.stringify(nexacroJsonCodec.serialize(root));
|
|
1412
|
+
}
|
|
1413
|
+
//#endregion
|
|
1187
1414
|
exports.ColumnTypeError = ColumnTypeError;
|
|
1188
1415
|
exports.Dataset = Dataset;
|
|
1189
1416
|
exports.InvalidXmlError = InvalidXmlError;
|
|
@@ -1209,11 +1436,15 @@ exports.escapeXml = escapeXml;
|
|
|
1209
1436
|
exports.initXapi = initXapi;
|
|
1210
1437
|
exports.isXapiRoot = isXapiRoot;
|
|
1211
1438
|
exports.makeParseEntities = makeParseEntities;
|
|
1439
|
+
exports.nexacroJsonCodec = nexacroJsonCodec;
|
|
1440
|
+
exports.normalizeColumnType = normalizeColumnType;
|
|
1212
1441
|
exports.parse = parse;
|
|
1442
|
+
exports.parseJson = parseJson;
|
|
1213
1443
|
exports.parseXml = parseXml;
|
|
1214
1444
|
exports.rowType = rowType;
|
|
1215
1445
|
exports.stringToDate = stringToDate;
|
|
1216
1446
|
exports.stringToReadableStream = stringToReadableStream;
|
|
1217
1447
|
exports.uint8ArrayToBase64 = uint8ArrayToBase64;
|
|
1218
1448
|
exports.write = write;
|
|
1449
|
+
exports.writeJsonString = writeJsonString;
|
|
1219
1450
|
exports.xapi = xapi;
|
package/dist/index.d.cts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Represents the possible data types for X-API values.
|
|
4
4
|
*/
|
|
5
|
-
type XapiValueType = string | number | Uint8Array | Date | undefined;
|
|
5
|
+
type XapiValueType = string | number | boolean | Uint8Array | Date | undefined;
|
|
6
6
|
/**
|
|
7
7
|
* Represents a column within a row of an X-API dataset.
|
|
8
8
|
*/
|
|
@@ -11,6 +11,8 @@ interface Col {
|
|
|
11
11
|
id: string;
|
|
12
12
|
/** The value of the column. */
|
|
13
13
|
value?: XapiValueType;
|
|
14
|
+
/** Original wire value. XML and SSV values are strings before schema conversion. */
|
|
15
|
+
rawValue?: string;
|
|
14
16
|
}
|
|
15
17
|
/**
|
|
16
18
|
* Defines the possible types of rows in an X-API dataset (e.g., "insert", "update", "delete").
|
|
@@ -41,7 +43,7 @@ interface Rows {
|
|
|
41
43
|
/**
|
|
42
44
|
* Defines the possible data types for columns in an X-API dataset.
|
|
43
45
|
*/
|
|
44
|
-
declare const columnType: readonly ["STRING", "INT", "FLOAT", "DECIMAL", "BIGDECIMAL", "DATE", "DATETIME", "TIME", "BLOB"];
|
|
46
|
+
declare const columnType: readonly ["STRING", "INT", "LONG", "FLOAT", "DOUBLE", "DECIMAL", "BIGDECIMAL", "BIG_DECIMAL", "BOOLEAN", "DATE", "DATETIME", "DATE_TIME", "TIME", "BLOB"];
|
|
45
47
|
/**
|
|
46
48
|
* Type representing the data type of a column.
|
|
47
49
|
*/
|
|
@@ -62,6 +64,7 @@ interface Column {
|
|
|
62
64
|
*/
|
|
63
65
|
type ConstColumn = Column & {
|
|
64
66
|
value: XapiValueType;
|
|
67
|
+
rawValue?: string;
|
|
65
68
|
};
|
|
66
69
|
/**
|
|
67
70
|
* Represents the column information section of an X-API dataset.
|
|
@@ -82,6 +85,8 @@ interface Parameter {
|
|
|
82
85
|
type?: ColumnType;
|
|
83
86
|
/** The value of the parameter. */
|
|
84
87
|
value?: XapiValueType;
|
|
88
|
+
/** Original wire value before conversion. */
|
|
89
|
+
rawValue?: string;
|
|
85
90
|
}
|
|
86
91
|
/**
|
|
87
92
|
* Represents a collection of parameters in an X-API request/response.
|
|
@@ -366,14 +371,14 @@ declare function uint8ArrayToBase64(uint8Array: Uint8Array): string;
|
|
|
366
371
|
* @param value - The string to convert.
|
|
367
372
|
* @returns A Date object if the string is a valid date/time, otherwise undefined.
|
|
368
373
|
*/
|
|
369
|
-
declare function stringToDate(value: string): Date | undefined;
|
|
374
|
+
declare function stringToDate(value: string, type?: ColumnType): Date | undefined;
|
|
370
375
|
/**
|
|
371
376
|
* Converts a Date object to a string representation based on the specified column type.
|
|
372
377
|
* @param date - The Date object to convert.
|
|
373
378
|
* @param type - The column type ("DATE", "DATETIME", or "TIME").
|
|
374
379
|
* @returns A string representation of the date/time.
|
|
375
380
|
*/
|
|
376
|
-
declare function dateToString(date: Date, type: Extract<ColumnType, "DATE" | "DATETIME" | "TIME">): string;
|
|
381
|
+
declare function dateToString(date: Date, type: Extract<ColumnType, "DATE" | "DATETIME" | "DATE_TIME" | "TIME">): string;
|
|
377
382
|
/**
|
|
378
383
|
* A WritableStream that collects all written Uint8Array chunks and provides them as a single string.
|
|
379
384
|
*/
|
|
@@ -400,6 +405,8 @@ declare function stringToReadableStream(str: string): ReadableStream<Uint8Array>
|
|
|
400
405
|
* @throws {ColumnTypeError} if the column type is unsupported.
|
|
401
406
|
*/
|
|
402
407
|
declare function convertToColumnType(value: XapiValueType, type: ColumnType): XapiValueType;
|
|
408
|
+
/** Normalizes X-API/Java type spellings to the names used by Dataset XML. */
|
|
409
|
+
declare function normalizeColumnType(type?: string): ColumnType;
|
|
403
410
|
/**
|
|
404
411
|
* Converts an XapiValueType to its string representation based on the specified ColumnType.
|
|
405
412
|
* @param value - The value to convert.
|
|
@@ -473,11 +480,16 @@ declare function parseXml(xml: string): XmlNode[];
|
|
|
473
480
|
type XapiTypeMap = {
|
|
474
481
|
STRING: string;
|
|
475
482
|
INT: number;
|
|
483
|
+
LONG: number;
|
|
476
484
|
FLOAT: number;
|
|
485
|
+
DOUBLE: number;
|
|
477
486
|
DECIMAL: number;
|
|
478
487
|
BIGDECIMAL: number;
|
|
488
|
+
BIG_DECIMAL: number;
|
|
489
|
+
BOOLEAN: boolean;
|
|
479
490
|
DATE: Date;
|
|
480
491
|
DATETIME: Date;
|
|
492
|
+
DATE_TIME: Date;
|
|
481
493
|
TIME: Date;
|
|
482
494
|
BLOB: Uint8Array;
|
|
483
495
|
};
|
|
@@ -506,7 +518,15 @@ interface XapiOperation<Request extends XapiRootSchema = XapiRootSchema, Respons
|
|
|
506
518
|
type RequiredColumnKeys<Columns extends XapiColumns> = { [Key in keyof Columns]-?: Columns[Key]["optional"] extends true ? never : Key; }[keyof Columns];
|
|
507
519
|
type OptionalColumnKeys<Columns extends XapiColumns> = { [Key in keyof Columns]-?: Columns[Key]["optional"] extends true ? Key : never; }[keyof Columns];
|
|
508
520
|
type InferColumns<Columns extends XapiColumns> = { [Key in RequiredColumnKeys<Columns>]: XapiTypeMap[Columns[Key]["type"]]; } & { [Key in OptionalColumnKeys<Columns>]?: XapiTypeMap[Columns[Key]["type"]]; };
|
|
509
|
-
|
|
521
|
+
/**
|
|
522
|
+
* A schema row remains assignable from the old plain object shape, while
|
|
523
|
+
* retaining the Nexacro row metadata when an operation needs it.
|
|
524
|
+
*/
|
|
525
|
+
type InferDatasetRow<Schema extends XapiDatasetSchema> = InferColumns<Schema["columns"]> & {
|
|
526
|
+
$rowType?: RowType;
|
|
527
|
+
$orgRow?: Partial<InferColumns<Schema["columns"]>>;
|
|
528
|
+
};
|
|
529
|
+
type InferDataset<Schema extends XapiDatasetSchema> = InferDatasetRow<Schema>[];
|
|
510
530
|
type InferRoot<Schema extends XapiRootSchema> = {
|
|
511
531
|
parameters: InferColumns<Schema["parameters"]>;
|
|
512
532
|
datasets: { [Key in keyof Schema["datasets"]]: InferDataset<Schema["datasets"][Key]>; };
|
|
@@ -529,11 +549,16 @@ declare function defineOperation<const Request extends XapiRootSchema, const Res
|
|
|
529
549
|
declare const xapi: {
|
|
530
550
|
readonly string: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"STRING", Optional>;
|
|
531
551
|
readonly int: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"INT", Optional>;
|
|
552
|
+
readonly long: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"LONG", Optional>;
|
|
532
553
|
readonly float: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"FLOAT", Optional>;
|
|
554
|
+
readonly double: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"DOUBLE", Optional>;
|
|
533
555
|
readonly decimal: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"DECIMAL", Optional>;
|
|
534
556
|
readonly bigdecimal: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"BIGDECIMAL", Optional>;
|
|
557
|
+
readonly bigDecimal: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"BIG_DECIMAL", Optional>;
|
|
558
|
+
readonly boolean: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"BOOLEAN", Optional>;
|
|
535
559
|
readonly date: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"DATE", Optional>;
|
|
536
560
|
readonly datetime: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"DATETIME", Optional>;
|
|
561
|
+
readonly dateTime: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"DATE_TIME", Optional>;
|
|
537
562
|
readonly time: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"TIME", Optional>;
|
|
538
563
|
readonly blob: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"BLOB", Optional>;
|
|
539
564
|
readonly dataset: typeof defineDataset;
|
|
@@ -543,4 +568,43 @@ declare const xapi: {
|
|
|
543
568
|
declare function encodeRoot<Schema extends XapiRootSchema>(schema: Schema, value: InferRoot<Schema>): XapiRoot;
|
|
544
569
|
declare function decodeRoot<Schema extends XapiRootSchema>(schema: Schema, root: XapiRoot): InferRoot<Schema>;
|
|
545
570
|
//#endregion
|
|
546
|
-
|
|
571
|
+
//#region src/codec.d.ts
|
|
572
|
+
/** The wire representation used by Nexacro's Dataset JSON format. */
|
|
573
|
+
interface NexacroJsonParameter {
|
|
574
|
+
id: string;
|
|
575
|
+
type?: ColumnType;
|
|
576
|
+
value?: string | number | boolean;
|
|
577
|
+
}
|
|
578
|
+
interface NexacroJsonColumn {
|
|
579
|
+
id: string;
|
|
580
|
+
type?: ColumnType;
|
|
581
|
+
size?: number | string;
|
|
582
|
+
value?: string | number | boolean;
|
|
583
|
+
}
|
|
584
|
+
interface NexacroJsonRow {
|
|
585
|
+
_RowType_?: "N" | "I" | "U" | "D" | "O";
|
|
586
|
+
[columnId: string]: unknown;
|
|
587
|
+
}
|
|
588
|
+
interface NexacroJsonDataset {
|
|
589
|
+
id: string;
|
|
590
|
+
ColumnInfo: {
|
|
591
|
+
ConstColumn?: NexacroJsonColumn[];
|
|
592
|
+
Column: NexacroJsonColumn[];
|
|
593
|
+
};
|
|
594
|
+
Rows: NexacroJsonRow[];
|
|
595
|
+
}
|
|
596
|
+
interface NexacroJsonRoot {
|
|
597
|
+
version: "1.0";
|
|
598
|
+
Parameters?: NexacroJsonParameter[];
|
|
599
|
+
Datasets?: NexacroJsonDataset[];
|
|
600
|
+
}
|
|
601
|
+
/** A serializer boundary around the X-API internal model. */
|
|
602
|
+
interface XapiCodec<Serialized> {
|
|
603
|
+
serialize(root: XapiRoot): Serialized;
|
|
604
|
+
deserialize(value: Serialized): XapiRoot;
|
|
605
|
+
}
|
|
606
|
+
declare const nexacroJsonCodec: XapiCodec<NexacroJsonRoot>;
|
|
607
|
+
declare function parseJson(value: string): XapiRoot;
|
|
608
|
+
declare function writeJsonString(root: XapiRoot): string;
|
|
609
|
+
//#endregion
|
|
610
|
+
export { Col, Column, ColumnInfo, ColumnType, ColumnTypeError, ConstColumn, Dataset, InferColumns, InferDataset, InferDatasetRow, InferRoot, InvalidXmlError, NexaVersion, NexacroJsonColumn, NexacroJsonDataset, NexacroJsonParameter, NexacroJsonRoot, NexacroJsonRow, Parameter, RequestOf, ResponseOf, Row, RowType, Rows, StringWritableStream, XapiCodec, XapiColumnSchema, XapiColumns, XapiDatasetSchema, XapiDatasets, XapiOperation, XapiOptions, XapiParameters, XapiRoot, XapiRootSchema, XapiTypeMap, XapiValueType, XapiVersion, XmlNode, XmlStringBuilder, XplatformVersion, _unescapeXml, arrayBufferToString, base64ToUint8Array, columnType, convertToColumnType, convertToString, dateToString, decodeRoot, defineDataset, defineOperation, defineRoot, encodeControlChars, encodeRoot, escapeXml, initXapi, isXapiRoot, makeParseEntities, nexacroJsonCodec, normalizeColumnType, parse, parseJson, parseXml, rowType, stringToDate, stringToReadableStream, uint8ArrayToBase64, write, writeJsonString, xapi };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Represents the possible data types for X-API values.
|
|
4
4
|
*/
|
|
5
|
-
type XapiValueType = string | number | Uint8Array | Date | undefined;
|
|
5
|
+
type XapiValueType = string | number | boolean | Uint8Array | Date | undefined;
|
|
6
6
|
/**
|
|
7
7
|
* Represents a column within a row of an X-API dataset.
|
|
8
8
|
*/
|
|
@@ -11,6 +11,8 @@ interface Col {
|
|
|
11
11
|
id: string;
|
|
12
12
|
/** The value of the column. */
|
|
13
13
|
value?: XapiValueType;
|
|
14
|
+
/** Original wire value. XML and SSV values are strings before schema conversion. */
|
|
15
|
+
rawValue?: string;
|
|
14
16
|
}
|
|
15
17
|
/**
|
|
16
18
|
* Defines the possible types of rows in an X-API dataset (e.g., "insert", "update", "delete").
|
|
@@ -41,7 +43,7 @@ interface Rows {
|
|
|
41
43
|
/**
|
|
42
44
|
* Defines the possible data types for columns in an X-API dataset.
|
|
43
45
|
*/
|
|
44
|
-
declare const columnType: readonly ["STRING", "INT", "FLOAT", "DECIMAL", "BIGDECIMAL", "DATE", "DATETIME", "TIME", "BLOB"];
|
|
46
|
+
declare const columnType: readonly ["STRING", "INT", "LONG", "FLOAT", "DOUBLE", "DECIMAL", "BIGDECIMAL", "BIG_DECIMAL", "BOOLEAN", "DATE", "DATETIME", "DATE_TIME", "TIME", "BLOB"];
|
|
45
47
|
/**
|
|
46
48
|
* Type representing the data type of a column.
|
|
47
49
|
*/
|
|
@@ -62,6 +64,7 @@ interface Column {
|
|
|
62
64
|
*/
|
|
63
65
|
type ConstColumn = Column & {
|
|
64
66
|
value: XapiValueType;
|
|
67
|
+
rawValue?: string;
|
|
65
68
|
};
|
|
66
69
|
/**
|
|
67
70
|
* Represents the column information section of an X-API dataset.
|
|
@@ -82,6 +85,8 @@ interface Parameter {
|
|
|
82
85
|
type?: ColumnType;
|
|
83
86
|
/** The value of the parameter. */
|
|
84
87
|
value?: XapiValueType;
|
|
88
|
+
/** Original wire value before conversion. */
|
|
89
|
+
rawValue?: string;
|
|
85
90
|
}
|
|
86
91
|
/**
|
|
87
92
|
* Represents a collection of parameters in an X-API request/response.
|
|
@@ -366,14 +371,14 @@ declare function uint8ArrayToBase64(uint8Array: Uint8Array): string;
|
|
|
366
371
|
* @param value - The string to convert.
|
|
367
372
|
* @returns A Date object if the string is a valid date/time, otherwise undefined.
|
|
368
373
|
*/
|
|
369
|
-
declare function stringToDate(value: string): Date | undefined;
|
|
374
|
+
declare function stringToDate(value: string, type?: ColumnType): Date | undefined;
|
|
370
375
|
/**
|
|
371
376
|
* Converts a Date object to a string representation based on the specified column type.
|
|
372
377
|
* @param date - The Date object to convert.
|
|
373
378
|
* @param type - The column type ("DATE", "DATETIME", or "TIME").
|
|
374
379
|
* @returns A string representation of the date/time.
|
|
375
380
|
*/
|
|
376
|
-
declare function dateToString(date: Date, type: Extract<ColumnType, "DATE" | "DATETIME" | "TIME">): string;
|
|
381
|
+
declare function dateToString(date: Date, type: Extract<ColumnType, "DATE" | "DATETIME" | "DATE_TIME" | "TIME">): string;
|
|
377
382
|
/**
|
|
378
383
|
* A WritableStream that collects all written Uint8Array chunks and provides them as a single string.
|
|
379
384
|
*/
|
|
@@ -400,6 +405,8 @@ declare function stringToReadableStream(str: string): ReadableStream<Uint8Array>
|
|
|
400
405
|
* @throws {ColumnTypeError} if the column type is unsupported.
|
|
401
406
|
*/
|
|
402
407
|
declare function convertToColumnType(value: XapiValueType, type: ColumnType): XapiValueType;
|
|
408
|
+
/** Normalizes X-API/Java type spellings to the names used by Dataset XML. */
|
|
409
|
+
declare function normalizeColumnType(type?: string): ColumnType;
|
|
403
410
|
/**
|
|
404
411
|
* Converts an XapiValueType to its string representation based on the specified ColumnType.
|
|
405
412
|
* @param value - The value to convert.
|
|
@@ -473,11 +480,16 @@ declare function parseXml(xml: string): XmlNode[];
|
|
|
473
480
|
type XapiTypeMap = {
|
|
474
481
|
STRING: string;
|
|
475
482
|
INT: number;
|
|
483
|
+
LONG: number;
|
|
476
484
|
FLOAT: number;
|
|
485
|
+
DOUBLE: number;
|
|
477
486
|
DECIMAL: number;
|
|
478
487
|
BIGDECIMAL: number;
|
|
488
|
+
BIG_DECIMAL: number;
|
|
489
|
+
BOOLEAN: boolean;
|
|
479
490
|
DATE: Date;
|
|
480
491
|
DATETIME: Date;
|
|
492
|
+
DATE_TIME: Date;
|
|
481
493
|
TIME: Date;
|
|
482
494
|
BLOB: Uint8Array;
|
|
483
495
|
};
|
|
@@ -506,7 +518,15 @@ interface XapiOperation<Request extends XapiRootSchema = XapiRootSchema, Respons
|
|
|
506
518
|
type RequiredColumnKeys<Columns extends XapiColumns> = { [Key in keyof Columns]-?: Columns[Key]["optional"] extends true ? never : Key; }[keyof Columns];
|
|
507
519
|
type OptionalColumnKeys<Columns extends XapiColumns> = { [Key in keyof Columns]-?: Columns[Key]["optional"] extends true ? Key : never; }[keyof Columns];
|
|
508
520
|
type InferColumns<Columns extends XapiColumns> = { [Key in RequiredColumnKeys<Columns>]: XapiTypeMap[Columns[Key]["type"]]; } & { [Key in OptionalColumnKeys<Columns>]?: XapiTypeMap[Columns[Key]["type"]]; };
|
|
509
|
-
|
|
521
|
+
/**
|
|
522
|
+
* A schema row remains assignable from the old plain object shape, while
|
|
523
|
+
* retaining the Nexacro row metadata when an operation needs it.
|
|
524
|
+
*/
|
|
525
|
+
type InferDatasetRow<Schema extends XapiDatasetSchema> = InferColumns<Schema["columns"]> & {
|
|
526
|
+
$rowType?: RowType;
|
|
527
|
+
$orgRow?: Partial<InferColumns<Schema["columns"]>>;
|
|
528
|
+
};
|
|
529
|
+
type InferDataset<Schema extends XapiDatasetSchema> = InferDatasetRow<Schema>[];
|
|
510
530
|
type InferRoot<Schema extends XapiRootSchema> = {
|
|
511
531
|
parameters: InferColumns<Schema["parameters"]>;
|
|
512
532
|
datasets: { [Key in keyof Schema["datasets"]]: InferDataset<Schema["datasets"][Key]>; };
|
|
@@ -529,11 +549,16 @@ declare function defineOperation<const Request extends XapiRootSchema, const Res
|
|
|
529
549
|
declare const xapi: {
|
|
530
550
|
readonly string: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"STRING", Optional>;
|
|
531
551
|
readonly int: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"INT", Optional>;
|
|
552
|
+
readonly long: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"LONG", Optional>;
|
|
532
553
|
readonly float: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"FLOAT", Optional>;
|
|
554
|
+
readonly double: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"DOUBLE", Optional>;
|
|
533
555
|
readonly decimal: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"DECIMAL", Optional>;
|
|
534
556
|
readonly bigdecimal: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"BIGDECIMAL", Optional>;
|
|
557
|
+
readonly bigDecimal: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"BIG_DECIMAL", Optional>;
|
|
558
|
+
readonly boolean: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"BOOLEAN", Optional>;
|
|
535
559
|
readonly date: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"DATE", Optional>;
|
|
536
560
|
readonly datetime: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"DATETIME", Optional>;
|
|
561
|
+
readonly dateTime: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"DATE_TIME", Optional>;
|
|
537
562
|
readonly time: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"TIME", Optional>;
|
|
538
563
|
readonly blob: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"BLOB", Optional>;
|
|
539
564
|
readonly dataset: typeof defineDataset;
|
|
@@ -543,4 +568,43 @@ declare const xapi: {
|
|
|
543
568
|
declare function encodeRoot<Schema extends XapiRootSchema>(schema: Schema, value: InferRoot<Schema>): XapiRoot;
|
|
544
569
|
declare function decodeRoot<Schema extends XapiRootSchema>(schema: Schema, root: XapiRoot): InferRoot<Schema>;
|
|
545
570
|
//#endregion
|
|
546
|
-
|
|
571
|
+
//#region src/codec.d.ts
|
|
572
|
+
/** The wire representation used by Nexacro's Dataset JSON format. */
|
|
573
|
+
interface NexacroJsonParameter {
|
|
574
|
+
id: string;
|
|
575
|
+
type?: ColumnType;
|
|
576
|
+
value?: string | number | boolean;
|
|
577
|
+
}
|
|
578
|
+
interface NexacroJsonColumn {
|
|
579
|
+
id: string;
|
|
580
|
+
type?: ColumnType;
|
|
581
|
+
size?: number | string;
|
|
582
|
+
value?: string | number | boolean;
|
|
583
|
+
}
|
|
584
|
+
interface NexacroJsonRow {
|
|
585
|
+
_RowType_?: "N" | "I" | "U" | "D" | "O";
|
|
586
|
+
[columnId: string]: unknown;
|
|
587
|
+
}
|
|
588
|
+
interface NexacroJsonDataset {
|
|
589
|
+
id: string;
|
|
590
|
+
ColumnInfo: {
|
|
591
|
+
ConstColumn?: NexacroJsonColumn[];
|
|
592
|
+
Column: NexacroJsonColumn[];
|
|
593
|
+
};
|
|
594
|
+
Rows: NexacroJsonRow[];
|
|
595
|
+
}
|
|
596
|
+
interface NexacroJsonRoot {
|
|
597
|
+
version: "1.0";
|
|
598
|
+
Parameters?: NexacroJsonParameter[];
|
|
599
|
+
Datasets?: NexacroJsonDataset[];
|
|
600
|
+
}
|
|
601
|
+
/** A serializer boundary around the X-API internal model. */
|
|
602
|
+
interface XapiCodec<Serialized> {
|
|
603
|
+
serialize(root: XapiRoot): Serialized;
|
|
604
|
+
deserialize(value: Serialized): XapiRoot;
|
|
605
|
+
}
|
|
606
|
+
declare const nexacroJsonCodec: XapiCodec<NexacroJsonRoot>;
|
|
607
|
+
declare function parseJson(value: string): XapiRoot;
|
|
608
|
+
declare function writeJsonString(root: XapiRoot): string;
|
|
609
|
+
//#endregion
|
|
610
|
+
export { Col, Column, ColumnInfo, ColumnType, ColumnTypeError, ConstColumn, Dataset, InferColumns, InferDataset, InferDatasetRow, InferRoot, InvalidXmlError, NexaVersion, NexacroJsonColumn, NexacroJsonDataset, NexacroJsonParameter, NexacroJsonRoot, NexacroJsonRow, Parameter, RequestOf, ResponseOf, Row, RowType, Rows, StringWritableStream, XapiCodec, XapiColumnSchema, XapiColumns, XapiDatasetSchema, XapiDatasets, XapiOperation, XapiOptions, XapiParameters, XapiRoot, XapiRootSchema, XapiTypeMap, XapiValueType, XapiVersion, XmlNode, XmlStringBuilder, XplatformVersion, _unescapeXml, arrayBufferToString, base64ToUint8Array, columnType, convertToColumnType, convertToString, dateToString, decodeRoot, defineDataset, defineOperation, defineRoot, encodeControlChars, encodeRoot, escapeXml, initXapi, isXapiRoot, makeParseEntities, nexacroJsonCodec, normalizeColumnType, parse, parseJson, parseXml, rowType, stringToDate, stringToReadableStream, uint8ArrayToBase64, write, writeJsonString, xapi };
|
package/dist/index.js
CHANGED
|
@@ -13,11 +13,16 @@ const rowType = [
|
|
|
13
13
|
const columnType = [
|
|
14
14
|
"STRING",
|
|
15
15
|
"INT",
|
|
16
|
+
"LONG",
|
|
16
17
|
"FLOAT",
|
|
18
|
+
"DOUBLE",
|
|
17
19
|
"DECIMAL",
|
|
18
20
|
"BIGDECIMAL",
|
|
21
|
+
"BIG_DECIMAL",
|
|
22
|
+
"BOOLEAN",
|
|
19
23
|
"DATE",
|
|
20
24
|
"DATETIME",
|
|
25
|
+
"DATE_TIME",
|
|
21
26
|
"TIME",
|
|
22
27
|
"BLOB"
|
|
23
28
|
];
|
|
@@ -367,8 +372,23 @@ function uint8ArrayToBase64(uint8Array) {
|
|
|
367
372
|
* @param value - The string to convert.
|
|
368
373
|
* @returns A Date object if the string is a valid date/time, otherwise undefined.
|
|
369
374
|
*/
|
|
370
|
-
function stringToDate(value) {
|
|
375
|
+
function stringToDate(value, type) {
|
|
371
376
|
if (!value) return void 0;
|
|
377
|
+
const normalizedType = type ? normalizeColumnType(type) : void 0;
|
|
378
|
+
if (normalizedType === "TIME") {
|
|
379
|
+
if (value.length !== 6 && value.length !== 9) return void 0;
|
|
380
|
+
const hours = parseInt(value.substring(0, 2), 10);
|
|
381
|
+
const minutes = parseInt(value.substring(2, 4), 10);
|
|
382
|
+
const seconds = parseInt(value.substring(4, 6), 10);
|
|
383
|
+
const milliseconds = value.length === 9 ? parseInt(value.substring(6, 9), 10) : 0;
|
|
384
|
+
if ([
|
|
385
|
+
hours,
|
|
386
|
+
minutes,
|
|
387
|
+
seconds,
|
|
388
|
+
milliseconds
|
|
389
|
+
].some(Number.isNaN) || hours > 23 || minutes > 59 || seconds > 59 || milliseconds > 999) return void 0;
|
|
390
|
+
return new Date(1970, 0, 1, hours, minutes, seconds, milliseconds);
|
|
391
|
+
}
|
|
372
392
|
let year;
|
|
373
393
|
let month;
|
|
374
394
|
let day;
|
|
@@ -376,7 +396,7 @@ function stringToDate(value) {
|
|
|
376
396
|
let minutes = 0;
|
|
377
397
|
let seconds = 0;
|
|
378
398
|
let milliseconds = 0;
|
|
379
|
-
if (value.length < 6 || value.length > 16) return;
|
|
399
|
+
if (value.length < 6 || value.length > (normalizedType ? 17 : 16)) return;
|
|
380
400
|
if (value.length >= 8) {
|
|
381
401
|
year = parseInt(value.substring(0, 4), 10);
|
|
382
402
|
month = parseInt(value.substring(4, 6), 10) - 1;
|
|
@@ -395,7 +415,10 @@ function stringToDate(value) {
|
|
|
395
415
|
minutes = parseInt(value.substring(10, 12), 10);
|
|
396
416
|
seconds = parseInt(value.substring(12, 14), 10);
|
|
397
417
|
}
|
|
398
|
-
if (value.length === 16
|
|
418
|
+
if (value.length === 16 || value.length === 17) {
|
|
419
|
+
milliseconds = parseInt(value.substring(14, value.length), 10);
|
|
420
|
+
if (value.length === 16 && normalizedType) milliseconds *= 10;
|
|
421
|
+
}
|
|
399
422
|
if (year < 1970 || year > 9999 || month < 0 || month > 11 || day < 1 || day > 31 || hours < 0 || hours > 23 || minutes < 0 || minutes > 59 || seconds < 0 || seconds > 59 || milliseconds < 0 || milliseconds > 999) return;
|
|
400
423
|
const date = new Date(year, month, day, hours, minutes, seconds, milliseconds);
|
|
401
424
|
if (isNaN(date.getTime())) return;
|
|
@@ -414,10 +437,10 @@ function dateToString(date, type) {
|
|
|
414
437
|
const hours = date.getHours().toString().padStart(2, "0");
|
|
415
438
|
const minutes = date.getMinutes().toString().padStart(2, "0");
|
|
416
439
|
const seconds = date.getSeconds().toString().padStart(2, "0");
|
|
417
|
-
switch (type) {
|
|
440
|
+
switch (normalizeColumnType(type)) {
|
|
418
441
|
case "DATE": return `${year}${month}${day}`;
|
|
419
|
-
case "DATETIME": return `${year}${month}${day}${hours}${minutes}${seconds}`;
|
|
420
|
-
case "TIME": return `${hours}${minutes}${seconds}`;
|
|
442
|
+
case "DATETIME": return `${year}${month}${day}${hours}${minutes}${seconds}${date.getMilliseconds() ? date.getMilliseconds().toString().padStart(3, "0") : ""}`;
|
|
443
|
+
case "TIME": return `${hours}${minutes}${seconds}${date.getMilliseconds() ? date.getMilliseconds().toString().padStart(3, "0") : ""}`;
|
|
421
444
|
default: return "";
|
|
422
445
|
}
|
|
423
446
|
}
|
|
@@ -465,12 +488,16 @@ function stringToReadableStream(str) {
|
|
|
465
488
|
* @throws {ColumnTypeError} if the column type is unsupported.
|
|
466
489
|
*/
|
|
467
490
|
function convertToColumnType(value, type) {
|
|
468
|
-
|
|
491
|
+
const normalizedType = normalizeColumnType(type);
|
|
492
|
+
switch (normalizeColumnType(type)) {
|
|
469
493
|
case "INT":
|
|
470
494
|
const intValue = parseInt(value, 10);
|
|
471
495
|
return isNaN(intValue) ? value : intValue;
|
|
472
496
|
case "FLOAT":
|
|
497
|
+
case "DOUBLE":
|
|
498
|
+
case "LONG":
|
|
473
499
|
case "BIGDECIMAL":
|
|
500
|
+
case "BIG_DECIMAL":
|
|
474
501
|
const floatValue = parseFloat(value);
|
|
475
502
|
return isNaN(floatValue) ? value : floatValue;
|
|
476
503
|
case "DECIMAL":
|
|
@@ -478,14 +505,29 @@ function convertToColumnType(value, type) {
|
|
|
478
505
|
return isNaN(decimalValue) ? value : decimalValue;
|
|
479
506
|
case "DATE":
|
|
480
507
|
case "DATETIME":
|
|
481
|
-
case "
|
|
508
|
+
case "DATE_TIME":
|
|
509
|
+
case "TIME": return stringToDate(value, normalizedType) || value;
|
|
510
|
+
case "BOOLEAN":
|
|
511
|
+
if (value === "true" || value === "1" || value === 1 || value === true) return true;
|
|
512
|
+
if (value === "false" || value === "0" || value === 0 || value === false) return false;
|
|
513
|
+
return value;
|
|
482
514
|
case "BLOB": try {
|
|
483
515
|
return base64ToUint8Array(value);
|
|
484
516
|
} catch {
|
|
485
517
|
return value;
|
|
486
518
|
}
|
|
487
519
|
case "STRING": return value;
|
|
488
|
-
default: throw new ColumnTypeError(`Unsupported column type: ${
|
|
520
|
+
default: throw new ColumnTypeError(`Unsupported column type: ${normalizedType}`);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
/** Normalizes X-API/Java type spellings to the names used by Dataset XML. */
|
|
524
|
+
function normalizeColumnType(type) {
|
|
525
|
+
const normalized = type?.replace(/[- ]/g, "_").toUpperCase();
|
|
526
|
+
switch (normalized) {
|
|
527
|
+
case "DATE_TIME": return "DATETIME";
|
|
528
|
+
case "BIG_DECIMAL": return "BIGDECIMAL";
|
|
529
|
+
case "BOOL": return "BOOLEAN";
|
|
530
|
+
default: return normalized || "STRING";
|
|
489
531
|
}
|
|
490
532
|
}
|
|
491
533
|
/**
|
|
@@ -497,12 +539,17 @@ function convertToColumnType(value, type) {
|
|
|
497
539
|
function convertToString(value, type) {
|
|
498
540
|
switch (type) {
|
|
499
541
|
case "INT":
|
|
542
|
+
case "LONG":
|
|
500
543
|
case "BIGDECIMAL":
|
|
544
|
+
case "BIG_DECIMAL":
|
|
501
545
|
case "FLOAT":
|
|
546
|
+
case "DOUBLE":
|
|
502
547
|
case "DECIMAL": return String(value);
|
|
548
|
+
case "BOOLEAN": return value ? "true" : "false";
|
|
503
549
|
case "DATE":
|
|
504
550
|
case "DATETIME":
|
|
505
|
-
case "
|
|
551
|
+
case "DATE_TIME":
|
|
552
|
+
case "TIME": return dateToString(value, normalizeColumnType(type));
|
|
506
553
|
case "BLOB": return uint8ArrayToBase64(value);
|
|
507
554
|
case "STRING": return String(value);
|
|
508
555
|
default: return String(value);
|
|
@@ -927,8 +974,9 @@ function parseColumnInfo(columnInfoElement, dataset) {
|
|
|
927
974
|
dataset.addConstColumn({
|
|
928
975
|
id: attrs?.id,
|
|
929
976
|
size: sizeStr ? parseInt(sizeStr, 10) : 0,
|
|
930
|
-
type: attrs?.type
|
|
931
|
-
value: parseValue(attrs?.value, attrs?.type)
|
|
977
|
+
type: normalizeColumnType(attrs?.type),
|
|
978
|
+
value: parseValue(attrs?.value, attrs?.type),
|
|
979
|
+
rawValue: attrs?.value
|
|
932
980
|
});
|
|
933
981
|
} else if (tagName === "Column") {
|
|
934
982
|
const attrs = colInfo.attributes;
|
|
@@ -936,7 +984,7 @@ function parseColumnInfo(columnInfoElement, dataset) {
|
|
|
936
984
|
dataset.addColumn({
|
|
937
985
|
id: attrs?.id,
|
|
938
986
|
size: sizeStr ? parseInt(sizeStr, 10) : 0,
|
|
939
|
-
type: attrs?.type
|
|
987
|
+
type: normalizeColumnType(attrs?.type)
|
|
940
988
|
});
|
|
941
989
|
}
|
|
942
990
|
}
|
|
@@ -966,7 +1014,8 @@ function parseRows(rowsElement, dataset) {
|
|
|
966
1014
|
const castedValue = parseValue(value, columnInfo.type);
|
|
967
1015
|
currentRow.cols.push({
|
|
968
1016
|
id: colId,
|
|
969
|
-
value: castedValue
|
|
1017
|
+
value: castedValue,
|
|
1018
|
+
rawValue: value
|
|
970
1019
|
});
|
|
971
1020
|
} else if (colTagName === "OrgRow") {
|
|
972
1021
|
const orgRow = [];
|
|
@@ -980,7 +1029,8 @@ function parseRows(rowsElement, dataset) {
|
|
|
980
1029
|
const castedValue = parseValue(value, dataset.getColumnInfo(colId).type);
|
|
981
1030
|
orgRow.push({
|
|
982
1031
|
id: colId,
|
|
983
|
-
value: castedValue
|
|
1032
|
+
value: castedValue,
|
|
1033
|
+
rawValue: value
|
|
984
1034
|
});
|
|
985
1035
|
}
|
|
986
1036
|
}
|
|
@@ -1004,8 +1054,9 @@ function parseParameters(parametersElement, xapiRoot) {
|
|
|
1004
1054
|
const value = p.children?.[0] ?? attrs?.value;
|
|
1005
1055
|
xapiRoot.addParameter({
|
|
1006
1056
|
id,
|
|
1007
|
-
type,
|
|
1008
|
-
value: parseValue(value, type)
|
|
1057
|
+
type: normalizeColumnType(type),
|
|
1058
|
+
value: parseValue(value, type),
|
|
1059
|
+
rawValue: value
|
|
1009
1060
|
});
|
|
1010
1061
|
}
|
|
1011
1062
|
}
|
|
@@ -1030,7 +1081,7 @@ function writeParameters(builder, parameters) {
|
|
|
1030
1081
|
builder.writeStartElement("Parameters");
|
|
1031
1082
|
for (const parameter of parameters) {
|
|
1032
1083
|
const attrs = { id: parameter.id };
|
|
1033
|
-
if (parameter.type !== void 0) attrs.type = parameter.type;
|
|
1084
|
+
if (parameter.type !== void 0) attrs.type = normalizeColumnType(parameter.type);
|
|
1034
1085
|
if (parameter.value !== void 0) if (typeof parameter.value === "string") attrs.value = parameter.value;
|
|
1035
1086
|
else if (parameter.value instanceof Date) attrs.value = dateToString(parameter.value, parameter.type);
|
|
1036
1087
|
else if (parameter.value instanceof Uint8Array) attrs.value = uint8ArrayToBase64(parameter.value);
|
|
@@ -1046,13 +1097,13 @@ function writeDataset(builder, dataset) {
|
|
|
1046
1097
|
for (const constCol of dataset.getConstColumns()) builder.writeStartElement("ConstColumn", {
|
|
1047
1098
|
id: constCol.id,
|
|
1048
1099
|
size: String(constCol.size),
|
|
1049
|
-
type: constCol.type,
|
|
1100
|
+
type: normalizeColumnType(constCol.type),
|
|
1050
1101
|
value: constCol.value !== void 0 ? String(constCol.value) : ""
|
|
1051
1102
|
}, true);
|
|
1052
1103
|
for (const col of dataset.getColumns()) builder.writeStartElement("Column", {
|
|
1053
1104
|
id: col.id,
|
|
1054
1105
|
size: String(col.size),
|
|
1055
|
-
type: col.type
|
|
1106
|
+
type: normalizeColumnType(col.type)
|
|
1056
1107
|
}, true);
|
|
1057
1108
|
builder.writeEndElement("ColumnInfo");
|
|
1058
1109
|
}
|
|
@@ -1079,14 +1130,30 @@ function writeColumn(builder, dataset, col) {
|
|
|
1079
1130
|
}
|
|
1080
1131
|
//#endregion
|
|
1081
1132
|
//#region src/schema.ts
|
|
1133
|
+
const schemaCache = /* @__PURE__ */ new WeakMap();
|
|
1134
|
+
function compileSchema(schema) {
|
|
1135
|
+
const cached = schemaCache.get(schema);
|
|
1136
|
+
if (cached) return cached;
|
|
1137
|
+
const compiled = {
|
|
1138
|
+
parameters: new Map(Object.entries(schema.parameters)),
|
|
1139
|
+
datasets: new Map(Object.entries(schema.datasets).map(([id, dataset]) => [id, { columns: new Map(Object.entries(dataset.columns)) }]))
|
|
1140
|
+
};
|
|
1141
|
+
schemaCache.set(schema, compiled);
|
|
1142
|
+
return compiled;
|
|
1143
|
+
}
|
|
1082
1144
|
const defaultSizes = {
|
|
1083
1145
|
STRING: 256,
|
|
1084
1146
|
INT: 10,
|
|
1147
|
+
LONG: 19,
|
|
1085
1148
|
FLOAT: 20,
|
|
1149
|
+
DOUBLE: 20,
|
|
1086
1150
|
DECIMAL: 20,
|
|
1087
1151
|
BIGDECIMAL: 30,
|
|
1152
|
+
BIG_DECIMAL: 30,
|
|
1153
|
+
BOOLEAN: 5,
|
|
1088
1154
|
DATE: 8,
|
|
1089
1155
|
DATETIME: 17,
|
|
1156
|
+
DATE_TIME: 17,
|
|
1090
1157
|
TIME: 6,
|
|
1091
1158
|
BLOB: 1e3
|
|
1092
1159
|
};
|
|
@@ -1120,11 +1187,16 @@ function defineOperation(definition) {
|
|
|
1120
1187
|
const xapi = {
|
|
1121
1188
|
string: (options) => column("STRING", options),
|
|
1122
1189
|
int: (options) => column("INT", options),
|
|
1190
|
+
long: (options) => column("LONG", options),
|
|
1123
1191
|
float: (options) => column("FLOAT", options),
|
|
1192
|
+
double: (options) => column("DOUBLE", options),
|
|
1124
1193
|
decimal: (options) => column("DECIMAL", options),
|
|
1125
1194
|
bigdecimal: (options) => column("BIGDECIMAL", options),
|
|
1195
|
+
bigDecimal: (options) => column("BIG_DECIMAL", options),
|
|
1196
|
+
boolean: (options) => column("BOOLEAN", options),
|
|
1126
1197
|
date: (options) => column("DATE", options),
|
|
1127
1198
|
datetime: (options) => column("DATETIME", options),
|
|
1199
|
+
dateTime: (options) => column("DATE_TIME", options),
|
|
1128
1200
|
time: (options) => column("TIME", options),
|
|
1129
1201
|
blob: (options) => column("BLOB", options),
|
|
1130
1202
|
dataset: defineDataset,
|
|
@@ -1133,7 +1205,8 @@ const xapi = {
|
|
|
1133
1205
|
};
|
|
1134
1206
|
function encodeRoot(schema, value) {
|
|
1135
1207
|
const root = new XapiRoot();
|
|
1136
|
-
|
|
1208
|
+
const compiled = compileSchema(schema);
|
|
1209
|
+
for (const [id, parameterSchema] of compiled.parameters) {
|
|
1137
1210
|
const parameterValue = value.parameters[id];
|
|
1138
1211
|
if (parameterValue !== void 0 || !parameterSchema.optional) root.addParameter({
|
|
1139
1212
|
id,
|
|
@@ -1141,30 +1214,39 @@ function encodeRoot(schema, value) {
|
|
|
1141
1214
|
value: parameterValue
|
|
1142
1215
|
});
|
|
1143
1216
|
}
|
|
1144
|
-
for (const [datasetId,
|
|
1217
|
+
for (const [datasetId, datasetDefinition] of compiled.datasets) {
|
|
1145
1218
|
const dataset = new Dataset(datasetId);
|
|
1146
|
-
for (const [id, columnSchema] of
|
|
1219
|
+
for (const [id, columnSchema] of datasetDefinition.columns) dataset.addColumn({
|
|
1147
1220
|
id,
|
|
1148
1221
|
type: columnSchema.type,
|
|
1149
1222
|
size: columnSchema.size
|
|
1150
1223
|
});
|
|
1151
1224
|
const rows = value.datasets[datasetId];
|
|
1225
|
+
const columnIds = [...datasetDefinition.columns.keys()];
|
|
1152
1226
|
for (const row of rows) {
|
|
1153
1227
|
const rowIndex = dataset.newRow();
|
|
1154
|
-
|
|
1228
|
+
dataset.rows[rowIndex].type = row.$rowType;
|
|
1229
|
+
for (const id of columnIds) dataset.setColumn(rowIndex, id, row[id]);
|
|
1230
|
+
if (row.$orgRow) dataset.rows[rowIndex].orgRow = Object.entries(row.$orgRow).map(([id, value]) => ({
|
|
1231
|
+
id,
|
|
1232
|
+
value
|
|
1233
|
+
}));
|
|
1155
1234
|
}
|
|
1156
1235
|
root.addDataset(dataset);
|
|
1157
1236
|
}
|
|
1158
1237
|
return root;
|
|
1159
1238
|
}
|
|
1160
1239
|
function decodeRoot(schema, root) {
|
|
1240
|
+
const compiled = compileSchema(schema);
|
|
1161
1241
|
const parameters = {};
|
|
1162
|
-
for (const id of
|
|
1163
|
-
const
|
|
1164
|
-
|
|
1242
|
+
for (const [id, parameterSchema] of compiled.parameters) {
|
|
1243
|
+
const parameter = root.getParameter(id);
|
|
1244
|
+
const value = parameter?.rawValue !== void 0 ? parameter.rawValue : parameter?.value;
|
|
1245
|
+
if (value !== void 0) parameters[id] = convertToColumnType(value, parameterSchema.type);
|
|
1165
1246
|
}
|
|
1166
1247
|
const datasets = {};
|
|
1167
|
-
for (const [datasetId,
|
|
1248
|
+
for (const [datasetId, datasetDefinition] of compiled.datasets) {
|
|
1249
|
+
const schemaColumns = datasetDefinition.columns;
|
|
1168
1250
|
const dataset = root.getDataset(datasetId);
|
|
1169
1251
|
if (!dataset) {
|
|
1170
1252
|
datasets[datasetId] = [];
|
|
@@ -1173,7 +1255,20 @@ function decodeRoot(schema, root) {
|
|
|
1173
1255
|
const constants = Object.fromEntries(dataset.getConstColumns().map(({ id, value }) => [id, value]));
|
|
1174
1256
|
datasets[datasetId] = dataset.getRows().map((row) => {
|
|
1175
1257
|
const value = { ...constants };
|
|
1176
|
-
for (const column of row.cols)
|
|
1258
|
+
for (const column of row.cols) {
|
|
1259
|
+
const columnSchema = schemaColumns.get(column.id);
|
|
1260
|
+
if (columnSchema) {
|
|
1261
|
+
const rawValue = column.rawValue !== void 0 ? column.rawValue : column.value;
|
|
1262
|
+
value[column.id] = rawValue === void 0 ? void 0 : convertToColumnType(rawValue, columnSchema.type);
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
if (row.type) value.$rowType = row.type;
|
|
1266
|
+
if (row.orgRow) value.$orgRow = Object.fromEntries(row.orgRow.flatMap((column) => {
|
|
1267
|
+
const columnSchema = schemaColumns.get(column.id);
|
|
1268
|
+
if (!columnSchema) return [];
|
|
1269
|
+
const rawValue = column.rawValue !== void 0 ? column.rawValue : column.value;
|
|
1270
|
+
return [[column.id, rawValue === void 0 ? void 0 : convertToColumnType(rawValue, columnSchema.type)]];
|
|
1271
|
+
}));
|
|
1177
1272
|
return value;
|
|
1178
1273
|
});
|
|
1179
1274
|
}
|
|
@@ -1183,4 +1278,136 @@ function decodeRoot(schema, root) {
|
|
|
1183
1278
|
};
|
|
1184
1279
|
}
|
|
1185
1280
|
//#endregion
|
|
1186
|
-
|
|
1281
|
+
//#region src/codec.ts
|
|
1282
|
+
const rowTypes = {
|
|
1283
|
+
N: void 0,
|
|
1284
|
+
I: "insert",
|
|
1285
|
+
U: "update",
|
|
1286
|
+
D: "delete",
|
|
1287
|
+
O: void 0
|
|
1288
|
+
};
|
|
1289
|
+
function sizeOf(size, type) {
|
|
1290
|
+
if (size !== void 0) return Number(size);
|
|
1291
|
+
return type === "STRING" ? 255 : 0;
|
|
1292
|
+
}
|
|
1293
|
+
function jsonValue(value, type) {
|
|
1294
|
+
if (value === null || value === void 0) return void 0;
|
|
1295
|
+
return convertToColumnType(typeof value === "string" ? value : String(value), normalizeColumnType(type));
|
|
1296
|
+
}
|
|
1297
|
+
function jsonRawValue(value) {
|
|
1298
|
+
return value === null || value === void 0 ? void 0 : String(value);
|
|
1299
|
+
}
|
|
1300
|
+
function jsonWireValue(value, type) {
|
|
1301
|
+
if (value === void 0) return void 0;
|
|
1302
|
+
if (value instanceof Date) return dateToString(value, type);
|
|
1303
|
+
if (value instanceof Uint8Array) return uint8ArrayToBase64(value);
|
|
1304
|
+
return value;
|
|
1305
|
+
}
|
|
1306
|
+
function columnsToObject(columns) {
|
|
1307
|
+
return Object.fromEntries(columns.map((column) => [column.id, column.value]));
|
|
1308
|
+
}
|
|
1309
|
+
function readRow(dataset, row) {
|
|
1310
|
+
const rowType = rowTypes[row._RowType_ ?? "N"];
|
|
1311
|
+
if (row._RowType_ === "O") {
|
|
1312
|
+
const previous = dataset.rows[dataset.rows.length - 1];
|
|
1313
|
+
if (previous?.type !== "update") return;
|
|
1314
|
+
previous.orgRow = dataset.getColumns().filter((column) => Object.prototype.hasOwnProperty.call(row, column.id)).map((column) => ({
|
|
1315
|
+
id: column.id,
|
|
1316
|
+
value: jsonValue(row[column.id], column.type),
|
|
1317
|
+
rawValue: jsonRawValue(row[column.id])
|
|
1318
|
+
}));
|
|
1319
|
+
return;
|
|
1320
|
+
}
|
|
1321
|
+
const index = dataset.newRow();
|
|
1322
|
+
dataset.rows[index].type = rowType;
|
|
1323
|
+
for (const column of dataset.getColumns()) if (Object.prototype.hasOwnProperty.call(row, column.id)) dataset.rows[index].cols.push({
|
|
1324
|
+
id: column.id,
|
|
1325
|
+
value: jsonValue(row[column.id], column.type),
|
|
1326
|
+
rawValue: jsonRawValue(row[column.id])
|
|
1327
|
+
});
|
|
1328
|
+
}
|
|
1329
|
+
function readJson(value) {
|
|
1330
|
+
const root = new XapiRoot();
|
|
1331
|
+
for (const parameter of value.Parameters ?? []) {
|
|
1332
|
+
const type = normalizeColumnType(parameter.type);
|
|
1333
|
+
root.addParameter({
|
|
1334
|
+
id: parameter.id,
|
|
1335
|
+
type,
|
|
1336
|
+
value: jsonValue(parameter.value, type),
|
|
1337
|
+
rawValue: jsonRawValue(parameter.value)
|
|
1338
|
+
});
|
|
1339
|
+
}
|
|
1340
|
+
for (const source of value.Datasets ?? []) {
|
|
1341
|
+
const dataset = new Dataset(source.id);
|
|
1342
|
+
for (const column of source.ColumnInfo.ConstColumn ?? []) {
|
|
1343
|
+
const type = normalizeColumnType(column.type);
|
|
1344
|
+
dataset.addConstColumn({
|
|
1345
|
+
id: column.id,
|
|
1346
|
+
type,
|
|
1347
|
+
size: sizeOf(column.size, type),
|
|
1348
|
+
value: jsonValue(column.value, type),
|
|
1349
|
+
rawValue: jsonRawValue(column.value)
|
|
1350
|
+
});
|
|
1351
|
+
}
|
|
1352
|
+
for (const column of source.ColumnInfo.Column) {
|
|
1353
|
+
const type = normalizeColumnType(column.type);
|
|
1354
|
+
dataset.addColumn({
|
|
1355
|
+
id: column.id,
|
|
1356
|
+
type,
|
|
1357
|
+
size: sizeOf(column.size, type)
|
|
1358
|
+
});
|
|
1359
|
+
}
|
|
1360
|
+
for (const row of source.Rows) readRow(dataset, row);
|
|
1361
|
+
root.addDataset(dataset);
|
|
1362
|
+
}
|
|
1363
|
+
return root;
|
|
1364
|
+
}
|
|
1365
|
+
function writeJson(root) {
|
|
1366
|
+
return {
|
|
1367
|
+
version: "1.0",
|
|
1368
|
+
...root.parameterSize() ? { Parameters: root.getParameters().map((parameter) => ({
|
|
1369
|
+
id: parameter.id,
|
|
1370
|
+
...parameter.type ? { type: parameter.type } : {},
|
|
1371
|
+
...parameter.value !== void 0 ? { value: jsonWireValue(parameter.value, parameter.type ?? "STRING") } : {}
|
|
1372
|
+
})) } : {},
|
|
1373
|
+
...root.datasetSize() ? { Datasets: root.getDatasets().map((dataset) => ({
|
|
1374
|
+
id: dataset.id,
|
|
1375
|
+
ColumnInfo: {
|
|
1376
|
+
...dataset.constColumnSize() ? { ConstColumn: dataset.getConstColumns().map((column) => ({
|
|
1377
|
+
id: column.id,
|
|
1378
|
+
type: column.type,
|
|
1379
|
+
size: column.size,
|
|
1380
|
+
value: jsonWireValue(column.value, column.type)
|
|
1381
|
+
})) } : {},
|
|
1382
|
+
Column: dataset.getColumns().map((column) => ({
|
|
1383
|
+
id: column.id,
|
|
1384
|
+
type: column.type,
|
|
1385
|
+
size: column.size
|
|
1386
|
+
}))
|
|
1387
|
+
},
|
|
1388
|
+
Rows: dataset.getRows().flatMap((row) => {
|
|
1389
|
+
const current = {
|
|
1390
|
+
_RowType_: row.type === "insert" ? "I" : row.type === "update" ? "U" : row.type === "delete" ? "D" : "N",
|
|
1391
|
+
...columnsToObject(row.cols)
|
|
1392
|
+
};
|
|
1393
|
+
if (!row.orgRow) return [current];
|
|
1394
|
+
return [current, {
|
|
1395
|
+
_RowType_: "O",
|
|
1396
|
+
...columnsToObject(row.orgRow)
|
|
1397
|
+
}];
|
|
1398
|
+
})
|
|
1399
|
+
})) } : {}
|
|
1400
|
+
};
|
|
1401
|
+
}
|
|
1402
|
+
const nexacroJsonCodec = {
|
|
1403
|
+
serialize: writeJson,
|
|
1404
|
+
deserialize: readJson
|
|
1405
|
+
};
|
|
1406
|
+
function parseJson(value) {
|
|
1407
|
+
return nexacroJsonCodec.deserialize(JSON.parse(value));
|
|
1408
|
+
}
|
|
1409
|
+
function writeJsonString(root) {
|
|
1410
|
+
return JSON.stringify(nexacroJsonCodec.serialize(root));
|
|
1411
|
+
}
|
|
1412
|
+
//#endregion
|
|
1413
|
+
export { ColumnTypeError, Dataset, InvalidXmlError, NexaVersion, StringWritableStream, XapiRoot, XmlStringBuilder, XplatformVersion, _unescapeXml, arrayBufferToString, base64ToUint8Array, columnType, convertToColumnType, convertToString, dateToString, decodeRoot, defineDataset, defineOperation, defineRoot, encodeControlChars, encodeRoot, escapeXml, initXapi, isXapiRoot, makeParseEntities, nexacroJsonCodec, normalizeColumnType, parse, parseJson, parseXml, rowType, stringToDate, stringToReadableStream, uint8ArrayToBase64, write, writeJsonString, xapi };
|