@querypanel/node-sdk 1.3.1 → 1.3.5

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.cts CHANGED
@@ -37,7 +37,7 @@ interface IntrospectOptions {
37
37
  tables?: string[];
38
38
  }
39
39
 
40
- type DatabaseDialect = "bigquery" | "clickhouse" | "postgres" | "mysql";
40
+ type DatabaseDialect = "bigquery" | "clickhouse" | "postgres" | "redshift" | "mysql";
41
41
  interface DatabaseExecutionResult {
42
42
  fields: string[];
43
43
  rows: Array<Record<string, unknown>>;
@@ -192,13 +192,19 @@ interface PostgresQueryResult {
192
192
  }>;
193
193
  }
194
194
  type PostgresClientFn = (sql: string, params?: unknown[]) => Promise<PostgresQueryResult>;
195
+ type PostgresWireDialect = "postgres" | "redshift";
195
196
  interface PostgresAdapterOptions {
196
197
  /** Logical database name used in introspection metadata. */
197
198
  database?: string;
198
199
  /** Schema to assume when a table is provided without qualification. */
199
200
  defaultSchema?: string;
200
- /** Optional database kind label. Defaults to "postgres". */
201
+ /** Optional database kind label. Defaults to the dialect. */
201
202
  kind?: SchemaIntrospection["db"]["kind"];
203
+ /**
204
+ * Wire-compatible engine behind the client. "redshift" uses Redshift's
205
+ * svv_* catalog views for introspection. Defaults to "postgres".
206
+ */
207
+ dialect?: PostgresWireDialect;
202
208
  /**
203
209
  * Optional allow-list of table names (schema-qualified or bare).
204
210
  * When specified, introspection and queries are restricted to these tables only.
@@ -215,6 +221,7 @@ declare class PostgresAdapter implements DatabaseAdapter {
215
221
  private readonly databaseName;
216
222
  private readonly defaultSchema;
217
223
  private readonly kind;
224
+ private readonly dialect;
218
225
  private readonly allowedTables?;
219
226
  constructor(clientFn: PostgresClientFn, options?: PostgresAdapterOptions);
220
227
  execute(sql: string, params?: Record<string, string | number | boolean | string[] | number[]>): Promise<DatabaseExecutionResult>;
@@ -225,7 +232,7 @@ declare class PostgresAdapter implements DatabaseAdapter {
225
232
  */
226
233
  private convertNamedToPositionalParams;
227
234
  validate(sql: string, params?: Record<string, string | number | boolean | string[] | number[]>): Promise<void>;
228
- getDialect(): "postgres";
235
+ getDialect(): PostgresWireDialect;
229
236
  /**
230
237
  * Simplified introspection: only collect table/column metadata for IngestRequest
231
238
  * No indexes, constraints, or statistics
@@ -990,6 +997,13 @@ interface ChartModifyOptions {
990
997
  * Omit this field; chart modifications always use v2.
991
998
  */
992
999
  pipeline?: "v2";
1000
+ /**
1001
+ * Fast path for structured controls (pinned charts): date-only changes
1002
+ * substitute params or call `/v2/rewrite-datefilter` instead of `/v2/query`,
1003
+ * and chart generation is skipped when the caller keeps its own encoding
1004
+ * (`chart.vizSpec` / `vegaLiteSpec` are then omitted). Default: false.
1005
+ */
1006
+ lightweight?: boolean;
993
1007
  /**
994
1008
  * QueryPanel session ID for context-aware follow-ups.
995
1009
  * Pass the querypanelSessionId from a previous ask() response
@@ -1248,6 +1262,18 @@ declare class QueryPanelSdkAPI {
1248
1262
  tenantFieldType?: string;
1249
1263
  enforceTenantIsolation?: boolean;
1250
1264
  }): void;
1265
+ /**
1266
+ * Attach an Amazon Redshift database. Redshift speaks the Postgres wire
1267
+ * protocol, so `clientFn` can wrap a `pg` client; introspection uses
1268
+ * Redshift's svv_* catalog views and SQL is generated for Redshift.
1269
+ */
1270
+ attachRedshift(name: string, clientFn: PostgresClientFn, options?: Omit<PostgresAdapterOptions, "dialect"> & {
1271
+ description?: string;
1272
+ tags?: string[];
1273
+ tenantFieldName?: string;
1274
+ tenantFieldType?: string;
1275
+ enforceTenantIsolation?: boolean;
1276
+ }): void;
1251
1277
  attachBigQuery(name: string, clientFn: BigQueryClientFn, options: BigQueryAdapterOptions & {
1252
1278
  description?: string;
1253
1279
  tags?: string[];
@@ -1986,4 +2012,4 @@ declare class QueryPanelSdkAPI {
1986
2012
  }, signal?: AbortSignal): Promise<SdkDashboard[]>;
1987
2013
  }
1988
2014
 
1989
- export { ALL_VIZ_CHART_TYPES, type ActiveChartBulkGetResponse, type ActiveChartCreateInput, type ActiveChartListOptions, type ActiveChartUpdateInput, type AggregateOp, type AskOptions, type AskResponse, type AxisField, type AxisFieldInput, BigQueryAdapter, type BigQueryAdapterOptions, type BigQueryClientFn, type BigQueryQueryRequest, type BigQueryQueryResult, CallbackApiClient, type ChartBulkGetResponse, type ChartCreateInput, type ChartEncoding, type ChartEnvelope, type ChartListAllOptions, type ChartListOptions, type ChartModifyInput, type ChartModifyOptions, type ChartModifyResponse, type ChartSpec, type ChartType, type ChartUpdateInput, ClickHouseAdapter, type ClickHouseAdapterOptions, type ClickHouseClientFn, type ContextDocument, type DashboardCreateInput, type DashboardForkInput, type DashboardForkUpdateInput, type DashboardListOptions, type DashboardUpdateInput, type DatabaseAdapter, type DatabaseDialect, type DateRangeInput, type EncodingHints, type FieldRef, type FieldRefInput, type FieldType, type IQueryPanelApi, type IngestResponse, type IntentResult, type MetricEncoding, type MetricField, type MetricSpec, type PaginatedResponse$1 as PaginatedResponse, type PaginationInfo$1 as PaginationInfo, type PaginationQuery$1 as PaginationQuery, type ParamRecord, type ParamValue, type PipelineTrace, PostgresAdapter, type PostgresAdapterOptions, type PostgresClientFn, QueryErrorCode, QueryErrorCode as QueryErrorCodeType, QueryPanelSdkAPI, type QueryPanelSdkAPIOptions, QueryPipelineError, type RequestHandler, type RequestHandlerOptions, type RequestHandlerResult, type SchemaIntrospection, type SchemaSyncOptions, type SdkActiveChart, type SdkChart, type SdkDashboard, type SdkSession, type SdkSessionTurn, type SessionGetOptions, type SessionListOptions, type SessionUpdateInput, type SqlModifications, type StackingMode, type TableColumn, type TableEncoding, type TableSpec, type TimeUnit, type ValueFormat, type VizModifications, type VizSpec, type VizSpecGenerateInput, type VizSpecGenerateOptions, type VizSpecGeneratorInput, type VizSpecKind, type VizSpecResponse, type VizSpecResult, anonymizeResults, mapGeneratedParams, normalizeSqlParamsInput, resolveQueryPipeline };
2015
+ export { ALL_VIZ_CHART_TYPES, type ActiveChartBulkGetResponse, type ActiveChartCreateInput, type ActiveChartListOptions, type ActiveChartUpdateInput, type AggregateOp, type AskOptions, type AskResponse, type AxisField, type AxisFieldInput, BigQueryAdapter, type BigQueryAdapterOptions, type BigQueryClientFn, type BigQueryQueryRequest, type BigQueryQueryResult, CallbackApiClient, type ChartBulkGetResponse, type ChartCreateInput, type ChartEncoding, type ChartEnvelope, type ChartListAllOptions, type ChartListOptions, type ChartModifyInput, type ChartModifyOptions, type ChartModifyResponse, type ChartSpec, type ChartType, type ChartUpdateInput, ClickHouseAdapter, type ClickHouseAdapterOptions, type ClickHouseClientFn, type ContextDocument, type DashboardCreateInput, type DashboardForkInput, type DashboardForkUpdateInput, type DashboardListOptions, type DashboardUpdateInput, type DatabaseAdapter, type DatabaseDialect, type DateRangeInput, type EncodingHints, type FieldRef, type FieldRefInput, type FieldType, type IQueryPanelApi, type IngestResponse, type IntentResult, type MetricEncoding, type MetricField, type MetricSpec, type PaginatedResponse$1 as PaginatedResponse, type PaginationInfo$1 as PaginationInfo, type PaginationQuery$1 as PaginationQuery, type ParamRecord, type ParamValue, type PipelineTrace, PostgresAdapter, type PostgresAdapterOptions, type PostgresClientFn, type PostgresWireDialect, QueryErrorCode, QueryErrorCode as QueryErrorCodeType, QueryPanelSdkAPI, type QueryPanelSdkAPIOptions, QueryPipelineError, type RequestHandler, type RequestHandlerOptions, type RequestHandlerResult, type SchemaIntrospection, type SchemaSyncOptions, type SdkActiveChart, type SdkChart, type SdkDashboard, type SdkSession, type SdkSessionTurn, type SessionGetOptions, type SessionListOptions, type SessionUpdateInput, type SqlModifications, type StackingMode, type TableColumn, type TableEncoding, type TableSpec, type TimeUnit, type ValueFormat, type VizModifications, type VizSpec, type VizSpecGenerateInput, type VizSpecGenerateOptions, type VizSpecGeneratorInput, type VizSpecKind, type VizSpecResponse, type VizSpecResult, anonymizeResults, mapGeneratedParams, normalizeSqlParamsInput, resolveQueryPipeline };
package/dist/index.d.ts CHANGED
@@ -37,7 +37,7 @@ interface IntrospectOptions {
37
37
  tables?: string[];
38
38
  }
39
39
 
40
- type DatabaseDialect = "bigquery" | "clickhouse" | "postgres" | "mysql";
40
+ type DatabaseDialect = "bigquery" | "clickhouse" | "postgres" | "redshift" | "mysql";
41
41
  interface DatabaseExecutionResult {
42
42
  fields: string[];
43
43
  rows: Array<Record<string, unknown>>;
@@ -192,13 +192,19 @@ interface PostgresQueryResult {
192
192
  }>;
193
193
  }
194
194
  type PostgresClientFn = (sql: string, params?: unknown[]) => Promise<PostgresQueryResult>;
195
+ type PostgresWireDialect = "postgres" | "redshift";
195
196
  interface PostgresAdapterOptions {
196
197
  /** Logical database name used in introspection metadata. */
197
198
  database?: string;
198
199
  /** Schema to assume when a table is provided without qualification. */
199
200
  defaultSchema?: string;
200
- /** Optional database kind label. Defaults to "postgres". */
201
+ /** Optional database kind label. Defaults to the dialect. */
201
202
  kind?: SchemaIntrospection["db"]["kind"];
203
+ /**
204
+ * Wire-compatible engine behind the client. "redshift" uses Redshift's
205
+ * svv_* catalog views for introspection. Defaults to "postgres".
206
+ */
207
+ dialect?: PostgresWireDialect;
202
208
  /**
203
209
  * Optional allow-list of table names (schema-qualified or bare).
204
210
  * When specified, introspection and queries are restricted to these tables only.
@@ -215,6 +221,7 @@ declare class PostgresAdapter implements DatabaseAdapter {
215
221
  private readonly databaseName;
216
222
  private readonly defaultSchema;
217
223
  private readonly kind;
224
+ private readonly dialect;
218
225
  private readonly allowedTables?;
219
226
  constructor(clientFn: PostgresClientFn, options?: PostgresAdapterOptions);
220
227
  execute(sql: string, params?: Record<string, string | number | boolean | string[] | number[]>): Promise<DatabaseExecutionResult>;
@@ -225,7 +232,7 @@ declare class PostgresAdapter implements DatabaseAdapter {
225
232
  */
226
233
  private convertNamedToPositionalParams;
227
234
  validate(sql: string, params?: Record<string, string | number | boolean | string[] | number[]>): Promise<void>;
228
- getDialect(): "postgres";
235
+ getDialect(): PostgresWireDialect;
229
236
  /**
230
237
  * Simplified introspection: only collect table/column metadata for IngestRequest
231
238
  * No indexes, constraints, or statistics
@@ -990,6 +997,13 @@ interface ChartModifyOptions {
990
997
  * Omit this field; chart modifications always use v2.
991
998
  */
992
999
  pipeline?: "v2";
1000
+ /**
1001
+ * Fast path for structured controls (pinned charts): date-only changes
1002
+ * substitute params or call `/v2/rewrite-datefilter` instead of `/v2/query`,
1003
+ * and chart generation is skipped when the caller keeps its own encoding
1004
+ * (`chart.vizSpec` / `vegaLiteSpec` are then omitted). Default: false.
1005
+ */
1006
+ lightweight?: boolean;
993
1007
  /**
994
1008
  * QueryPanel session ID for context-aware follow-ups.
995
1009
  * Pass the querypanelSessionId from a previous ask() response
@@ -1248,6 +1262,18 @@ declare class QueryPanelSdkAPI {
1248
1262
  tenantFieldType?: string;
1249
1263
  enforceTenantIsolation?: boolean;
1250
1264
  }): void;
1265
+ /**
1266
+ * Attach an Amazon Redshift database. Redshift speaks the Postgres wire
1267
+ * protocol, so `clientFn` can wrap a `pg` client; introspection uses
1268
+ * Redshift's svv_* catalog views and SQL is generated for Redshift.
1269
+ */
1270
+ attachRedshift(name: string, clientFn: PostgresClientFn, options?: Omit<PostgresAdapterOptions, "dialect"> & {
1271
+ description?: string;
1272
+ tags?: string[];
1273
+ tenantFieldName?: string;
1274
+ tenantFieldType?: string;
1275
+ enforceTenantIsolation?: boolean;
1276
+ }): void;
1251
1277
  attachBigQuery(name: string, clientFn: BigQueryClientFn, options: BigQueryAdapterOptions & {
1252
1278
  description?: string;
1253
1279
  tags?: string[];
@@ -1986,4 +2012,4 @@ declare class QueryPanelSdkAPI {
1986
2012
  }, signal?: AbortSignal): Promise<SdkDashboard[]>;
1987
2013
  }
1988
2014
 
1989
- export { ALL_VIZ_CHART_TYPES, type ActiveChartBulkGetResponse, type ActiveChartCreateInput, type ActiveChartListOptions, type ActiveChartUpdateInput, type AggregateOp, type AskOptions, type AskResponse, type AxisField, type AxisFieldInput, BigQueryAdapter, type BigQueryAdapterOptions, type BigQueryClientFn, type BigQueryQueryRequest, type BigQueryQueryResult, CallbackApiClient, type ChartBulkGetResponse, type ChartCreateInput, type ChartEncoding, type ChartEnvelope, type ChartListAllOptions, type ChartListOptions, type ChartModifyInput, type ChartModifyOptions, type ChartModifyResponse, type ChartSpec, type ChartType, type ChartUpdateInput, ClickHouseAdapter, type ClickHouseAdapterOptions, type ClickHouseClientFn, type ContextDocument, type DashboardCreateInput, type DashboardForkInput, type DashboardForkUpdateInput, type DashboardListOptions, type DashboardUpdateInput, type DatabaseAdapter, type DatabaseDialect, type DateRangeInput, type EncodingHints, type FieldRef, type FieldRefInput, type FieldType, type IQueryPanelApi, type IngestResponse, type IntentResult, type MetricEncoding, type MetricField, type MetricSpec, type PaginatedResponse$1 as PaginatedResponse, type PaginationInfo$1 as PaginationInfo, type PaginationQuery$1 as PaginationQuery, type ParamRecord, type ParamValue, type PipelineTrace, PostgresAdapter, type PostgresAdapterOptions, type PostgresClientFn, QueryErrorCode, QueryErrorCode as QueryErrorCodeType, QueryPanelSdkAPI, type QueryPanelSdkAPIOptions, QueryPipelineError, type RequestHandler, type RequestHandlerOptions, type RequestHandlerResult, type SchemaIntrospection, type SchemaSyncOptions, type SdkActiveChart, type SdkChart, type SdkDashboard, type SdkSession, type SdkSessionTurn, type SessionGetOptions, type SessionListOptions, type SessionUpdateInput, type SqlModifications, type StackingMode, type TableColumn, type TableEncoding, type TableSpec, type TimeUnit, type ValueFormat, type VizModifications, type VizSpec, type VizSpecGenerateInput, type VizSpecGenerateOptions, type VizSpecGeneratorInput, type VizSpecKind, type VizSpecResponse, type VizSpecResult, anonymizeResults, mapGeneratedParams, normalizeSqlParamsInput, resolveQueryPipeline };
2015
+ export { ALL_VIZ_CHART_TYPES, type ActiveChartBulkGetResponse, type ActiveChartCreateInput, type ActiveChartListOptions, type ActiveChartUpdateInput, type AggregateOp, type AskOptions, type AskResponse, type AxisField, type AxisFieldInput, BigQueryAdapter, type BigQueryAdapterOptions, type BigQueryClientFn, type BigQueryQueryRequest, type BigQueryQueryResult, CallbackApiClient, type ChartBulkGetResponse, type ChartCreateInput, type ChartEncoding, type ChartEnvelope, type ChartListAllOptions, type ChartListOptions, type ChartModifyInput, type ChartModifyOptions, type ChartModifyResponse, type ChartSpec, type ChartType, type ChartUpdateInput, ClickHouseAdapter, type ClickHouseAdapterOptions, type ClickHouseClientFn, type ContextDocument, type DashboardCreateInput, type DashboardForkInput, type DashboardForkUpdateInput, type DashboardListOptions, type DashboardUpdateInput, type DatabaseAdapter, type DatabaseDialect, type DateRangeInput, type EncodingHints, type FieldRef, type FieldRefInput, type FieldType, type IQueryPanelApi, type IngestResponse, type IntentResult, type MetricEncoding, type MetricField, type MetricSpec, type PaginatedResponse$1 as PaginatedResponse, type PaginationInfo$1 as PaginationInfo, type PaginationQuery$1 as PaginationQuery, type ParamRecord, type ParamValue, type PipelineTrace, PostgresAdapter, type PostgresAdapterOptions, type PostgresClientFn, type PostgresWireDialect, QueryErrorCode, QueryErrorCode as QueryErrorCodeType, QueryPanelSdkAPI, type QueryPanelSdkAPIOptions, QueryPipelineError, type RequestHandler, type RequestHandlerOptions, type RequestHandlerResult, type SchemaIntrospection, type SchemaSyncOptions, type SdkActiveChart, type SdkChart, type SdkDashboard, type SdkSession, type SdkSessionTurn, type SessionGetOptions, type SessionListOptions, type SessionUpdateInput, type SqlModifications, type StackingMode, type TableColumn, type TableEncoding, type TableSpec, type TimeUnit, type ValueFormat, type VizModifications, type VizSpec, type VizSpecGenerateInput, type VizSpecGenerateOptions, type VizSpecGeneratorInput, type VizSpecKind, type VizSpecResponse, type VizSpecResult, anonymizeResults, mapGeneratedParams, normalizeSqlParamsInput, resolveQueryPipeline };
package/dist/index.js CHANGED
@@ -501,7 +501,8 @@ var PostgresAdapter = class {
501
501
  this.clientFn = clientFn;
502
502
  this.databaseName = options.database ?? "postgres";
503
503
  this.defaultSchema = options.defaultSchema ?? "public";
504
- this.kind = options.kind ?? "postgres";
504
+ this.dialect = options.dialect ?? "postgres";
505
+ this.kind = options.kind ?? this.dialect;
505
506
  if (options.allowedTables) {
506
507
  this.allowedTables = normalizeTableFilter3(
507
508
  options.allowedTables,
@@ -513,6 +514,7 @@ var PostgresAdapter = class {
513
514
  databaseName;
514
515
  defaultSchema;
515
516
  kind;
517
+ dialect;
516
518
  allowedTables;
517
519
  async execute(sql, params) {
518
520
  if (this.allowedTables) {
@@ -592,7 +594,7 @@ var PostgresAdapter = class {
592
594
  await this.clientFn(`EXPLAIN ${sql}`, paramArray);
593
595
  }
594
596
  getDialect() {
595
- return "postgres";
597
+ return this.dialect;
596
598
  }
597
599
  /**
598
600
  * Simplified introspection: only collect table/column metadata for IngestRequest
@@ -601,12 +603,13 @@ var PostgresAdapter = class {
601
603
  async introspect(options) {
602
604
  const tablesToIntrospect = options?.tables ? normalizeTableFilter3(options.tables, this.defaultSchema) : this.allowedTables;
603
605
  const normalizedTables = tablesToIntrospect ?? [];
606
+ const isRedshift = this.dialect === "redshift";
604
607
  const tablesResult = await this.clientFn(
605
- buildTablesQuery2(normalizedTables)
608
+ isRedshift ? buildRedshiftTablesQuery(normalizedTables) : buildTablesQuery2(normalizedTables)
606
609
  );
607
610
  const tableRows = tablesResult.rows;
608
611
  const columnsResult = await this.clientFn(
609
- buildColumnsQuery2(normalizedTables)
612
+ isRedshift ? buildRedshiftColumnsQuery(normalizedTables) : buildColumnsQuery2(normalizedTables)
610
613
  );
611
614
  const columnRows = columnsResult.rows;
612
615
  const tablesByKey = /* @__PURE__ */ new Map();
@@ -720,10 +723,11 @@ function buildColumnsQuery2(tables) {
720
723
  AND kcu.column_name = cols.column_name
721
724
  ) AS is_primary_key
722
725
  FROM information_schema.columns cols
726
+ LEFT JOIN pg_catalog.pg_namespace n ON n.nspname = cols.table_schema
723
727
  LEFT JOIN pg_catalog.pg_class c
724
728
  ON c.relname = cols.table_name
729
+ AND c.relnamespace = n.oid
725
730
  AND c.relkind IN ('r', 'v', 'm')
726
- LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
727
731
  LEFT JOIN pg_catalog.pg_attribute attr
728
732
  ON attr.attrelid = c.oid
729
733
  AND attr.attname = cols.column_name
@@ -733,6 +737,38 @@ function buildColumnsQuery2(tables) {
733
737
  ${filter}
734
738
  ORDER BY cols.table_schema, cols.table_name, cols.ordinal_position;`;
735
739
  }
740
+ var REDSHIFT_EXCLUDED_SCHEMAS = "('pg_catalog', 'information_schema', 'pg_internal', 'pg_automv')";
741
+ function buildRedshiftTablesQuery(tables) {
742
+ const filter = buildFilterClause(tables, "table_schema", "table_name");
743
+ return `SELECT
744
+ table_name,
745
+ table_schema AS schema_name,
746
+ table_type,
747
+ remarks AS comment
748
+ FROM svv_tables
749
+ WHERE table_catalog = current_database()
750
+ AND table_schema NOT IN ${REDSHIFT_EXCLUDED_SCHEMAS}
751
+ AND table_schema NOT LIKE 'pg_temp%'
752
+ ${filter}
753
+ ORDER BY table_schema, table_name;`;
754
+ }
755
+ function buildRedshiftColumnsQuery(tables) {
756
+ const filter = buildFilterClause(tables, "table_schema", "table_name");
757
+ return `SELECT
758
+ table_name,
759
+ table_schema,
760
+ column_name,
761
+ data_type,
762
+ NULL AS udt_name,
763
+ remarks AS description,
764
+ FALSE AS is_primary_key
765
+ FROM svv_columns
766
+ WHERE table_catalog = current_database()
767
+ AND table_schema NOT IN ${REDSHIFT_EXCLUDED_SCHEMAS}
768
+ AND table_schema NOT LIKE 'pg_temp%'
769
+ ${filter}
770
+ ORDER BY table_schema, table_name, ordinal_position;`;
771
+ }
736
772
  function buildFilterClause(tables, schemaExpr, tableExpr) {
737
773
  if (!tables.length) return "";
738
774
  const clauses = tables.map(({ schema, table }) => {
@@ -2245,6 +2281,7 @@ function buildModifiedQuestion(originalQuestion, modifications, hasSessionContex
2245
2281
  }
2246
2282
  return `${originalQuestion} (${hints.join(", ")})`;
2247
2283
  }
2284
+ var REWRITE_DATEFILTER_ENDPOINT = "/v2/rewrite-datefilter";
2248
2285
  var START_PARAM_KEY_REGEX = /(^|_)(start|from)(_|$)/i;
2249
2286
  var END_PARAM_KEY_REGEX = /(^|_)(end|to)(_|$)/i;
2250
2287
  var ISO_DATETIME_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z?$/;
@@ -2281,31 +2318,118 @@ function normalizeGeneratedParamKey(param, index) {
2281
2318
  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);
2282
2319
  return nameCandidate.replace(/[{}]/g, "").replace(/(.+):.*$/, "$1").replace(/^[:$]/, "").trim();
2283
2320
  }
2284
- function applyDateRangeOverrides(dateRange, params, paramMetadata) {
2321
+ function collectParamKeys(params, paramMetadata) {
2322
+ const keys = new Set(Object.keys(params));
2323
+ for (let i = 0; i < paramMetadata.length; i++) {
2324
+ const param = paramMetadata[i];
2325
+ if (!param) continue;
2326
+ keys.add(normalizeGeneratedParamKey(param, i));
2327
+ }
2328
+ return [...keys];
2329
+ }
2330
+ function placeholderKey(token) {
2331
+ if (token.startsWith("$") || token.startsWith("@")) return token.slice(1);
2332
+ return token.slice(1, -1).replace(/:.+$/, "").trim();
2333
+ }
2334
+ function isDateLike(value) {
2335
+ return typeof value === "string" && /^\d{4}-\d{2}-\d{2}/.test(value.trim());
2336
+ }
2337
+ function dateBoundKeysFromSql(sql) {
2338
+ const start = /* @__PURE__ */ new Set();
2339
+ const end = /* @__PURE__ */ new Set();
2340
+ const comparison = /(>=|<=|>|<)\s*(\$\d+|\{[^}]+\}|@[A-Za-z_][\w]*)/g;
2341
+ const between = /BETWEEN\s+(\$\d+|\{[^}]+\}|@[A-Za-z_][\w]*)\s+AND\s+(\$\d+|\{[^}]+\}|@[A-Za-z_][\w]*)/gi;
2342
+ for (const match of sql.matchAll(comparison)) {
2343
+ const key = placeholderKey(match[2] ?? "");
2344
+ if (!key) continue;
2345
+ if (match[1] === ">=" || match[1] === ">") start.add(key);
2346
+ else end.add(key);
2347
+ }
2348
+ for (const match of sql.matchAll(between)) {
2349
+ const startKey = placeholderKey(match[1] ?? "");
2350
+ const endKey = placeholderKey(match[2] ?? "");
2351
+ if (startKey) start.add(startKey);
2352
+ if (endKey) end.add(endKey);
2353
+ }
2354
+ return { start, end };
2355
+ }
2356
+ function paramValueForKey(key, params, paramMetadata) {
2357
+ if (key in params) return params[key];
2358
+ for (let i = 0; i < paramMetadata.length; i++) {
2359
+ const param = paramMetadata[i];
2360
+ if (!param) continue;
2361
+ if (normalizeGeneratedParamKey(param, i) === key) return param.value;
2362
+ }
2363
+ return void 0;
2364
+ }
2365
+ function dateBoundKeys(sql, params, paramMetadata, boundary) {
2366
+ const fromSql = dateBoundKeysFromSql(sql)[boundary];
2367
+ const keys = [];
2368
+ for (const key of collectParamKeys(params, paramMetadata)) {
2369
+ const named = keyLooksLikeDateBoundary(key, boundary);
2370
+ if (!named && !fromSql.has(key)) continue;
2371
+ if (!isDateLike(paramValueForKey(key, params, paramMetadata))) continue;
2372
+ keys.push(key);
2373
+ }
2374
+ return keys;
2375
+ }
2376
+ function canSubstituteDateRangeParams(dateRange, sql, params, paramMetadata = []) {
2377
+ if (!dateRange) return false;
2378
+ const from = normalizeDateInput(dateRange.from);
2379
+ const to = normalizeDateInput(dateRange.to);
2380
+ if (!from && !to) return false;
2381
+ if (from && dateBoundKeys(sql, params, paramMetadata, "start").length === 0) {
2382
+ return false;
2383
+ }
2384
+ if (to && dateBoundKeys(sql, params, paramMetadata, "end").length === 0) {
2385
+ return false;
2386
+ }
2387
+ return true;
2388
+ }
2389
+ function isDateRangeOnlySqlModification(modifications) {
2390
+ if (!modifications?.dateRange) return false;
2391
+ if (modifications.customSql) return false;
2392
+ if (modifications.timeGranularity) return false;
2393
+ if (typeof modifications.additionalInstructions === "string" && modifications.additionalInstructions.trim().length > 0) {
2394
+ return false;
2395
+ }
2396
+ return true;
2397
+ }
2398
+ function applyDateRangeOverrides(dateRange, sql, params, paramMetadata) {
2285
2399
  if (!dateRange) return;
2286
2400
  const from = normalizeDateInput(dateRange.from);
2287
2401
  const to = normalizeDateInput(dateRange.to);
2288
2402
  if (!from && !to) return;
2403
+ const startKeys = new Set(
2404
+ from ? dateBoundKeys(sql, params, paramMetadata, "start") : []
2405
+ );
2406
+ const endKeys = new Set(
2407
+ to ? dateBoundKeys(sql, params, paramMetadata, "end") : []
2408
+ );
2289
2409
  for (const [key, value] of Object.entries(params)) {
2290
- if (from && keyLooksLikeDateBoundary(key, "start")) {
2291
- params[key] = formatDateOverride(from, "start", value);
2410
+ if (startKeys.has(key)) {
2411
+ params[key] = formatDateOverride(from ?? "", "start", value);
2292
2412
  }
2293
- if (to && keyLooksLikeDateBoundary(key, "end")) {
2294
- params[key] = formatDateOverride(to, "end", value);
2413
+ if (endKeys.has(key)) {
2414
+ params[key] = formatDateOverride(to ?? "", "end", value);
2295
2415
  }
2296
2416
  }
2297
2417
  for (let i = 0; i < paramMetadata.length; i++) {
2298
2418
  const param = paramMetadata[i];
2299
2419
  if (!param) continue;
2300
2420
  const key = normalizeGeneratedParamKey(param, i);
2301
- if (from && keyLooksLikeDateBoundary(key, "start")) {
2302
- param.value = formatDateOverride(from, "start", param.value);
2421
+ if (startKeys.has(key)) {
2422
+ param.value = formatDateOverride(from ?? "", "start", param.value);
2303
2423
  }
2304
- if (to && keyLooksLikeDateBoundary(key, "end")) {
2305
- param.value = formatDateOverride(to, "end", param.value);
2424
+ if (endKeys.has(key)) {
2425
+ param.value = formatDateOverride(to ?? "", "end", param.value);
2306
2426
  }
2307
2427
  }
2308
2428
  }
2429
+ function buildPreviousParams(params, paramMetadata) {
2430
+ if (paramMetadata.length > 0) return paramMetadata;
2431
+ return Object.entries(params).map(([name, value]) => ({ name, value }));
2432
+ }
2309
2433
  function buildVizHints(modifications) {
2310
2434
  const hints = {};
2311
2435
  if (modifications.kind) {
@@ -2356,6 +2480,9 @@ async function modifyChart(client, queryEngine, input, options, signal) {
2356
2480
  const hasSqlMods = !!input.sqlModifications;
2357
2481
  const hasVizMods = !!input.vizModifications;
2358
2482
  const hasCustomSql = !!input.sqlModifications?.customSql;
2483
+ const lightweight = options?.lightweight === true;
2484
+ const dateOnly = lightweight && isDateRangeOnlySqlModification(input.sqlModifications);
2485
+ const skipChartLlm = lightweight && !hasCustomSql && (dateOnly || hasVizMods && !hasSqlMods);
2359
2486
  resolveQueryPipeline(options?.pipeline);
2360
2487
  const queryEndpoint = "/v2/query";
2361
2488
  let currentSql = input.sql;
@@ -2409,6 +2536,20 @@ async function modifyChart(client, queryEngine, input, options, signal) {
2409
2536
  paramMetadata = [];
2410
2537
  queryId = void 0;
2411
2538
  sqlChanged = true;
2539
+ } else if (dateOnly && canSubstituteDateRangeParams(
2540
+ input.sqlModifications?.dateRange,
2541
+ finalSql,
2542
+ finalParams,
2543
+ paramMetadata
2544
+ )) {
2545
+ finalParams = { ...finalParams };
2546
+ applyDateRangeOverrides(
2547
+ input.sqlModifications?.dateRange,
2548
+ finalSql,
2549
+ finalParams,
2550
+ paramMetadata
2551
+ );
2552
+ sqlChanged = false;
2412
2553
  } else if (hasSqlMods && !hasCustomSql) {
2413
2554
  const modifiedQuestion = buildModifiedQuestion(
2414
2555
  input.question,
@@ -2416,18 +2557,36 @@ async function modifyChart(client, queryEngine, input, options, signal) {
2416
2557
  hasQuerypanelSessionContext
2417
2558
  );
2418
2559
  finalQuestion = modifiedQuestion;
2419
- const queryResponse = await client.post(
2560
+ const sharedBody = {
2561
+ session_id: querypanelSessionId,
2562
+ previous_sql: currentSql,
2563
+ ...tenantSettings ? { tenant_settings: tenantSettings } : {},
2564
+ ...databaseName ? { database: databaseName } : {},
2565
+ ...metadata?.dialect ? { dialect: metadata.dialect } : {},
2566
+ debug: options?.debug ?? false
2567
+ };
2568
+ const [endpoint, body] = dateOnly ? [
2569
+ REWRITE_DATEFILTER_ENDPOINT,
2570
+ {
2571
+ ...sharedBody,
2572
+ question: input.question,
2573
+ previous_params: buildPreviousParams(finalParams, paramMetadata),
2574
+ date_range: {
2575
+ from: normalizeDateInput(input.sqlModifications?.dateRange?.from),
2576
+ to: normalizeDateInput(input.sqlModifications?.dateRange?.to)
2577
+ }
2578
+ }
2579
+ ] : [
2420
2580
  queryEndpoint,
2421
2581
  {
2582
+ ...sharedBody,
2422
2583
  question: modifiedQuestion,
2423
- session_id: querypanelSessionId,
2424
- previous_sql: currentSql,
2425
- ...options?.maxRetry ? { max_retry: options.maxRetry } : {},
2426
- ...tenantSettings ? { tenant_settings: tenantSettings } : {},
2427
- ...databaseName ? { database: databaseName } : {},
2428
- ...metadata?.dialect ? { dialect: metadata.dialect } : {},
2429
- debug: options?.debug ?? false
2430
- },
2584
+ ...options?.maxRetry ? { max_retry: options.maxRetry } : {}
2585
+ }
2586
+ ];
2587
+ const queryResponse = await client.post(
2588
+ endpoint,
2589
+ body,
2431
2590
  tenantId,
2432
2591
  options?.userId,
2433
2592
  options?.scopes,
@@ -2439,6 +2598,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
2439
2598
  finalParams = queryEngine.mapGeneratedParams(paramMetadata);
2440
2599
  applyDateRangeOverrides(
2441
2600
  input.sqlModifications?.dateRange,
2601
+ finalSql,
2442
2602
  finalParams,
2443
2603
  paramMetadata
2444
2604
  );
@@ -2459,7 +2619,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
2459
2619
  };
2460
2620
  const vizHints = hasVizMods ? buildVizHints(input.vizModifications) : {};
2461
2621
  const vizHintsForChart = chartType === "vizspec" ? vizHints : stripVizSpecOnlyHints(vizHints);
2462
- if (chartType === "vizspec") {
2622
+ if (!skipChartLlm && chartType === "vizspec") {
2463
2623
  const vizspecResponse = await client.post(
2464
2624
  "/vizspec",
2465
2625
  {
@@ -2486,7 +2646,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
2486
2646
  specType: "vizspec",
2487
2647
  notes: rows.length === 0 ? vizspecResponse.notes ?? "Query returned no rows." : vizspecResponse.notes
2488
2648
  };
2489
- } else {
2649
+ } else if (!skipChartLlm) {
2490
2650
  const chartResponse = await client.post(
2491
2651
  "/chart",
2492
2652
  {
@@ -2742,7 +2902,7 @@ var QueryPanelSdkAPI = class _QueryPanelSdkAPI {
2742
2902
  const adapter = new PostgresAdapter(clientFn, options);
2743
2903
  const metadata = {
2744
2904
  name,
2745
- dialect: "postgres",
2905
+ dialect: adapter.getDialect(),
2746
2906
  description: options?.description,
2747
2907
  tags: options?.tags,
2748
2908
  tenantFieldName: options?.tenantFieldName,
@@ -2754,6 +2914,14 @@ var QueryPanelSdkAPI = class _QueryPanelSdkAPI {
2754
2914
  };
2755
2915
  this.queryEngine.attachDatabase(name, adapter, metadata);
2756
2916
  }
2917
+ /**
2918
+ * Attach an Amazon Redshift database. Redshift speaks the Postgres wire
2919
+ * protocol, so `clientFn` can wrap a `pg` client; introspection uses
2920
+ * Redshift's svv_* catalog views and SQL is generated for Redshift.
2921
+ */
2922
+ attachRedshift(name, clientFn, options) {
2923
+ this.attachPostgres(name, clientFn, { ...options, dialect: "redshift" });
2924
+ }
2757
2925
  attachBigQuery(name, clientFn, options) {
2758
2926
  const adapter = new BigQueryAdapter(clientFn, options);
2759
2927
  const metadata = {