@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/README.md +47 -19
- package/dist/index.cjs +194 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -4
- package/dist/index.d.ts +30 -4
- package/dist/index.js +194 -26
- package/dist/index.js.map +1 -1
- package/package.json +16 -3
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
|
|
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():
|
|
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
|
|
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():
|
|
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.
|
|
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
|
|
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
|
|
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 (
|
|
2291
|
-
params[key] = formatDateOverride(from, "start", value);
|
|
2410
|
+
if (startKeys.has(key)) {
|
|
2411
|
+
params[key] = formatDateOverride(from ?? "", "start", value);
|
|
2292
2412
|
}
|
|
2293
|
-
if (
|
|
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 (
|
|
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 (
|
|
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
|
|
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
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
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:
|
|
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 = {
|