@xapi-js/core 1.6.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 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) milliseconds = parseInt(value.substring(14, 16), 10);
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
- switch (type) {
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 "TIME": return stringToDate(value) || value;
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: ${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 "TIME": return dateToString(value, type);
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 || "STRING",
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 || "STRING"
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
- for (const [id, parameterSchema] of Object.entries(schema.parameters)) {
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,18 +1215,19 @@ function encodeRoot(schema, value) {
1142
1215
  value: parameterValue
1143
1216
  });
1144
1217
  }
1145
- for (const [datasetId, datasetSchema] of Object.entries(schema.datasets)) {
1218
+ for (const [datasetId, datasetDefinition] of compiled.datasets) {
1146
1219
  const dataset = new Dataset(datasetId);
1147
- for (const [id, columnSchema] of Object.entries(datasetSchema.columns)) dataset.addColumn({
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;
1156
- for (const id of Object.keys(datasetSchema.columns)) dataset.setColumn(rowIndex, id, row[id]);
1230
+ for (const id of columnIds) dataset.setColumn(rowIndex, id, row[id]);
1157
1231
  if (row.$orgRow) dataset.rows[rowIndex].orgRow = Object.entries(row.$orgRow).map(([id, value]) => ({
1158
1232
  id,
1159
1233
  value
@@ -1164,13 +1238,16 @@ function encodeRoot(schema, value) {
1164
1238
  return root;
1165
1239
  }
1166
1240
  function decodeRoot(schema, root) {
1241
+ const compiled = compileSchema(schema);
1167
1242
  const parameters = {};
1168
- for (const id of Object.keys(schema.parameters)) {
1169
- const value = root.getParameter(id)?.value;
1170
- if (value !== void 0) parameters[id] = value;
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);
1171
1247
  }
1172
1248
  const datasets = {};
1173
- for (const [datasetId, datasetSchema] of Object.entries(schema.datasets)) {
1249
+ for (const [datasetId, datasetDefinition] of compiled.datasets) {
1250
+ const schemaColumns = datasetDefinition.columns;
1174
1251
  const dataset = root.getDataset(datasetId);
1175
1252
  if (!dataset) {
1176
1253
  datasets[datasetId] = [];
@@ -1179,9 +1256,20 @@ function decodeRoot(schema, root) {
1179
1256
  const constants = Object.fromEntries(dataset.getConstColumns().map(({ id, value }) => [id, value]));
1180
1257
  datasets[datasetId] = dataset.getRows().map((row) => {
1181
1258
  const value = { ...constants };
1182
- for (const column of row.cols) if (column.id in datasetSchema.columns) value[column.id] = column.value;
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
+ }
1183
1266
  if (row.type) value.$rowType = row.type;
1184
- if (row.orgRow) value.$orgRow = Object.fromEntries(row.orgRow.map((column) => [column.id, column.value]));
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
+ }));
1185
1273
  return value;
1186
1274
  });
1187
1275
  }
@@ -1205,9 +1293,10 @@ function sizeOf(size, type) {
1205
1293
  }
1206
1294
  function jsonValue(value, type) {
1207
1295
  if (value === null || value === void 0) return void 0;
1208
- if (type === "DATE" || type === "DATETIME" || type === "TIME") return typeof value === "string" ? convertToColumnType(value, type) : value;
1209
- if (type === "BLOB" && typeof value === "string") return convertToColumnType(value, type);
1210
- return value;
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);
1211
1300
  }
1212
1301
  function jsonWireValue(value, type) {
1213
1302
  if (value === void 0) return void 0;
@@ -1225,7 +1314,8 @@ function readRow(dataset, row) {
1225
1314
  if (previous?.type !== "update") return;
1226
1315
  previous.orgRow = dataset.getColumns().filter((column) => Object.prototype.hasOwnProperty.call(row, column.id)).map((column) => ({
1227
1316
  id: column.id,
1228
- value: jsonValue(row[column.id], column.type)
1317
+ value: jsonValue(row[column.id], column.type),
1318
+ rawValue: jsonRawValue(row[column.id])
1229
1319
  }));
1230
1320
  return;
1231
1321
  }
@@ -1233,29 +1323,35 @@ function readRow(dataset, row) {
1233
1323
  dataset.rows[index].type = rowType;
1234
1324
  for (const column of dataset.getColumns()) if (Object.prototype.hasOwnProperty.call(row, column.id)) dataset.rows[index].cols.push({
1235
1325
  id: column.id,
1236
- value: jsonValue(row[column.id], column.type)
1326
+ value: jsonValue(row[column.id], column.type),
1327
+ rawValue: jsonRawValue(row[column.id])
1237
1328
  });
1238
1329
  }
1239
1330
  function readJson(value) {
1240
1331
  const root = new XapiRoot();
1241
- for (const parameter of value.Parameters ?? []) root.addParameter({
1242
- id: parameter.id,
1243
- type: parameter.type,
1244
- value: jsonValue(parameter.value, parameter.type)
1245
- });
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
+ }
1246
1341
  for (const source of value.Datasets ?? []) {
1247
1342
  const dataset = new Dataset(source.id);
1248
1343
  for (const column of source.ColumnInfo.ConstColumn ?? []) {
1249
- const type = column.type ?? "STRING";
1344
+ const type = normalizeColumnType(column.type);
1250
1345
  dataset.addConstColumn({
1251
1346
  id: column.id,
1252
1347
  type,
1253
1348
  size: sizeOf(column.size, type),
1254
- value: jsonValue(column.value, type)
1349
+ value: jsonValue(column.value, type),
1350
+ rawValue: jsonRawValue(column.value)
1255
1351
  });
1256
1352
  }
1257
1353
  for (const column of source.ColumnInfo.Column) {
1258
- const type = column.type ?? "STRING";
1354
+ const type = normalizeColumnType(column.type);
1259
1355
  dataset.addColumn({
1260
1356
  id: column.id,
1261
1357
  type,
@@ -1341,6 +1437,7 @@ exports.initXapi = initXapi;
1341
1437
  exports.isXapiRoot = isXapiRoot;
1342
1438
  exports.makeParseEntities = makeParseEntities;
1343
1439
  exports.nexacroJsonCodec = nexacroJsonCodec;
1440
+ exports.normalizeColumnType = normalizeColumnType;
1344
1441
  exports.parse = parse;
1345
1442
  exports.parseJson = parseJson;
1346
1443
  exports.parseXml = parseXml;
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
  };
@@ -537,11 +549,16 @@ declare function defineOperation<const Request extends XapiRootSchema, const Res
537
549
  declare const xapi: {
538
550
  readonly string: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"STRING", Optional>;
539
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>;
540
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>;
541
555
  readonly decimal: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"DECIMAL", Optional>;
542
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>;
543
559
  readonly date: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"DATE", Optional>;
544
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>;
545
562
  readonly time: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"TIME", Optional>;
546
563
  readonly blob: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"BLOB", Optional>;
547
564
  readonly dataset: typeof defineDataset;
@@ -556,13 +573,13 @@ declare function decodeRoot<Schema extends XapiRootSchema>(schema: Schema, root:
556
573
  interface NexacroJsonParameter {
557
574
  id: string;
558
575
  type?: ColumnType;
559
- value?: string | number;
576
+ value?: string | number | boolean;
560
577
  }
561
578
  interface NexacroJsonColumn {
562
579
  id: string;
563
580
  type?: ColumnType;
564
581
  size?: number | string;
565
- value?: string | number;
582
+ value?: string | number | boolean;
566
583
  }
567
584
  interface NexacroJsonRow {
568
585
  _RowType_?: "N" | "I" | "U" | "D" | "O";
@@ -590,4 +607,4 @@ declare const nexacroJsonCodec: XapiCodec<NexacroJsonRoot>;
590
607
  declare function parseJson(value: string): XapiRoot;
591
608
  declare function writeJsonString(root: XapiRoot): string;
592
609
  //#endregion
593
- 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, parse, parseJson, parseXml, rowType, stringToDate, stringToReadableStream, uint8ArrayToBase64, write, writeJsonString, xapi };
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
  };
@@ -537,11 +549,16 @@ declare function defineOperation<const Request extends XapiRootSchema, const Res
537
549
  declare const xapi: {
538
550
  readonly string: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"STRING", Optional>;
539
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>;
540
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>;
541
555
  readonly decimal: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"DECIMAL", Optional>;
542
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>;
543
559
  readonly date: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"DATE", Optional>;
544
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>;
545
562
  readonly time: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"TIME", Optional>;
546
563
  readonly blob: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"BLOB", Optional>;
547
564
  readonly dataset: typeof defineDataset;
@@ -556,13 +573,13 @@ declare function decodeRoot<Schema extends XapiRootSchema>(schema: Schema, root:
556
573
  interface NexacroJsonParameter {
557
574
  id: string;
558
575
  type?: ColumnType;
559
- value?: string | number;
576
+ value?: string | number | boolean;
560
577
  }
561
578
  interface NexacroJsonColumn {
562
579
  id: string;
563
580
  type?: ColumnType;
564
581
  size?: number | string;
565
- value?: string | number;
582
+ value?: string | number | boolean;
566
583
  }
567
584
  interface NexacroJsonRow {
568
585
  _RowType_?: "N" | "I" | "U" | "D" | "O";
@@ -590,4 +607,4 @@ declare const nexacroJsonCodec: XapiCodec<NexacroJsonRoot>;
590
607
  declare function parseJson(value: string): XapiRoot;
591
608
  declare function writeJsonString(root: XapiRoot): string;
592
609
  //#endregion
593
- 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, parse, parseJson, parseXml, rowType, stringToDate, stringToReadableStream, uint8ArrayToBase64, write, writeJsonString, xapi };
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) milliseconds = parseInt(value.substring(14, 16), 10);
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
- switch (type) {
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 "TIME": return stringToDate(value) || value;
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: ${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 "TIME": return dateToString(value, type);
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 || "STRING",
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 || "STRING"
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
- for (const [id, parameterSchema] of Object.entries(schema.parameters)) {
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,18 +1214,19 @@ function encodeRoot(schema, value) {
1141
1214
  value: parameterValue
1142
1215
  });
1143
1216
  }
1144
- for (const [datasetId, datasetSchema] of Object.entries(schema.datasets)) {
1217
+ for (const [datasetId, datasetDefinition] of compiled.datasets) {
1145
1218
  const dataset = new Dataset(datasetId);
1146
- for (const [id, columnSchema] of Object.entries(datasetSchema.columns)) dataset.addColumn({
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;
1155
- for (const id of Object.keys(datasetSchema.columns)) dataset.setColumn(rowIndex, id, row[id]);
1229
+ for (const id of columnIds) dataset.setColumn(rowIndex, id, row[id]);
1156
1230
  if (row.$orgRow) dataset.rows[rowIndex].orgRow = Object.entries(row.$orgRow).map(([id, value]) => ({
1157
1231
  id,
1158
1232
  value
@@ -1163,13 +1237,16 @@ function encodeRoot(schema, value) {
1163
1237
  return root;
1164
1238
  }
1165
1239
  function decodeRoot(schema, root) {
1240
+ const compiled = compileSchema(schema);
1166
1241
  const parameters = {};
1167
- for (const id of Object.keys(schema.parameters)) {
1168
- const value = root.getParameter(id)?.value;
1169
- if (value !== void 0) parameters[id] = value;
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);
1170
1246
  }
1171
1247
  const datasets = {};
1172
- for (const [datasetId, datasetSchema] of Object.entries(schema.datasets)) {
1248
+ for (const [datasetId, datasetDefinition] of compiled.datasets) {
1249
+ const schemaColumns = datasetDefinition.columns;
1173
1250
  const dataset = root.getDataset(datasetId);
1174
1251
  if (!dataset) {
1175
1252
  datasets[datasetId] = [];
@@ -1178,9 +1255,20 @@ function decodeRoot(schema, root) {
1178
1255
  const constants = Object.fromEntries(dataset.getConstColumns().map(({ id, value }) => [id, value]));
1179
1256
  datasets[datasetId] = dataset.getRows().map((row) => {
1180
1257
  const value = { ...constants };
1181
- for (const column of row.cols) if (column.id in datasetSchema.columns) value[column.id] = column.value;
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
+ }
1182
1265
  if (row.type) value.$rowType = row.type;
1183
- if (row.orgRow) value.$orgRow = Object.fromEntries(row.orgRow.map((column) => [column.id, column.value]));
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
+ }));
1184
1272
  return value;
1185
1273
  });
1186
1274
  }
@@ -1204,9 +1292,10 @@ function sizeOf(size, type) {
1204
1292
  }
1205
1293
  function jsonValue(value, type) {
1206
1294
  if (value === null || value === void 0) return void 0;
1207
- if (type === "DATE" || type === "DATETIME" || type === "TIME") return typeof value === "string" ? convertToColumnType(value, type) : value;
1208
- if (type === "BLOB" && typeof value === "string") return convertToColumnType(value, type);
1209
- return value;
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);
1210
1299
  }
1211
1300
  function jsonWireValue(value, type) {
1212
1301
  if (value === void 0) return void 0;
@@ -1224,7 +1313,8 @@ function readRow(dataset, row) {
1224
1313
  if (previous?.type !== "update") return;
1225
1314
  previous.orgRow = dataset.getColumns().filter((column) => Object.prototype.hasOwnProperty.call(row, column.id)).map((column) => ({
1226
1315
  id: column.id,
1227
- value: jsonValue(row[column.id], column.type)
1316
+ value: jsonValue(row[column.id], column.type),
1317
+ rawValue: jsonRawValue(row[column.id])
1228
1318
  }));
1229
1319
  return;
1230
1320
  }
@@ -1232,29 +1322,35 @@ function readRow(dataset, row) {
1232
1322
  dataset.rows[index].type = rowType;
1233
1323
  for (const column of dataset.getColumns()) if (Object.prototype.hasOwnProperty.call(row, column.id)) dataset.rows[index].cols.push({
1234
1324
  id: column.id,
1235
- value: jsonValue(row[column.id], column.type)
1325
+ value: jsonValue(row[column.id], column.type),
1326
+ rawValue: jsonRawValue(row[column.id])
1236
1327
  });
1237
1328
  }
1238
1329
  function readJson(value) {
1239
1330
  const root = new XapiRoot();
1240
- for (const parameter of value.Parameters ?? []) root.addParameter({
1241
- id: parameter.id,
1242
- type: parameter.type,
1243
- value: jsonValue(parameter.value, parameter.type)
1244
- });
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
+ }
1245
1340
  for (const source of value.Datasets ?? []) {
1246
1341
  const dataset = new Dataset(source.id);
1247
1342
  for (const column of source.ColumnInfo.ConstColumn ?? []) {
1248
- const type = column.type ?? "STRING";
1343
+ const type = normalizeColumnType(column.type);
1249
1344
  dataset.addConstColumn({
1250
1345
  id: column.id,
1251
1346
  type,
1252
1347
  size: sizeOf(column.size, type),
1253
- value: jsonValue(column.value, type)
1348
+ value: jsonValue(column.value, type),
1349
+ rawValue: jsonRawValue(column.value)
1254
1350
  });
1255
1351
  }
1256
1352
  for (const column of source.ColumnInfo.Column) {
1257
- const type = column.type ?? "STRING";
1353
+ const type = normalizeColumnType(column.type);
1258
1354
  dataset.addColumn({
1259
1355
  id: column.id,
1260
1356
  type,
@@ -1314,4 +1410,4 @@ function writeJsonString(root) {
1314
1410
  return JSON.stringify(nexacroJsonCodec.serialize(root));
1315
1411
  }
1316
1412
  //#endregion
1317
- 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, parse, parseJson, parseXml, rowType, stringToDate, stringToReadableStream, uint8ArrayToBase64, write, writeJsonString, xapi };
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 };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xapi-js/core",
3
3
  "type": "module",
4
- "version": "1.6.0",
4
+ "version": "1.6.1",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",