@querypanel/node-sdk 1.2.10 → 1.3.0-beta.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.cjs CHANGED
@@ -38,7 +38,9 @@ __export(index_exports, {
38
38
  QueryErrorCode: () => QueryErrorCode,
39
39
  QueryPanelSdkAPI: () => QueryPanelSdkAPI,
40
40
  QueryPipelineError: () => QueryPipelineError,
41
- anonymizeResults: () => anonymizeResults
41
+ anonymizeResults: () => anonymizeResults,
42
+ mapGeneratedParams: () => mapGeneratedParams,
43
+ normalizeSqlParamsInput: () => normalizeSqlParamsInput
42
44
  });
43
45
  module.exports = __toCommonJS(index_exports);
44
46
 
@@ -497,6 +499,37 @@ function toNumber(value) {
497
499
  }
498
500
 
499
501
  // src/adapters/postgres.ts
502
+ function maxPostgresPlaceholderIndex(sql) {
503
+ let max = 0;
504
+ for (const match of sql.matchAll(/\$(\d+)\b/g)) {
505
+ const index = Number.parseInt(match[1], 10);
506
+ if (Number.isFinite(index) && index > max) {
507
+ max = index;
508
+ }
509
+ }
510
+ return max;
511
+ }
512
+ function filterParamsForPostgresSql(sql, params) {
513
+ if (!params || Object.keys(params).length === 0) {
514
+ return void 0;
515
+ }
516
+ const placeholderCount = maxPostgresPlaceholderIndex(sql);
517
+ if (placeholderCount === 0) {
518
+ return void 0;
519
+ }
520
+ const hasNumericKeys = Object.keys(params).some((key) => /^\d+$/.test(key));
521
+ if (hasNumericKeys) {
522
+ const filtered = {};
523
+ for (let index = 1; index <= placeholderCount; index += 1) {
524
+ const key = String(index);
525
+ if (key in params) {
526
+ filtered[key] = params[key];
527
+ }
528
+ }
529
+ return Object.keys(filtered).length > 0 ? filtered : void 0;
530
+ }
531
+ return params;
532
+ }
500
533
  var PostgresAdapter = class {
501
534
  constructor(clientFn, options = {}) {
502
535
  this.clientFn = clientFn;
@@ -514,9 +547,10 @@ var PostgresAdapter = class {
514
547
  if (this.allowedTables) {
515
548
  this.validateQueryTables(sql);
516
549
  }
550
+ const boundParams = filterParamsForPostgresSql(sql, params);
517
551
  let paramArray;
518
- if (params) {
519
- paramArray = this.convertNamedToPositionalParams(params);
552
+ if (boundParams) {
553
+ paramArray = this.convertNamedToPositionalParams(sql, boundParams);
520
554
  }
521
555
  const result = await this.clientFn(sql, paramArray);
522
556
  const fields = result.fields.map((f) => f.name);
@@ -546,36 +580,43 @@ var PostgresAdapter = class {
546
580
  }
547
581
  }
548
582
  /**
549
- * Convert params to positional array for PostgreSQL.
550
- * PostgreSQL expects $1, $2, $3 in SQL and an array of values [val1, val2, val3].
551
- * When the record has numeric keys ("1", "2", "3") — e.g. from mapGeneratedParams —
552
- * use only those in order so placeholder order matches SQL. Otherwise fall back to
553
- * named keys in alphabetical order for backward compatibility.
583
+ * Convert params to positional array for PostgreSQL ($1, $2, …).
584
+ * Values must align with v2 generation order via numeric keys from mapGeneratedParams.
554
585
  */
555
- convertNamedToPositionalParams(params) {
556
- const numericKeys = Object.keys(params).filter((k) => /^\d+$/.test(k)).map((k) => Number.parseInt(k, 10)).sort((a, b) => a - b);
557
- if (numericKeys.length > 0) {
558
- const positionalParams = [];
559
- for (const key of numericKeys) {
560
- let val = params[String(key)];
561
- if (typeof val === "string") {
562
- const match = val.match(/^<([a-zA-Z0-9_]+)>$/);
563
- const namedKey = match?.[1];
564
- if (namedKey && namedKey in params) {
565
- val = params[namedKey];
566
- }
586
+ convertNamedToPositionalParams(sql, params) {
587
+ const placeholderCount = maxPostgresPlaceholderIndex(sql);
588
+ if (placeholderCount === 0) {
589
+ return [];
590
+ }
591
+ const positionalParams = [];
592
+ for (let index = 1; index <= placeholderCount; index += 1) {
593
+ const key = String(index);
594
+ let val = params[key];
595
+ if (val === void 0 && placeholderCount === 1) {
596
+ const namedKeys = Object.keys(params).filter((k) => !/^\d+$/.test(k));
597
+ if (namedKeys.length === 1) {
598
+ val = params[namedKeys[0]];
567
599
  }
568
- positionalParams.push(val);
569
600
  }
570
- return positionalParams;
601
+ if (val === void 0) {
602
+ throw new Error(`Missing value for PostgreSQL parameter $${index}`);
603
+ }
604
+ if (typeof val === "string") {
605
+ const match = val.match(/^<([a-zA-Z0-9_]+)>$/);
606
+ const namedKey = match?.[1];
607
+ if (namedKey && namedKey in params) {
608
+ val = params[namedKey];
609
+ }
610
+ }
611
+ positionalParams.push(val);
571
612
  }
572
- const namedKeys = Object.keys(params).filter((k) => !/^\d+$/.test(k)).sort();
573
- return namedKeys.map((key) => params[key]);
613
+ return positionalParams;
574
614
  }
575
615
  async validate(sql, params) {
616
+ const boundParams = filterParamsForPostgresSql(sql, params);
576
617
  let paramArray;
577
- if (params) {
578
- paramArray = this.convertNamedToPositionalParams(params);
618
+ if (boundParams) {
619
+ paramArray = this.convertNamedToPositionalParams(sql, boundParams);
579
620
  }
580
621
  await this.clientFn(`EXPLAIN ${sql}`, paramArray);
581
622
  }
@@ -1218,6 +1259,45 @@ var CallbackApiClient = class {
1218
1259
  }
1219
1260
  };
1220
1261
 
1262
+ // src/core/map-generated-params.ts
1263
+ function mapGeneratedParams(params) {
1264
+ const record = {};
1265
+ params.forEach((param, index) => {
1266
+ const value = param.value;
1267
+ if (value === void 0) {
1268
+ return;
1269
+ }
1270
+ record[String(index + 1)] = value;
1271
+ const nameCandidate = typeof param.name === "string" && param.name.trim() || typeof param.placeholder === "string" && param.placeholder.trim() || typeof param.position === "number" && String(param.position) || String(index + 1);
1272
+ const key = nameCandidate.replace(/[{}:$]/g, "").trim();
1273
+ record[key] = value;
1274
+ });
1275
+ return record;
1276
+ }
1277
+ function normalizeSqlParamsInput(params) {
1278
+ if (params == null) {
1279
+ return {};
1280
+ }
1281
+ if (Array.isArray(params)) {
1282
+ if (params.length === 0) {
1283
+ return {};
1284
+ }
1285
+ const first = params[0];
1286
+ if (first && typeof first === "object" && "value" in first) {
1287
+ return mapGeneratedParams(params);
1288
+ }
1289
+ const positional = {};
1290
+ params.forEach((value, index) => {
1291
+ positional[String(index + 1)] = value;
1292
+ });
1293
+ return positional;
1294
+ }
1295
+ if (typeof params === "object") {
1296
+ return params;
1297
+ }
1298
+ return {};
1299
+ }
1300
+
1221
1301
  // src/core/query-engine.ts
1222
1302
  var QueryEngine = class {
1223
1303
  constructor() {
@@ -1288,18 +1368,7 @@ var QueryEngine = class {
1288
1368
  * - Named keys remain for tenant isolation / other lookups.
1289
1369
  */
1290
1370
  mapGeneratedParams(params) {
1291
- const record = {};
1292
- params.forEach((param, index) => {
1293
- const value = param.value;
1294
- if (value === void 0) {
1295
- return;
1296
- }
1297
- record[String(index + 1)] = value;
1298
- const nameCandidate = typeof param.name === "string" && param.name.trim() || typeof param.placeholder === "string" && param.placeholder.trim() || typeof param.position === "number" && String(param.position) || String(index + 1);
1299
- const key = nameCandidate.replace(/[{}:$]/g, "").trim();
1300
- record[key] = value;
1301
- });
1302
- return record;
1371
+ return mapGeneratedParams(params);
1303
1372
  }
1304
1373
  ensureTenantIsolation(sql, params, metadata, tenantId) {
1305
1374
  if (!metadata.tenantFieldName || metadata.enforceTenantIsolation === false) {
@@ -1319,8 +1388,10 @@ var QueryEngine = class {
1319
1388
  params[tenantField] = tenantId;
1320
1389
  tenantPredicate = `${tenantField} = @${tenantField}`;
1321
1390
  } else {
1322
- const escapedId = tenantId.replace(/'/g, "''");
1323
- tenantPredicate = `${tenantField} = '${escapedId}'`;
1391
+ const paramIndex = this.nextPostgresPlaceholderIndex(sql, params);
1392
+ params[String(paramIndex)] = tenantId;
1393
+ params[tenantField] = tenantId;
1394
+ tenantPredicate = `${tenantField} = $${paramIndex}`;
1324
1395
  }
1325
1396
  if (/\bwhere\b/i.test(sql)) {
1326
1397
  return sql.replace(
@@ -1330,6 +1401,23 @@ var QueryEngine = class {
1330
1401
  }
1331
1402
  return `${sql} WHERE ${tenantPredicate}`;
1332
1403
  }
1404
+ nextPostgresPlaceholderIndex(sql, params) {
1405
+ let max = 0;
1406
+ for (const match of sql.matchAll(/\$(\d+)\b/g)) {
1407
+ const index = Number.parseInt(match[1], 10);
1408
+ if (Number.isFinite(index) && index > max) {
1409
+ max = index;
1410
+ }
1411
+ }
1412
+ if (max > 0) {
1413
+ return max + 1;
1414
+ }
1415
+ const numericKeys = Object.keys(params).filter((key) => /^\d+$/.test(key)).map((key) => Number.parseInt(key, 10)).filter((index) => Number.isFinite(index));
1416
+ if (numericKeys.length > 0) {
1417
+ return Math.max(...numericKeys) + 1;
1418
+ }
1419
+ return 1;
1420
+ }
1333
1421
  };
1334
1422
 
1335
1423
  // src/routes/charts.ts
@@ -1864,6 +1952,7 @@ function resolveTenantId4(client, tenantId) {
1864
1952
  function buildSchemaRequest(databaseName, adapter, introspection, metadata) {
1865
1953
  const dialect = adapter.getDialect();
1866
1954
  const tables = introspection.tables.map((table) => ({
1955
+ schema_name: table.schema,
1867
1956
  table_name: table.name,
1868
1957
  description: table.comment ?? `Table ${table.name}`,
1869
1958
  columns: table.columns.map((column) => ({
@@ -3540,6 +3629,8 @@ var QueryPanelSdkAPI = class _QueryPanelSdkAPI {
3540
3629
  QueryErrorCode,
3541
3630
  QueryPanelSdkAPI,
3542
3631
  QueryPipelineError,
3543
- anonymizeResults
3632
+ anonymizeResults,
3633
+ mapGeneratedParams,
3634
+ normalizeSqlParamsInput
3544
3635
  });
3545
3636
  //# sourceMappingURL=index.cjs.map