@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 CHANGED
@@ -2292,6 +2292,7 @@ function buildModifiedQuestion(originalQuestion, modifications, hasSessionContex
2292
2292
  }
2293
2293
  return `${originalQuestion} (${hints.join(", ")})`;
2294
2294
  }
2295
+ var REWRITE_DATEFILTER_ENDPOINT = "/v2/rewrite-datefilter";
2295
2296
  var START_PARAM_KEY_REGEX = /(^|_)(start|from)(_|$)/i;
2296
2297
  var END_PARAM_KEY_REGEX = /(^|_)(end|to)(_|$)/i;
2297
2298
  var ISO_DATETIME_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z?$/;
@@ -2328,31 +2329,118 @@ function normalizeGeneratedParamKey(param, index) {
2328
2329
  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);
2329
2330
  return nameCandidate.replace(/[{}]/g, "").replace(/(.+):.*$/, "$1").replace(/^[:$]/, "").trim();
2330
2331
  }
2331
- function applyDateRangeOverrides(dateRange, params, paramMetadata) {
2332
+ function collectParamKeys(params, paramMetadata) {
2333
+ const keys = new Set(Object.keys(params));
2334
+ for (let i = 0; i < paramMetadata.length; i++) {
2335
+ const param = paramMetadata[i];
2336
+ if (!param) continue;
2337
+ keys.add(normalizeGeneratedParamKey(param, i));
2338
+ }
2339
+ return [...keys];
2340
+ }
2341
+ function placeholderKey(token) {
2342
+ if (token.startsWith("$") || token.startsWith("@")) return token.slice(1);
2343
+ return token.slice(1, -1).replace(/:.+$/, "").trim();
2344
+ }
2345
+ function isDateLike(value) {
2346
+ return typeof value === "string" && /^\d{4}-\d{2}-\d{2}/.test(value.trim());
2347
+ }
2348
+ function dateBoundKeysFromSql(sql) {
2349
+ const start = /* @__PURE__ */ new Set();
2350
+ const end = /* @__PURE__ */ new Set();
2351
+ const comparison = /(>=|<=|>|<)\s*(\$\d+|\{[^}]+\}|@[A-Za-z_][\w]*)/g;
2352
+ const between = /BETWEEN\s+(\$\d+|\{[^}]+\}|@[A-Za-z_][\w]*)\s+AND\s+(\$\d+|\{[^}]+\}|@[A-Za-z_][\w]*)/gi;
2353
+ for (const match of sql.matchAll(comparison)) {
2354
+ const key = placeholderKey(match[2] ?? "");
2355
+ if (!key) continue;
2356
+ if (match[1] === ">=" || match[1] === ">") start.add(key);
2357
+ else end.add(key);
2358
+ }
2359
+ for (const match of sql.matchAll(between)) {
2360
+ const startKey = placeholderKey(match[1] ?? "");
2361
+ const endKey = placeholderKey(match[2] ?? "");
2362
+ if (startKey) start.add(startKey);
2363
+ if (endKey) end.add(endKey);
2364
+ }
2365
+ return { start, end };
2366
+ }
2367
+ function paramValueForKey(key, params, paramMetadata) {
2368
+ if (key in params) return params[key];
2369
+ for (let i = 0; i < paramMetadata.length; i++) {
2370
+ const param = paramMetadata[i];
2371
+ if (!param) continue;
2372
+ if (normalizeGeneratedParamKey(param, i) === key) return param.value;
2373
+ }
2374
+ return void 0;
2375
+ }
2376
+ function dateBoundKeys(sql, params, paramMetadata, boundary) {
2377
+ const fromSql = dateBoundKeysFromSql(sql)[boundary];
2378
+ const keys = [];
2379
+ for (const key of collectParamKeys(params, paramMetadata)) {
2380
+ const named = keyLooksLikeDateBoundary(key, boundary);
2381
+ if (!named && !fromSql.has(key)) continue;
2382
+ if (!isDateLike(paramValueForKey(key, params, paramMetadata))) continue;
2383
+ keys.push(key);
2384
+ }
2385
+ return keys;
2386
+ }
2387
+ function canSubstituteDateRangeParams(dateRange, sql, params, paramMetadata = []) {
2388
+ if (!dateRange) return false;
2389
+ const from = normalizeDateInput(dateRange.from);
2390
+ const to = normalizeDateInput(dateRange.to);
2391
+ if (!from && !to) return false;
2392
+ if (from && dateBoundKeys(sql, params, paramMetadata, "start").length === 0) {
2393
+ return false;
2394
+ }
2395
+ if (to && dateBoundKeys(sql, params, paramMetadata, "end").length === 0) {
2396
+ return false;
2397
+ }
2398
+ return true;
2399
+ }
2400
+ function isDateRangeOnlySqlModification(modifications) {
2401
+ if (!modifications?.dateRange) return false;
2402
+ if (modifications.customSql) return false;
2403
+ if (modifications.timeGranularity) return false;
2404
+ if (typeof modifications.additionalInstructions === "string" && modifications.additionalInstructions.trim().length > 0) {
2405
+ return false;
2406
+ }
2407
+ return true;
2408
+ }
2409
+ function applyDateRangeOverrides(dateRange, sql, params, paramMetadata) {
2332
2410
  if (!dateRange) return;
2333
2411
  const from = normalizeDateInput(dateRange.from);
2334
2412
  const to = normalizeDateInput(dateRange.to);
2335
2413
  if (!from && !to) return;
2414
+ const startKeys = new Set(
2415
+ from ? dateBoundKeys(sql, params, paramMetadata, "start") : []
2416
+ );
2417
+ const endKeys = new Set(
2418
+ to ? dateBoundKeys(sql, params, paramMetadata, "end") : []
2419
+ );
2336
2420
  for (const [key, value] of Object.entries(params)) {
2337
- if (from && keyLooksLikeDateBoundary(key, "start")) {
2338
- params[key] = formatDateOverride(from, "start", value);
2421
+ if (startKeys.has(key)) {
2422
+ params[key] = formatDateOverride(from ?? "", "start", value);
2339
2423
  }
2340
- if (to && keyLooksLikeDateBoundary(key, "end")) {
2341
- params[key] = formatDateOverride(to, "end", value);
2424
+ if (endKeys.has(key)) {
2425
+ params[key] = formatDateOverride(to ?? "", "end", value);
2342
2426
  }
2343
2427
  }
2344
2428
  for (let i = 0; i < paramMetadata.length; i++) {
2345
2429
  const param = paramMetadata[i];
2346
2430
  if (!param) continue;
2347
2431
  const key = normalizeGeneratedParamKey(param, i);
2348
- if (from && keyLooksLikeDateBoundary(key, "start")) {
2349
- param.value = formatDateOverride(from, "start", param.value);
2432
+ if (startKeys.has(key)) {
2433
+ param.value = formatDateOverride(from ?? "", "start", param.value);
2350
2434
  }
2351
- if (to && keyLooksLikeDateBoundary(key, "end")) {
2352
- param.value = formatDateOverride(to, "end", param.value);
2435
+ if (endKeys.has(key)) {
2436
+ param.value = formatDateOverride(to ?? "", "end", param.value);
2353
2437
  }
2354
2438
  }
2355
2439
  }
2440
+ function buildPreviousParams(params, paramMetadata) {
2441
+ if (paramMetadata.length > 0) return paramMetadata;
2442
+ return Object.entries(params).map(([name, value]) => ({ name, value }));
2443
+ }
2356
2444
  function buildVizHints(modifications) {
2357
2445
  const hints = {};
2358
2446
  if (modifications.kind) {
@@ -2403,6 +2491,9 @@ async function modifyChart(client, queryEngine, input, options, signal) {
2403
2491
  const hasSqlMods = !!input.sqlModifications;
2404
2492
  const hasVizMods = !!input.vizModifications;
2405
2493
  const hasCustomSql = !!input.sqlModifications?.customSql;
2494
+ const lightweight = options?.lightweight === true;
2495
+ const dateOnly = lightweight && isDateRangeOnlySqlModification(input.sqlModifications);
2496
+ const skipChartLlm = lightweight && !hasCustomSql && (dateOnly || hasVizMods && !hasSqlMods);
2406
2497
  resolveQueryPipeline(options?.pipeline);
2407
2498
  const queryEndpoint = "/v2/query";
2408
2499
  let currentSql = input.sql;
@@ -2456,6 +2547,20 @@ async function modifyChart(client, queryEngine, input, options, signal) {
2456
2547
  paramMetadata = [];
2457
2548
  queryId = void 0;
2458
2549
  sqlChanged = true;
2550
+ } else if (dateOnly && canSubstituteDateRangeParams(
2551
+ input.sqlModifications?.dateRange,
2552
+ finalSql,
2553
+ finalParams,
2554
+ paramMetadata
2555
+ )) {
2556
+ finalParams = { ...finalParams };
2557
+ applyDateRangeOverrides(
2558
+ input.sqlModifications?.dateRange,
2559
+ finalSql,
2560
+ finalParams,
2561
+ paramMetadata
2562
+ );
2563
+ sqlChanged = false;
2459
2564
  } else if (hasSqlMods && !hasCustomSql) {
2460
2565
  const modifiedQuestion = buildModifiedQuestion(
2461
2566
  input.question,
@@ -2463,18 +2568,36 @@ async function modifyChart(client, queryEngine, input, options, signal) {
2463
2568
  hasQuerypanelSessionContext
2464
2569
  );
2465
2570
  finalQuestion = modifiedQuestion;
2466
- const queryResponse = await client.post(
2571
+ const sharedBody = {
2572
+ session_id: querypanelSessionId,
2573
+ previous_sql: currentSql,
2574
+ ...tenantSettings ? { tenant_settings: tenantSettings } : {},
2575
+ ...databaseName ? { database: databaseName } : {},
2576
+ ...metadata?.dialect ? { dialect: metadata.dialect } : {},
2577
+ debug: options?.debug ?? false
2578
+ };
2579
+ const [endpoint, body] = dateOnly ? [
2580
+ REWRITE_DATEFILTER_ENDPOINT,
2581
+ {
2582
+ ...sharedBody,
2583
+ question: input.question,
2584
+ previous_params: buildPreviousParams(finalParams, paramMetadata),
2585
+ date_range: {
2586
+ from: normalizeDateInput(input.sqlModifications?.dateRange?.from),
2587
+ to: normalizeDateInput(input.sqlModifications?.dateRange?.to)
2588
+ }
2589
+ }
2590
+ ] : [
2467
2591
  queryEndpoint,
2468
2592
  {
2593
+ ...sharedBody,
2469
2594
  question: modifiedQuestion,
2470
- session_id: querypanelSessionId,
2471
- previous_sql: currentSql,
2472
- ...options?.maxRetry ? { max_retry: options.maxRetry } : {},
2473
- ...tenantSettings ? { tenant_settings: tenantSettings } : {},
2474
- ...databaseName ? { database: databaseName } : {},
2475
- ...metadata?.dialect ? { dialect: metadata.dialect } : {},
2476
- debug: options?.debug ?? false
2477
- },
2595
+ ...options?.maxRetry ? { max_retry: options.maxRetry } : {}
2596
+ }
2597
+ ];
2598
+ const queryResponse = await client.post(
2599
+ endpoint,
2600
+ body,
2478
2601
  tenantId,
2479
2602
  options?.userId,
2480
2603
  options?.scopes,
@@ -2486,6 +2609,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
2486
2609
  finalParams = queryEngine.mapGeneratedParams(paramMetadata);
2487
2610
  applyDateRangeOverrides(
2488
2611
  input.sqlModifications?.dateRange,
2612
+ finalSql,
2489
2613
  finalParams,
2490
2614
  paramMetadata
2491
2615
  );
@@ -2506,7 +2630,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
2506
2630
  };
2507
2631
  const vizHints = hasVizMods ? buildVizHints(input.vizModifications) : {};
2508
2632
  const vizHintsForChart = chartType === "vizspec" ? vizHints : stripVizSpecOnlyHints(vizHints);
2509
- if (chartType === "vizspec") {
2633
+ if (!skipChartLlm && chartType === "vizspec") {
2510
2634
  const vizspecResponse = await client.post(
2511
2635
  "/vizspec",
2512
2636
  {
@@ -2533,7 +2657,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
2533
2657
  specType: "vizspec",
2534
2658
  notes: rows.length === 0 ? vizspecResponse.notes ?? "Query returned no rows." : vizspecResponse.notes
2535
2659
  };
2536
- } else {
2660
+ } else if (!skipChartLlm) {
2537
2661
  const chartResponse = await client.post(
2538
2662
  "/chart",
2539
2663
  {