@querypanel/node-sdk 1.3.1 → 1.3.3
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 +144 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +144 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -990,6 +990,13 @@ interface ChartModifyOptions {
|
|
|
990
990
|
* Omit this field; chart modifications always use v2.
|
|
991
991
|
*/
|
|
992
992
|
pipeline?: "v2";
|
|
993
|
+
/**
|
|
994
|
+
* Fast path for structured controls (pinned charts): date-only changes
|
|
995
|
+
* substitute params or call `/v2/rewrite-datefilter` instead of `/v2/query`,
|
|
996
|
+
* and chart generation is skipped when the caller keeps its own encoding
|
|
997
|
+
* (`chart.vizSpec` / `vegaLiteSpec` are then omitted). Default: false.
|
|
998
|
+
*/
|
|
999
|
+
lightweight?: boolean;
|
|
993
1000
|
/**
|
|
994
1001
|
* QueryPanel session ID for context-aware follow-ups.
|
|
995
1002
|
* Pass the querypanelSessionId from a previous ask() response
|
package/dist/index.d.ts
CHANGED
|
@@ -990,6 +990,13 @@ interface ChartModifyOptions {
|
|
|
990
990
|
* Omit this field; chart modifications always use v2.
|
|
991
991
|
*/
|
|
992
992
|
pipeline?: "v2";
|
|
993
|
+
/**
|
|
994
|
+
* Fast path for structured controls (pinned charts): date-only changes
|
|
995
|
+
* substitute params or call `/v2/rewrite-datefilter` instead of `/v2/query`,
|
|
996
|
+
* and chart generation is skipped when the caller keeps its own encoding
|
|
997
|
+
* (`chart.vizSpec` / `vegaLiteSpec` are then omitted). Default: false.
|
|
998
|
+
*/
|
|
999
|
+
lightweight?: boolean;
|
|
993
1000
|
/**
|
|
994
1001
|
* QueryPanel session ID for context-aware follow-ups.
|
|
995
1002
|
* Pass the querypanelSessionId from a previous ask() response
|
package/dist/index.js
CHANGED
|
@@ -2245,6 +2245,7 @@ function buildModifiedQuestion(originalQuestion, modifications, hasSessionContex
|
|
|
2245
2245
|
}
|
|
2246
2246
|
return `${originalQuestion} (${hints.join(", ")})`;
|
|
2247
2247
|
}
|
|
2248
|
+
var REWRITE_DATEFILTER_ENDPOINT = "/v2/rewrite-datefilter";
|
|
2248
2249
|
var START_PARAM_KEY_REGEX = /(^|_)(start|from)(_|$)/i;
|
|
2249
2250
|
var END_PARAM_KEY_REGEX = /(^|_)(end|to)(_|$)/i;
|
|
2250
2251
|
var ISO_DATETIME_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z?$/;
|
|
@@ -2281,31 +2282,118 @@ function normalizeGeneratedParamKey(param, index) {
|
|
|
2281
2282
|
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
2283
|
return nameCandidate.replace(/[{}]/g, "").replace(/(.+):.*$/, "$1").replace(/^[:$]/, "").trim();
|
|
2283
2284
|
}
|
|
2284
|
-
function
|
|
2285
|
+
function collectParamKeys(params, paramMetadata) {
|
|
2286
|
+
const keys = new Set(Object.keys(params));
|
|
2287
|
+
for (let i = 0; i < paramMetadata.length; i++) {
|
|
2288
|
+
const param = paramMetadata[i];
|
|
2289
|
+
if (!param) continue;
|
|
2290
|
+
keys.add(normalizeGeneratedParamKey(param, i));
|
|
2291
|
+
}
|
|
2292
|
+
return [...keys];
|
|
2293
|
+
}
|
|
2294
|
+
function placeholderKey(token) {
|
|
2295
|
+
if (token.startsWith("$") || token.startsWith("@")) return token.slice(1);
|
|
2296
|
+
return token.slice(1, -1).replace(/:.+$/, "").trim();
|
|
2297
|
+
}
|
|
2298
|
+
function isDateLike(value) {
|
|
2299
|
+
return typeof value === "string" && /^\d{4}-\d{2}-\d{2}/.test(value.trim());
|
|
2300
|
+
}
|
|
2301
|
+
function dateBoundKeysFromSql(sql) {
|
|
2302
|
+
const start = /* @__PURE__ */ new Set();
|
|
2303
|
+
const end = /* @__PURE__ */ new Set();
|
|
2304
|
+
const comparison = /(>=|<=|>|<)\s*(\$\d+|\{[^}]+\}|@[A-Za-z_][\w]*)/g;
|
|
2305
|
+
const between = /BETWEEN\s+(\$\d+|\{[^}]+\}|@[A-Za-z_][\w]*)\s+AND\s+(\$\d+|\{[^}]+\}|@[A-Za-z_][\w]*)/gi;
|
|
2306
|
+
for (const match of sql.matchAll(comparison)) {
|
|
2307
|
+
const key = placeholderKey(match[2] ?? "");
|
|
2308
|
+
if (!key) continue;
|
|
2309
|
+
if (match[1] === ">=" || match[1] === ">") start.add(key);
|
|
2310
|
+
else end.add(key);
|
|
2311
|
+
}
|
|
2312
|
+
for (const match of sql.matchAll(between)) {
|
|
2313
|
+
const startKey = placeholderKey(match[1] ?? "");
|
|
2314
|
+
const endKey = placeholderKey(match[2] ?? "");
|
|
2315
|
+
if (startKey) start.add(startKey);
|
|
2316
|
+
if (endKey) end.add(endKey);
|
|
2317
|
+
}
|
|
2318
|
+
return { start, end };
|
|
2319
|
+
}
|
|
2320
|
+
function paramValueForKey(key, params, paramMetadata) {
|
|
2321
|
+
if (key in params) return params[key];
|
|
2322
|
+
for (let i = 0; i < paramMetadata.length; i++) {
|
|
2323
|
+
const param = paramMetadata[i];
|
|
2324
|
+
if (!param) continue;
|
|
2325
|
+
if (normalizeGeneratedParamKey(param, i) === key) return param.value;
|
|
2326
|
+
}
|
|
2327
|
+
return void 0;
|
|
2328
|
+
}
|
|
2329
|
+
function dateBoundKeys(sql, params, paramMetadata, boundary) {
|
|
2330
|
+
const fromSql = dateBoundKeysFromSql(sql)[boundary];
|
|
2331
|
+
const keys = [];
|
|
2332
|
+
for (const key of collectParamKeys(params, paramMetadata)) {
|
|
2333
|
+
const named = keyLooksLikeDateBoundary(key, boundary);
|
|
2334
|
+
if (!named && !fromSql.has(key)) continue;
|
|
2335
|
+
if (!isDateLike(paramValueForKey(key, params, paramMetadata))) continue;
|
|
2336
|
+
keys.push(key);
|
|
2337
|
+
}
|
|
2338
|
+
return keys;
|
|
2339
|
+
}
|
|
2340
|
+
function canSubstituteDateRangeParams(dateRange, sql, params, paramMetadata = []) {
|
|
2341
|
+
if (!dateRange) return false;
|
|
2342
|
+
const from = normalizeDateInput(dateRange.from);
|
|
2343
|
+
const to = normalizeDateInput(dateRange.to);
|
|
2344
|
+
if (!from && !to) return false;
|
|
2345
|
+
if (from && dateBoundKeys(sql, params, paramMetadata, "start").length === 0) {
|
|
2346
|
+
return false;
|
|
2347
|
+
}
|
|
2348
|
+
if (to && dateBoundKeys(sql, params, paramMetadata, "end").length === 0) {
|
|
2349
|
+
return false;
|
|
2350
|
+
}
|
|
2351
|
+
return true;
|
|
2352
|
+
}
|
|
2353
|
+
function isDateRangeOnlySqlModification(modifications) {
|
|
2354
|
+
if (!modifications?.dateRange) return false;
|
|
2355
|
+
if (modifications.customSql) return false;
|
|
2356
|
+
if (modifications.timeGranularity) return false;
|
|
2357
|
+
if (typeof modifications.additionalInstructions === "string" && modifications.additionalInstructions.trim().length > 0) {
|
|
2358
|
+
return false;
|
|
2359
|
+
}
|
|
2360
|
+
return true;
|
|
2361
|
+
}
|
|
2362
|
+
function applyDateRangeOverrides(dateRange, sql, params, paramMetadata) {
|
|
2285
2363
|
if (!dateRange) return;
|
|
2286
2364
|
const from = normalizeDateInput(dateRange.from);
|
|
2287
2365
|
const to = normalizeDateInput(dateRange.to);
|
|
2288
2366
|
if (!from && !to) return;
|
|
2367
|
+
const startKeys = new Set(
|
|
2368
|
+
from ? dateBoundKeys(sql, params, paramMetadata, "start") : []
|
|
2369
|
+
);
|
|
2370
|
+
const endKeys = new Set(
|
|
2371
|
+
to ? dateBoundKeys(sql, params, paramMetadata, "end") : []
|
|
2372
|
+
);
|
|
2289
2373
|
for (const [key, value] of Object.entries(params)) {
|
|
2290
|
-
if (
|
|
2291
|
-
params[key] = formatDateOverride(from, "start", value);
|
|
2374
|
+
if (startKeys.has(key)) {
|
|
2375
|
+
params[key] = formatDateOverride(from ?? "", "start", value);
|
|
2292
2376
|
}
|
|
2293
|
-
if (
|
|
2294
|
-
params[key] = formatDateOverride(to, "end", value);
|
|
2377
|
+
if (endKeys.has(key)) {
|
|
2378
|
+
params[key] = formatDateOverride(to ?? "", "end", value);
|
|
2295
2379
|
}
|
|
2296
2380
|
}
|
|
2297
2381
|
for (let i = 0; i < paramMetadata.length; i++) {
|
|
2298
2382
|
const param = paramMetadata[i];
|
|
2299
2383
|
if (!param) continue;
|
|
2300
2384
|
const key = normalizeGeneratedParamKey(param, i);
|
|
2301
|
-
if (
|
|
2302
|
-
param.value = formatDateOverride(from, "start", param.value);
|
|
2385
|
+
if (startKeys.has(key)) {
|
|
2386
|
+
param.value = formatDateOverride(from ?? "", "start", param.value);
|
|
2303
2387
|
}
|
|
2304
|
-
if (
|
|
2305
|
-
param.value = formatDateOverride(to, "end", param.value);
|
|
2388
|
+
if (endKeys.has(key)) {
|
|
2389
|
+
param.value = formatDateOverride(to ?? "", "end", param.value);
|
|
2306
2390
|
}
|
|
2307
2391
|
}
|
|
2308
2392
|
}
|
|
2393
|
+
function buildPreviousParams(params, paramMetadata) {
|
|
2394
|
+
if (paramMetadata.length > 0) return paramMetadata;
|
|
2395
|
+
return Object.entries(params).map(([name, value]) => ({ name, value }));
|
|
2396
|
+
}
|
|
2309
2397
|
function buildVizHints(modifications) {
|
|
2310
2398
|
const hints = {};
|
|
2311
2399
|
if (modifications.kind) {
|
|
@@ -2356,6 +2444,9 @@ async function modifyChart(client, queryEngine, input, options, signal) {
|
|
|
2356
2444
|
const hasSqlMods = !!input.sqlModifications;
|
|
2357
2445
|
const hasVizMods = !!input.vizModifications;
|
|
2358
2446
|
const hasCustomSql = !!input.sqlModifications?.customSql;
|
|
2447
|
+
const lightweight = options?.lightweight === true;
|
|
2448
|
+
const dateOnly = lightweight && isDateRangeOnlySqlModification(input.sqlModifications);
|
|
2449
|
+
const skipChartLlm = lightweight && !hasCustomSql && (dateOnly || hasVizMods && !hasSqlMods);
|
|
2359
2450
|
resolveQueryPipeline(options?.pipeline);
|
|
2360
2451
|
const queryEndpoint = "/v2/query";
|
|
2361
2452
|
let currentSql = input.sql;
|
|
@@ -2409,6 +2500,20 @@ async function modifyChart(client, queryEngine, input, options, signal) {
|
|
|
2409
2500
|
paramMetadata = [];
|
|
2410
2501
|
queryId = void 0;
|
|
2411
2502
|
sqlChanged = true;
|
|
2503
|
+
} else if (dateOnly && canSubstituteDateRangeParams(
|
|
2504
|
+
input.sqlModifications?.dateRange,
|
|
2505
|
+
finalSql,
|
|
2506
|
+
finalParams,
|
|
2507
|
+
paramMetadata
|
|
2508
|
+
)) {
|
|
2509
|
+
finalParams = { ...finalParams };
|
|
2510
|
+
applyDateRangeOverrides(
|
|
2511
|
+
input.sqlModifications?.dateRange,
|
|
2512
|
+
finalSql,
|
|
2513
|
+
finalParams,
|
|
2514
|
+
paramMetadata
|
|
2515
|
+
);
|
|
2516
|
+
sqlChanged = false;
|
|
2412
2517
|
} else if (hasSqlMods && !hasCustomSql) {
|
|
2413
2518
|
const modifiedQuestion = buildModifiedQuestion(
|
|
2414
2519
|
input.question,
|
|
@@ -2416,18 +2521,36 @@ async function modifyChart(client, queryEngine, input, options, signal) {
|
|
|
2416
2521
|
hasQuerypanelSessionContext
|
|
2417
2522
|
);
|
|
2418
2523
|
finalQuestion = modifiedQuestion;
|
|
2419
|
-
const
|
|
2524
|
+
const sharedBody = {
|
|
2525
|
+
session_id: querypanelSessionId,
|
|
2526
|
+
previous_sql: currentSql,
|
|
2527
|
+
...tenantSettings ? { tenant_settings: tenantSettings } : {},
|
|
2528
|
+
...databaseName ? { database: databaseName } : {},
|
|
2529
|
+
...metadata?.dialect ? { dialect: metadata.dialect } : {},
|
|
2530
|
+
debug: options?.debug ?? false
|
|
2531
|
+
};
|
|
2532
|
+
const [endpoint, body] = dateOnly ? [
|
|
2533
|
+
REWRITE_DATEFILTER_ENDPOINT,
|
|
2534
|
+
{
|
|
2535
|
+
...sharedBody,
|
|
2536
|
+
question: input.question,
|
|
2537
|
+
previous_params: buildPreviousParams(finalParams, paramMetadata),
|
|
2538
|
+
date_range: {
|
|
2539
|
+
from: normalizeDateInput(input.sqlModifications?.dateRange?.from),
|
|
2540
|
+
to: normalizeDateInput(input.sqlModifications?.dateRange?.to)
|
|
2541
|
+
}
|
|
2542
|
+
}
|
|
2543
|
+
] : [
|
|
2420
2544
|
queryEndpoint,
|
|
2421
2545
|
{
|
|
2546
|
+
...sharedBody,
|
|
2422
2547
|
question: modifiedQuestion,
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
debug: options?.debug ?? false
|
|
2430
|
-
},
|
|
2548
|
+
...options?.maxRetry ? { max_retry: options.maxRetry } : {}
|
|
2549
|
+
}
|
|
2550
|
+
];
|
|
2551
|
+
const queryResponse = await client.post(
|
|
2552
|
+
endpoint,
|
|
2553
|
+
body,
|
|
2431
2554
|
tenantId,
|
|
2432
2555
|
options?.userId,
|
|
2433
2556
|
options?.scopes,
|
|
@@ -2439,6 +2562,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
|
|
|
2439
2562
|
finalParams = queryEngine.mapGeneratedParams(paramMetadata);
|
|
2440
2563
|
applyDateRangeOverrides(
|
|
2441
2564
|
input.sqlModifications?.dateRange,
|
|
2565
|
+
finalSql,
|
|
2442
2566
|
finalParams,
|
|
2443
2567
|
paramMetadata
|
|
2444
2568
|
);
|
|
@@ -2459,7 +2583,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
|
|
|
2459
2583
|
};
|
|
2460
2584
|
const vizHints = hasVizMods ? buildVizHints(input.vizModifications) : {};
|
|
2461
2585
|
const vizHintsForChart = chartType === "vizspec" ? vizHints : stripVizSpecOnlyHints(vizHints);
|
|
2462
|
-
if (chartType === "vizspec") {
|
|
2586
|
+
if (!skipChartLlm && chartType === "vizspec") {
|
|
2463
2587
|
const vizspecResponse = await client.post(
|
|
2464
2588
|
"/vizspec",
|
|
2465
2589
|
{
|
|
@@ -2486,7 +2610,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
|
|
|
2486
2610
|
specType: "vizspec",
|
|
2487
2611
|
notes: rows.length === 0 ? vizspecResponse.notes ?? "Query returned no rows." : vizspecResponse.notes
|
|
2488
2612
|
};
|
|
2489
|
-
} else {
|
|
2613
|
+
} else if (!skipChartLlm) {
|
|
2490
2614
|
const chartResponse = await client.post(
|
|
2491
2615
|
"/chart",
|
|
2492
2616
|
{
|