@querypanel/node-sdk 1.0.52 → 1.0.53

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.js CHANGED
@@ -1414,21 +1414,39 @@ function anonymizeResults(rows) {
1414
1414
  }
1415
1415
 
1416
1416
  // src/routes/modify.ts
1417
- function buildModifiedQuestion(originalQuestion, modifications) {
1417
+ function buildModifiedQuestion(originalQuestion, modifications, pipeline) {
1418
1418
  const hints = [];
1419
1419
  if (modifications.timeGranularity) {
1420
1420
  hints.push(`group results by ${modifications.timeGranularity}`);
1421
1421
  }
1422
1422
  if (modifications.dateRange) {
1423
- const parts = [];
1424
- if (modifications.dateRange.from) {
1425
- parts.push(`from ${modifications.dateRange.from}`);
1426
- }
1427
- if (modifications.dateRange.to) {
1428
- parts.push(`to ${modifications.dateRange.to}`);
1429
- }
1430
- if (parts.length > 0) {
1431
- hints.push(`filter date range ${parts.join(" ")}`);
1423
+ if (pipeline === "v2") {
1424
+ const from = normalizeDateInput(modifications.dateRange.from);
1425
+ const to = normalizeDateInput(modifications.dateRange.to);
1426
+ if (from && to) {
1427
+ hints.push(
1428
+ `replace any existing date filters with exact date range from ${from} to ${to} (inclusive, do not add extra days)`
1429
+ );
1430
+ } else if (from) {
1431
+ hints.push(
1432
+ `replace any existing date filters with exact start date ${from} (do not shift this date)`
1433
+ );
1434
+ } else if (to) {
1435
+ hints.push(
1436
+ `replace any existing date filters with exact end date ${to} (inclusive, do not add extra days)`
1437
+ );
1438
+ }
1439
+ } else {
1440
+ const parts = [];
1441
+ if (modifications.dateRange.from) {
1442
+ parts.push(`from ${modifications.dateRange.from}`);
1443
+ }
1444
+ if (modifications.dateRange.to) {
1445
+ parts.push(`to ${modifications.dateRange.to}`);
1446
+ }
1447
+ if (parts.length > 0) {
1448
+ hints.push(`filter date range ${parts.join(" ")}`);
1449
+ }
1432
1450
  }
1433
1451
  }
1434
1452
  if (modifications.additionalInstructions) {
@@ -1439,6 +1457,67 @@ function buildModifiedQuestion(originalQuestion, modifications) {
1439
1457
  }
1440
1458
  return `${originalQuestion} (${hints.join(", ")})`;
1441
1459
  }
1460
+ var START_PARAM_KEY_REGEX = /(^|_)(start|from)(_|$)/i;
1461
+ var END_PARAM_KEY_REGEX = /(^|_)(end|to)(_|$)/i;
1462
+ var ISO_DATETIME_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z?$/;
1463
+ var SQL_DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
1464
+ var SQL_DATETIME_RE = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/;
1465
+ function normalizeDateInput(value) {
1466
+ if (!value) return void 0;
1467
+ const trimmed = value.trim();
1468
+ if (!trimmed) return void 0;
1469
+ if (ISO_DATETIME_RE.test(trimmed)) {
1470
+ return trimmed.replace("T", " ").replace(/\.\d+Z?$/, "").replace(/Z$/, "");
1471
+ }
1472
+ return trimmed;
1473
+ }
1474
+ function keyLooksLikeDateBoundary(key, boundary) {
1475
+ return boundary === "start" ? START_PARAM_KEY_REGEX.test(key) : END_PARAM_KEY_REGEX.test(key);
1476
+ }
1477
+ function hasTimeComponent(value) {
1478
+ return typeof value === "string" && /\d{2}:\d{2}:\d{2}/.test(value);
1479
+ }
1480
+ function formatDateOverride(dateValue, boundary, existingValue) {
1481
+ if (SQL_DATE_RE.test(dateValue) && !hasTimeComponent(existingValue)) {
1482
+ return dateValue;
1483
+ }
1484
+ if (SQL_DATE_RE.test(dateValue)) {
1485
+ return `${dateValue} ${boundary === "start" ? "00:00:00" : "23:59:59"}`;
1486
+ }
1487
+ if (SQL_DATETIME_RE.test(dateValue)) {
1488
+ return dateValue;
1489
+ }
1490
+ return dateValue;
1491
+ }
1492
+ function normalizeGeneratedParamKey(param, index) {
1493
+ 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);
1494
+ return nameCandidate.replace(/[{}]/g, "").replace(/(.+):.*$/, "$1").replace(/^[:$]/, "").trim();
1495
+ }
1496
+ function applyDateRangeOverrides(dateRange, params, paramMetadata) {
1497
+ if (!dateRange) return;
1498
+ const from = normalizeDateInput(dateRange.from);
1499
+ const to = normalizeDateInput(dateRange.to);
1500
+ if (!from && !to) return;
1501
+ for (const [key, value] of Object.entries(params)) {
1502
+ if (from && keyLooksLikeDateBoundary(key, "start")) {
1503
+ params[key] = formatDateOverride(from, "start", value);
1504
+ }
1505
+ if (to && keyLooksLikeDateBoundary(key, "end")) {
1506
+ params[key] = formatDateOverride(to, "end", value);
1507
+ }
1508
+ }
1509
+ for (let i = 0; i < paramMetadata.length; i++) {
1510
+ const param = paramMetadata[i];
1511
+ if (!param) continue;
1512
+ const key = normalizeGeneratedParamKey(param, i);
1513
+ if (from && keyLooksLikeDateBoundary(key, "start")) {
1514
+ param.value = formatDateOverride(from, "start", param.value);
1515
+ }
1516
+ if (to && keyLooksLikeDateBoundary(key, "end")) {
1517
+ param.value = formatDateOverride(to, "end", param.value);
1518
+ }
1519
+ }
1520
+ }
1442
1521
  function buildVizHints(modifications) {
1443
1522
  const hints = {};
1444
1523
  if (modifications.kind) {
@@ -1471,6 +1550,9 @@ function stripVizSpecOnlyHints(hints) {
1471
1550
  const { kind: _kind, ...rest } = hints;
1472
1551
  return rest;
1473
1552
  }
1553
+ function isDateRangeOnly(mods) {
1554
+ return !!mods.dateRange && !mods.timeGranularity && !mods.additionalInstructions && !mods.customSql;
1555
+ }
1474
1556
  function resolveTenantId5(client, tenantId) {
1475
1557
  const resolved = tenantId ?? client.getDefaultTenantId();
1476
1558
  if (!resolved) {
@@ -1494,6 +1576,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
1494
1576
  let rationale;
1495
1577
  let queryId;
1496
1578
  let sqlChanged = false;
1579
+ let finalQuestion = input.question;
1497
1580
  const databaseName = input.database ?? queryEngine.getDefaultDatabase();
1498
1581
  if (!databaseName) {
1499
1582
  throw new Error(
@@ -1514,11 +1597,87 @@ async function modifyChart(client, queryEngine, input, options, signal) {
1514
1597
  finalParams = {};
1515
1598
  paramMetadata = [];
1516
1599
  sqlChanged = true;
1600
+ } else if (hasSqlMods && options?.pipeline === "v2" && isDateRangeOnly(input.sqlModifications)) {
1601
+ let usedFastPath = false;
1602
+ try {
1603
+ const rewriteResponse = await client.post(
1604
+ "/v2/rewrite-datefilter",
1605
+ {
1606
+ previous_sql: input.sql,
1607
+ previous_params: input.params ? Object.entries(input.params).map(([name, value]) => ({
1608
+ name,
1609
+ value
1610
+ })) : [],
1611
+ date_range: input.sqlModifications.dateRange,
1612
+ question: input.question,
1613
+ ...tenantSettings ? { tenant_settings: tenantSettings } : {},
1614
+ ...databaseName ? { database: databaseName } : {},
1615
+ ...metadata?.dialect ? { dialect: metadata.dialect } : {}
1616
+ },
1617
+ tenantId,
1618
+ options?.userId,
1619
+ options?.scopes,
1620
+ signal,
1621
+ sessionId
1622
+ );
1623
+ finalSql = rewriteResponse.sql;
1624
+ paramMetadata = Array.isArray(rewriteResponse.params) ? rewriteResponse.params : [];
1625
+ finalParams = queryEngine.mapGeneratedParams(paramMetadata);
1626
+ applyDateRangeOverrides(
1627
+ input.sqlModifications?.dateRange,
1628
+ finalParams,
1629
+ paramMetadata
1630
+ );
1631
+ rationale = rewriteResponse.rationale;
1632
+ queryId = rewriteResponse.queryId;
1633
+ sqlChanged = finalSql !== input.sql;
1634
+ usedFastPath = true;
1635
+ } catch {
1636
+ }
1637
+ if (!usedFastPath) {
1638
+ const modifiedQuestion = buildModifiedQuestion(
1639
+ input.question,
1640
+ input.sqlModifications,
1641
+ "v2"
1642
+ );
1643
+ finalQuestion = modifiedQuestion;
1644
+ const queryResponse = await client.post(
1645
+ queryEndpoint,
1646
+ {
1647
+ question: modifiedQuestion,
1648
+ previous_sql: input.sql,
1649
+ ...options?.maxRetry ? { max_retry: options.maxRetry } : {},
1650
+ ...tenantSettings ? { tenant_settings: tenantSettings } : {},
1651
+ ...databaseName ? { database: databaseName } : {},
1652
+ ...metadata?.dialect ? { dialect: metadata.dialect } : {}
1653
+ },
1654
+ tenantId,
1655
+ options?.userId,
1656
+ options?.scopes,
1657
+ signal,
1658
+ sessionId
1659
+ );
1660
+ finalSql = queryResponse.sql;
1661
+ paramMetadata = Array.isArray(queryResponse.params) ? queryResponse.params : [];
1662
+ finalParams = queryEngine.mapGeneratedParams(paramMetadata);
1663
+ applyDateRangeOverrides(
1664
+ input.sqlModifications?.dateRange,
1665
+ finalParams,
1666
+ paramMetadata
1667
+ );
1668
+ rationale = queryResponse.rationale;
1669
+ queryId = queryResponse.queryId;
1670
+ sqlChanged = finalSql !== input.sql;
1671
+ }
1517
1672
  } else if (hasSqlMods && !hasCustomSql) {
1518
1673
  const modifiedQuestion = buildModifiedQuestion(
1519
1674
  input.question,
1520
- input.sqlModifications
1675
+ input.sqlModifications,
1676
+ options?.pipeline
1521
1677
  );
1678
+ if (options?.pipeline === "v2") {
1679
+ finalQuestion = modifiedQuestion;
1680
+ }
1522
1681
  const queryResponse = await client.post(
1523
1682
  queryEndpoint,
1524
1683
  {
@@ -1538,6 +1697,13 @@ async function modifyChart(client, queryEngine, input, options, signal) {
1538
1697
  finalSql = queryResponse.sql;
1539
1698
  paramMetadata = Array.isArray(queryResponse.params) ? queryResponse.params : [];
1540
1699
  finalParams = queryEngine.mapGeneratedParams(paramMetadata);
1700
+ if (options?.pipeline === "v2") {
1701
+ applyDateRangeOverrides(
1702
+ input.sqlModifications?.dateRange,
1703
+ finalParams,
1704
+ paramMetadata
1705
+ );
1706
+ }
1541
1707
  rationale = queryResponse.rationale;
1542
1708
  queryId = queryResponse.queryId;
1543
1709
  sqlChanged = finalSql !== input.sql;
@@ -1560,7 +1726,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
1560
1726
  const vizspecResponse = await client.post(
1561
1727
  "/vizspec",
1562
1728
  {
1563
- question: input.question,
1729
+ question: finalQuestion,
1564
1730
  sql: finalSql,
1565
1731
  rationale,
1566
1732
  fields: execution.fields,
@@ -1585,7 +1751,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
1585
1751
  const chartResponse = await client.post(
1586
1752
  "/chart",
1587
1753
  {
1588
- question: input.question,
1754
+ question: finalQuestion,
1589
1755
  sql: finalSql,
1590
1756
  rationale,
1591
1757
  fields: execution.fields,