@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.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 applyDateRangeOverrides(dateRange, params, paramMetadata) {
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 (from && keyLooksLikeDateBoundary(key, "start")) {
2291
- params[key] = formatDateOverride(from, "start", value);
2374
+ if (startKeys.has(key)) {
2375
+ params[key] = formatDateOverride(from ?? "", "start", value);
2292
2376
  }
2293
- if (to && keyLooksLikeDateBoundary(key, "end")) {
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 (from && keyLooksLikeDateBoundary(key, "start")) {
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 (to && keyLooksLikeDateBoundary(key, "end")) {
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 queryResponse = await client.post(
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
- 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
- },
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
  {