@saptools/cf-hana 0.3.0 → 0.3.2

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.d.ts CHANGED
@@ -328,6 +328,7 @@ interface CfHanaErrorOptions {
328
328
  }
329
329
  interface QueryErrorOptions extends CfHanaErrorOptions {
330
330
  readonly sqlState?: string;
331
+ readonly databaseCode?: number;
331
332
  }
332
333
  /** Base error for every failure surfaced by `@saptools/cf-hana`. */
333
334
  declare class CfHanaError extends Error {
@@ -341,6 +342,7 @@ declare class CredentialsNotFoundError extends CfHanaError {
341
342
  /** A SQL statement failed on the HANA server. */
342
343
  declare class QueryError extends CfHanaError {
343
344
  readonly sqlState: string | undefined;
345
+ readonly databaseCode: number | undefined;
344
346
  constructor(message: string, options?: QueryErrorOptions);
345
347
  }
346
348
  /** A write/DDL statement was issued on a read-only client. */
package/dist/index.js CHANGED
@@ -23,12 +23,36 @@ var CredentialsNotFoundError = class extends CfHanaError {
23
23
  };
24
24
  var QueryError = class extends CfHanaError {
25
25
  sqlState;
26
+ databaseCode;
26
27
  constructor(message, options) {
27
28
  super("QUERY", message, options);
28
29
  this.name = "QueryError";
29
30
  this.sqlState = options?.sqlState;
31
+ this.databaseCode = options?.databaseCode;
30
32
  }
31
33
  };
34
+ function isDatabaseErrorShape(error) {
35
+ return typeof error === "object" && error !== null && "code" in error;
36
+ }
37
+ function safeDatabaseCode(value) {
38
+ if (typeof value === "number" && Number.isSafeInteger(value)) {
39
+ return value;
40
+ }
41
+ if (typeof value !== "string" || !/^\d+$/.test(value)) {
42
+ return void 0;
43
+ }
44
+ const parsed = Number(value);
45
+ return Number.isSafeInteger(parsed) ? parsed : void 0;
46
+ }
47
+ function databaseCode(error) {
48
+ if (error instanceof QueryError) {
49
+ return error.databaseCode ?? databaseCode(error.cause);
50
+ }
51
+ if (isDatabaseErrorShape(error)) {
52
+ return safeDatabaseCode(error.code);
53
+ }
54
+ return void 0;
55
+ }
32
56
  var ReadOnlyViolationError = class extends CfHanaError {
33
57
  constructor(message, options) {
34
58
  super("READ_ONLY_VIOLATION", message, options);
@@ -601,7 +625,7 @@ async function listColumns(connection, schema, table) {
601
625
  }
602
626
 
603
627
  // src/config.ts
604
- var CLI_VERSION = "0.3.0";
628
+ var CLI_VERSION = "0.3.2";
605
629
  var ENV_PREFIX = "CF_HANA";
606
630
  var DEFAULT_QUERY_TIMEOUT_MS = 3e4;
607
631
  var DEFAULT_CONNECT_TIMEOUT_MS = 3e4;
@@ -1065,7 +1089,15 @@ function catalogObjects() {
1065
1089
  { SCHEMA_NAME: "APP_SCHEMA", OBJECT_NAME: "EXISTING_TABLE", OBJECT_TYPE: "TABLE" },
1066
1090
  { SCHEMA_NAME: "APP_SCHEMA", OBJECT_NAME: "MISSING_TABLE_FIXED", OBJECT_TYPE: "TABLE" },
1067
1091
  { SCHEMA_NAME: "APP_SCHEMA", OBJECT_NAME: "MISSING_TABLE_VIEW", OBJECT_TYPE: "VIEW" },
1068
- { SCHEMA_NAME: "APP_SCHEMA", OBJECT_NAME: "STATUS_ITEMS", OBJECT_TYPE: "TABLE" }
1092
+ { SCHEMA_NAME: "APP_SCHEMA", OBJECT_NAME: "STATUS_ITEMS", OBJECT_TYPE: "TABLE" },
1093
+ { SCHEMA_NAME: "APP_SCHEMA", OBJECT_NAME: "CORE_AUTH_SCOPE", OBJECT_TYPE: "TABLE" }
1094
+ ];
1095
+ }
1096
+ function tableColumns() {
1097
+ return [
1098
+ { COLUMN_NAME: "ID", DATA_TYPE_NAME: "INTEGER", LENGTH: null, SCALE: null, IS_NULLABLE: "FALSE", POSITION: 1 },
1099
+ { COLUMN_NAME: "IS_ACTIVE", DATA_TYPE_NAME: "BOOLEAN", LENGTH: null, SCALE: null, IS_NULLABLE: "TRUE", POSITION: 2 },
1100
+ { COLUMN_NAME: "SCOPE_NAME", DATA_TYPE_NAME: "NVARCHAR", LENGTH: 255, SCALE: null, IS_NULLABLE: "TRUE", POSITION: 3 }
1069
1101
  ];
1070
1102
  }
1071
1103
  function fakeExec(sql) {
@@ -1090,9 +1122,32 @@ function fakeExec(sql) {
1090
1122
  affectedRows: 0
1091
1123
  };
1092
1124
  }
1125
+ if (upperSql.includes("SYS.TABLE_COLUMNS")) {
1126
+ return {
1127
+ rows: tableColumns(),
1128
+ columns: [
1129
+ { name: "COLUMN_NAME", typeName: "NVARCHAR" },
1130
+ { name: "DATA_TYPE_NAME", typeName: "NVARCHAR" },
1131
+ { name: "LENGTH", typeName: "INTEGER" },
1132
+ { name: "SCALE", typeName: "INTEGER" },
1133
+ { name: "IS_NULLABLE", typeName: "NVARCHAR" },
1134
+ { name: "POSITION", typeName: "INTEGER" }
1135
+ ],
1136
+ affectedRows: 0
1137
+ };
1138
+ }
1093
1139
  if (upperSql.includes("MISSING_TABLE") || upperSql.includes("MISSING_TABLES")) {
1094
1140
  throw new QueryError("invalid table name: MISSING_TABLE", { sqlState: "42S02" });
1095
1141
  }
1142
+ if (upperSql.includes("ISACTIVE")) {
1143
+ throw new QueryError("invalid column name: ISACTIVE: line 1 col 8 (at pos 7)", { databaseCode: 260 });
1144
+ }
1145
+ if (upperSql.includes("LOB_ORDER_ERROR")) {
1146
+ throw new QueryError("inconsistent datatype: LOB type is not allowed in ORDER BY clause", { databaseCode: 266 });
1147
+ }
1148
+ if (upperSql.includes("LOB_GROUP_ERROR")) {
1149
+ throw new QueryError("inconsistent datatype: LOB type is not allowed in GROUP BY clause", { databaseCode: 274 });
1150
+ }
1096
1151
  if (sql.toUpperCase().includes("LOB_FIXTURE")) {
1097
1152
  return {
1098
1153
  rows: [
@@ -1217,7 +1272,12 @@ function extractSqlState(error) {
1217
1272
  }
1218
1273
  function toQueryError(error) {
1219
1274
  const sqlState = extractSqlState(error);
1220
- return sqlState === void 0 ? new QueryError(error.message, { cause: error }) : new QueryError(error.message, { cause: error, sqlState });
1275
+ const code = databaseCode(error);
1276
+ return new QueryError(error.message, {
1277
+ cause: error,
1278
+ ...sqlState === void 0 ? {} : { sqlState },
1279
+ ...code === void 0 ? {} : { databaseCode: code }
1280
+ });
1221
1281
  }
1222
1282
  function toColumns(metadata) {
1223
1283
  if (metadata === void 0) {