@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.cjs CHANGED
@@ -1455,21 +1455,39 @@ function anonymizeResults(rows) {
1455
1455
  }
1456
1456
 
1457
1457
  // src/routes/modify.ts
1458
- function buildModifiedQuestion(originalQuestion, modifications) {
1458
+ function buildModifiedQuestion(originalQuestion, modifications, pipeline) {
1459
1459
  const hints = [];
1460
1460
  if (modifications.timeGranularity) {
1461
1461
  hints.push(`group results by ${modifications.timeGranularity}`);
1462
1462
  }
1463
1463
  if (modifications.dateRange) {
1464
- const parts = [];
1465
- if (modifications.dateRange.from) {
1466
- parts.push(`from ${modifications.dateRange.from}`);
1467
- }
1468
- if (modifications.dateRange.to) {
1469
- parts.push(`to ${modifications.dateRange.to}`);
1470
- }
1471
- if (parts.length > 0) {
1472
- hints.push(`filter date range ${parts.join(" ")}`);
1464
+ if (pipeline === "v2") {
1465
+ const from = normalizeDateInput(modifications.dateRange.from);
1466
+ const to = normalizeDateInput(modifications.dateRange.to);
1467
+ if (from && to) {
1468
+ hints.push(
1469
+ `replace any existing date filters with exact date range from ${from} to ${to} (inclusive, do not add extra days)`
1470
+ );
1471
+ } else if (from) {
1472
+ hints.push(
1473
+ `replace any existing date filters with exact start date ${from} (do not shift this date)`
1474
+ );
1475
+ } else if (to) {
1476
+ hints.push(
1477
+ `replace any existing date filters with exact end date ${to} (inclusive, do not add extra days)`
1478
+ );
1479
+ }
1480
+ } else {
1481
+ const parts = [];
1482
+ if (modifications.dateRange.from) {
1483
+ parts.push(`from ${modifications.dateRange.from}`);
1484
+ }
1485
+ if (modifications.dateRange.to) {
1486
+ parts.push(`to ${modifications.dateRange.to}`);
1487
+ }
1488
+ if (parts.length > 0) {
1489
+ hints.push(`filter date range ${parts.join(" ")}`);
1490
+ }
1473
1491
  }
1474
1492
  }
1475
1493
  if (modifications.additionalInstructions) {
@@ -1480,6 +1498,67 @@ function buildModifiedQuestion(originalQuestion, modifications) {
1480
1498
  }
1481
1499
  return `${originalQuestion} (${hints.join(", ")})`;
1482
1500
  }
1501
+ var START_PARAM_KEY_REGEX = /(^|_)(start|from)(_|$)/i;
1502
+ var END_PARAM_KEY_REGEX = /(^|_)(end|to)(_|$)/i;
1503
+ var ISO_DATETIME_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z?$/;
1504
+ var SQL_DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
1505
+ var SQL_DATETIME_RE = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/;
1506
+ function normalizeDateInput(value) {
1507
+ if (!value) return void 0;
1508
+ const trimmed = value.trim();
1509
+ if (!trimmed) return void 0;
1510
+ if (ISO_DATETIME_RE.test(trimmed)) {
1511
+ return trimmed.replace("T", " ").replace(/\.\d+Z?$/, "").replace(/Z$/, "");
1512
+ }
1513
+ return trimmed;
1514
+ }
1515
+ function keyLooksLikeDateBoundary(key, boundary) {
1516
+ return boundary === "start" ? START_PARAM_KEY_REGEX.test(key) : END_PARAM_KEY_REGEX.test(key);
1517
+ }
1518
+ function hasTimeComponent(value) {
1519
+ return typeof value === "string" && /\d{2}:\d{2}:\d{2}/.test(value);
1520
+ }
1521
+ function formatDateOverride(dateValue, boundary, existingValue) {
1522
+ if (SQL_DATE_RE.test(dateValue) && !hasTimeComponent(existingValue)) {
1523
+ return dateValue;
1524
+ }
1525
+ if (SQL_DATE_RE.test(dateValue)) {
1526
+ return `${dateValue} ${boundary === "start" ? "00:00:00" : "23:59:59"}`;
1527
+ }
1528
+ if (SQL_DATETIME_RE.test(dateValue)) {
1529
+ return dateValue;
1530
+ }
1531
+ return dateValue;
1532
+ }
1533
+ function normalizeGeneratedParamKey(param, index) {
1534
+ 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);
1535
+ return nameCandidate.replace(/[{}]/g, "").replace(/(.+):.*$/, "$1").replace(/^[:$]/, "").trim();
1536
+ }
1537
+ function applyDateRangeOverrides(dateRange, params, paramMetadata) {
1538
+ if (!dateRange) return;
1539
+ const from = normalizeDateInput(dateRange.from);
1540
+ const to = normalizeDateInput(dateRange.to);
1541
+ if (!from && !to) return;
1542
+ for (const [key, value] of Object.entries(params)) {
1543
+ if (from && keyLooksLikeDateBoundary(key, "start")) {
1544
+ params[key] = formatDateOverride(from, "start", value);
1545
+ }
1546
+ if (to && keyLooksLikeDateBoundary(key, "end")) {
1547
+ params[key] = formatDateOverride(to, "end", value);
1548
+ }
1549
+ }
1550
+ for (let i = 0; i < paramMetadata.length; i++) {
1551
+ const param = paramMetadata[i];
1552
+ if (!param) continue;
1553
+ const key = normalizeGeneratedParamKey(param, i);
1554
+ if (from && keyLooksLikeDateBoundary(key, "start")) {
1555
+ param.value = formatDateOverride(from, "start", param.value);
1556
+ }
1557
+ if (to && keyLooksLikeDateBoundary(key, "end")) {
1558
+ param.value = formatDateOverride(to, "end", param.value);
1559
+ }
1560
+ }
1561
+ }
1483
1562
  function buildVizHints(modifications) {
1484
1563
  const hints = {};
1485
1564
  if (modifications.kind) {
@@ -1512,6 +1591,9 @@ function stripVizSpecOnlyHints(hints) {
1512
1591
  const { kind: _kind, ...rest } = hints;
1513
1592
  return rest;
1514
1593
  }
1594
+ function isDateRangeOnly(mods) {
1595
+ return !!mods.dateRange && !mods.timeGranularity && !mods.additionalInstructions && !mods.customSql;
1596
+ }
1515
1597
  function resolveTenantId5(client, tenantId) {
1516
1598
  const resolved = tenantId ?? client.getDefaultTenantId();
1517
1599
  if (!resolved) {
@@ -1535,6 +1617,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
1535
1617
  let rationale;
1536
1618
  let queryId;
1537
1619
  let sqlChanged = false;
1620
+ let finalQuestion = input.question;
1538
1621
  const databaseName = input.database ?? queryEngine.getDefaultDatabase();
1539
1622
  if (!databaseName) {
1540
1623
  throw new Error(
@@ -1555,11 +1638,87 @@ async function modifyChart(client, queryEngine, input, options, signal) {
1555
1638
  finalParams = {};
1556
1639
  paramMetadata = [];
1557
1640
  sqlChanged = true;
1641
+ } else if (hasSqlMods && options?.pipeline === "v2" && isDateRangeOnly(input.sqlModifications)) {
1642
+ let usedFastPath = false;
1643
+ try {
1644
+ const rewriteResponse = await client.post(
1645
+ "/v2/rewrite-datefilter",
1646
+ {
1647
+ previous_sql: input.sql,
1648
+ previous_params: input.params ? Object.entries(input.params).map(([name, value]) => ({
1649
+ name,
1650
+ value
1651
+ })) : [],
1652
+ date_range: input.sqlModifications.dateRange,
1653
+ question: input.question,
1654
+ ...tenantSettings ? { tenant_settings: tenantSettings } : {},
1655
+ ...databaseName ? { database: databaseName } : {},
1656
+ ...metadata?.dialect ? { dialect: metadata.dialect } : {}
1657
+ },
1658
+ tenantId,
1659
+ options?.userId,
1660
+ options?.scopes,
1661
+ signal,
1662
+ sessionId
1663
+ );
1664
+ finalSql = rewriteResponse.sql;
1665
+ paramMetadata = Array.isArray(rewriteResponse.params) ? rewriteResponse.params : [];
1666
+ finalParams = queryEngine.mapGeneratedParams(paramMetadata);
1667
+ applyDateRangeOverrides(
1668
+ input.sqlModifications?.dateRange,
1669
+ finalParams,
1670
+ paramMetadata
1671
+ );
1672
+ rationale = rewriteResponse.rationale;
1673
+ queryId = rewriteResponse.queryId;
1674
+ sqlChanged = finalSql !== input.sql;
1675
+ usedFastPath = true;
1676
+ } catch {
1677
+ }
1678
+ if (!usedFastPath) {
1679
+ const modifiedQuestion = buildModifiedQuestion(
1680
+ input.question,
1681
+ input.sqlModifications,
1682
+ "v2"
1683
+ );
1684
+ finalQuestion = modifiedQuestion;
1685
+ const queryResponse = await client.post(
1686
+ queryEndpoint,
1687
+ {
1688
+ question: modifiedQuestion,
1689
+ previous_sql: input.sql,
1690
+ ...options?.maxRetry ? { max_retry: options.maxRetry } : {},
1691
+ ...tenantSettings ? { tenant_settings: tenantSettings } : {},
1692
+ ...databaseName ? { database: databaseName } : {},
1693
+ ...metadata?.dialect ? { dialect: metadata.dialect } : {}
1694
+ },
1695
+ tenantId,
1696
+ options?.userId,
1697
+ options?.scopes,
1698
+ signal,
1699
+ sessionId
1700
+ );
1701
+ finalSql = queryResponse.sql;
1702
+ paramMetadata = Array.isArray(queryResponse.params) ? queryResponse.params : [];
1703
+ finalParams = queryEngine.mapGeneratedParams(paramMetadata);
1704
+ applyDateRangeOverrides(
1705
+ input.sqlModifications?.dateRange,
1706
+ finalParams,
1707
+ paramMetadata
1708
+ );
1709
+ rationale = queryResponse.rationale;
1710
+ queryId = queryResponse.queryId;
1711
+ sqlChanged = finalSql !== input.sql;
1712
+ }
1558
1713
  } else if (hasSqlMods && !hasCustomSql) {
1559
1714
  const modifiedQuestion = buildModifiedQuestion(
1560
1715
  input.question,
1561
- input.sqlModifications
1716
+ input.sqlModifications,
1717
+ options?.pipeline
1562
1718
  );
1719
+ if (options?.pipeline === "v2") {
1720
+ finalQuestion = modifiedQuestion;
1721
+ }
1563
1722
  const queryResponse = await client.post(
1564
1723
  queryEndpoint,
1565
1724
  {
@@ -1579,6 +1738,13 @@ async function modifyChart(client, queryEngine, input, options, signal) {
1579
1738
  finalSql = queryResponse.sql;
1580
1739
  paramMetadata = Array.isArray(queryResponse.params) ? queryResponse.params : [];
1581
1740
  finalParams = queryEngine.mapGeneratedParams(paramMetadata);
1741
+ if (options?.pipeline === "v2") {
1742
+ applyDateRangeOverrides(
1743
+ input.sqlModifications?.dateRange,
1744
+ finalParams,
1745
+ paramMetadata
1746
+ );
1747
+ }
1582
1748
  rationale = queryResponse.rationale;
1583
1749
  queryId = queryResponse.queryId;
1584
1750
  sqlChanged = finalSql !== input.sql;
@@ -1601,7 +1767,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
1601
1767
  const vizspecResponse = await client.post(
1602
1768
  "/vizspec",
1603
1769
  {
1604
- question: input.question,
1770
+ question: finalQuestion,
1605
1771
  sql: finalSql,
1606
1772
  rationale,
1607
1773
  fields: execution.fields,
@@ -1626,7 +1792,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
1626
1792
  const chartResponse = await client.post(
1627
1793
  "/chart",
1628
1794
  {
1629
- question: input.question,
1795
+ question: finalQuestion,
1630
1796
  sql: finalSql,
1631
1797
  rationale,
1632
1798
  fields: execution.fields,