@saptools/cf-hana 0.1.5 → 0.2.0

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.js CHANGED
@@ -478,14 +478,17 @@ function buildDelete(schema, table, where) {
478
478
  // src/catalog.ts
479
479
  async function listSchemas(connection) {
480
480
  const result = await connection.query(
481
- "SELECT SCHEMA_NAME FROM SYS.SCHEMAS ORDER BY SCHEMA_NAME"
481
+ "SELECT SCHEMA_NAME FROM SYS.SCHEMAS ORDER BY SCHEMA_NAME",
482
+ [],
483
+ { autoLimit: false }
482
484
  );
483
485
  return result.rows.map((row) => row.SCHEMA_NAME);
484
486
  }
485
487
  async function listTables(connection, schema) {
486
488
  const result = await connection.query(
487
489
  "SELECT SCHEMA_NAME, TABLE_NAME, TABLE_TYPE FROM SYS.TABLES WHERE SCHEMA_NAME = ? ORDER BY TABLE_NAME",
488
- [schema]
490
+ [schema],
491
+ { autoLimit: false }
489
492
  );
490
493
  return result.rows.map((row) => ({
491
494
  schema: row.SCHEMA_NAME,
@@ -497,7 +500,8 @@ async function listTables(connection, schema) {
497
500
  async function listColumns(connection, schema, table) {
498
501
  const result = await connection.query(
499
502
  "SELECT COLUMN_NAME, DATA_TYPE_NAME, LENGTH, SCALE, IS_NULLABLE, POSITION FROM SYS.TABLE_COLUMNS WHERE SCHEMA_NAME = ? AND TABLE_NAME = ? ORDER BY POSITION",
500
- [schema, table]
503
+ [schema, table],
504
+ { autoLimit: false }
501
505
  );
502
506
  return result.rows.map((row) => ({
503
507
  name: row.COLUMN_NAME,
@@ -510,13 +514,14 @@ async function listColumns(connection, schema, table) {
510
514
  }
511
515
 
512
516
  // src/config.ts
513
- var CLI_VERSION = "0.1.5";
517
+ var CLI_VERSION = "0.2.0";
514
518
  var ENV_PREFIX = "CF_HANA";
515
519
  var DEFAULT_QUERY_TIMEOUT_MS = 3e4;
516
520
  var DEFAULT_CONNECT_TIMEOUT_MS = 3e4;
517
521
  var DEFAULT_POOL_MAX = 4;
518
522
  var DEFAULT_POOL_IDLE_MS = 6e4;
519
- var DEFAULT_AUTO_LIMIT = 1e3;
523
+ var DEFAULT_AUTO_LIMIT = 100;
524
+ var MAX_RESULT_STORE_BYTES = 256 * 1024 * 1024;
520
525
  function envName(suffix) {
521
526
  return `${ENV_PREFIX}_${suffix}`;
522
527
  }
@@ -629,7 +634,13 @@ function toConnectionTarget(binding, role) {
629
634
  }
630
635
 
631
636
  // src/driver/fake.ts
637
+ import { appendFile } from "fs/promises";
632
638
  function fakeExec(sql) {
639
+ const kind = classifyStatement(sql);
640
+ const forcedFailure = readEnv(envName("FAKE_FAIL_STATEMENT"))?.toLowerCase();
641
+ if (forcedFailure === kind) {
642
+ throw new Error(`fake driver forced ${kind.toUpperCase()} failure`);
643
+ }
633
644
  if (sql.toUpperCase().includes("DUMMY")) {
634
645
  return {
635
646
  rows: [{ "1": 1 }],
@@ -637,7 +648,6 @@ function fakeExec(sql) {
637
648
  affectedRows: 0
638
649
  };
639
650
  }
640
- const kind = classifyStatement(sql);
641
651
  if (kind === "select") {
642
652
  return {
643
653
  rows: [
@@ -656,10 +666,23 @@ function fakeExec(sql) {
656
666
  }
657
667
  return { rows: [], columns: [], affectedRows: 0 };
658
668
  }
669
+ async function traceFakeExec(sql, params) {
670
+ const tracePath = readEnv(envName("FAKE_TRACE_FILE"));
671
+ if (tracePath === void 0) {
672
+ return;
673
+ }
674
+ const entry = { sql, paramCount: params.length };
675
+ await appendFile(tracePath, `${JSON.stringify(entry)}
676
+ `, {
677
+ encoding: "utf8",
678
+ mode: 384
679
+ });
680
+ }
659
681
  var FakeConnection = class {
660
682
  closed = false;
661
- exec(sql, _params) {
662
- return Promise.resolve(fakeExec(sql));
683
+ async exec(sql, params) {
684
+ await traceFakeExec(sql, params);
685
+ return fakeExec(sql);
663
686
  }
664
687
  setAutoCommit(_enabled) {
665
688
  return Promise.resolve();
@@ -933,7 +956,7 @@ function createDriver(name) {
933
956
  }
934
957
 
935
958
  // src/history.ts
936
- import { appendFile, mkdir as mkdir2, readdir, rm } from "fs/promises";
959
+ import { appendFile as appendFile2, mkdir as mkdir2, readdir, rm } from "fs/promises";
937
960
  import { homedir as homedir2 } from "os";
938
961
  import { join as join2 } from "path";
939
962
  var SAPTOOLS_DIR_NAME2 = ".saptools";
@@ -995,7 +1018,7 @@ async function appendSqlHistory(input, options = {}) {
995
1018
  ...input
996
1019
  };
997
1020
  await mkdir2(historyDir, { recursive: true, mode: 448 });
998
- await appendFile(sqlHistoryFilePath(now, options.saptoolsRoot), `${JSON.stringify(entry)}
1021
+ await appendFile2(sqlHistoryFilePath(now, options.saptoolsRoot), `${JSON.stringify(entry)}
999
1022
  `, {
1000
1023
  encoding: "utf8",
1001
1024
  mode: 384
@@ -1152,10 +1175,28 @@ function applyAutoLimit(sql, limit) {
1152
1175
  if (/\blimit\b/i.test(stripped) || /\btop\s+\d/i.test(stripped)) {
1153
1176
  return { sql, applied: false };
1154
1177
  }
1155
- return { sql: appendLimit(sql, limit), applied: true };
1178
+ return {
1179
+ sql: appendLimit(sql, limit + 1),
1180
+ applied: true,
1181
+ requestedLimit: limit
1182
+ };
1156
1183
  }
1157
1184
 
1158
1185
  // src/connection.ts
1186
+ function assertValidAutoLimit(value) {
1187
+ if (value !== false && (!Number.isSafeInteger(value) || value <= 0 || value >= Number.MAX_SAFE_INTEGER)) {
1188
+ throw new CfHanaError("CONFIG", "autoLimit must be a positive safe integer");
1189
+ }
1190
+ }
1191
+ function boundedRows(rows, requestedLimit) {
1192
+ if (requestedLimit === void 0) {
1193
+ return { rows, truncated: false };
1194
+ }
1195
+ return {
1196
+ rows: rows.slice(0, requestedLimit),
1197
+ truncated: rows.length > requestedLimit
1198
+ };
1199
+ }
1159
1200
  async function withTimeout(work, timeoutMs, onTimeout) {
1160
1201
  let timer;
1161
1202
  const timeout = new Promise((_resolve, reject) => {
@@ -1229,6 +1270,7 @@ var Connection = class _Connection {
1229
1270
  }
1230
1271
  const kind = classifyStatement(sql);
1231
1272
  const autoLimit = options.autoLimit ?? this.config.autoLimit;
1273
+ assertValidAutoLimit(autoLimit);
1232
1274
  const limited = kind === "select" ? applyAutoLimit(sql, autoLimit) : { sql, applied: false };
1233
1275
  const timeoutMs = options.timeoutMs ?? this.config.queryTimeoutMs;
1234
1276
  const started = Date.now();
@@ -1240,12 +1282,13 @@ var Connection = class _Connection {
1240
1282
  }
1241
1283
  );
1242
1284
  const elapsedMs = Date.now() - started;
1285
+ const selected = boundedRows(execResult.rows, limited.requestedLimit);
1243
1286
  return {
1244
- rows: execResult.rows,
1287
+ rows: selected.rows,
1245
1288
  columns: execResult.columns,
1246
- rowCount: kind === "select" ? execResult.rows.length : execResult.affectedRows,
1289
+ rowCount: kind === "select" ? selected.rows.length : execResult.affectedRows,
1247
1290
  statement: kind,
1248
- truncated: limited.applied && execResult.rows.length === autoLimit,
1291
+ truncated: selected.truncated,
1249
1292
  elapsedMs
1250
1293
  };
1251
1294
  }