yamchart 0.8.2 → 0.8.4

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.
Files changed (61) hide show
  1. package/dist/{advisor-3V6WKALO.js → advisor-CSVLJFOG.js} +10 -10
  2. package/dist/{chunk-77CBXDCO.js → chunk-5N3FYFBV.js} +72 -1
  3. package/dist/chunk-5N3FYFBV.js.map +1 -0
  4. package/dist/{chunk-T76DI6OA.js → chunk-QLBCPJDL.js} +4 -4
  5. package/dist/{chunk-KP4CYPBL.js → chunk-RYTMXP2R.js} +49 -7
  6. package/dist/chunk-RYTMXP2R.js.map +1 -0
  7. package/dist/{chunk-HRF7QVK5.js → chunk-VTLZAE3C.js} +2 -2
  8. package/dist/{chunk-GX2PNKES.js → chunk-VXDZEBAN.js} +21 -7
  9. package/dist/chunk-VXDZEBAN.js.map +1 -0
  10. package/dist/{connection-utils-MI7RM5BP.js → connection-utils-2SZAG2QM.js} +4 -4
  11. package/dist/{describe-46XBIND7.js → describe-ELE7CAVA.js} +5 -5
  12. package/dist/{dev-IMKOBPDZ.js → dev-AWJ7TF6G.js} +49 -18
  13. package/dist/dev-AWJ7TF6G.js.map +1 -0
  14. package/dist/dist-2OQOI2PU.js +54 -0
  15. package/dist/{dist-ONU5AKOH.js → dist-E2PVGIPT.js} +4 -2
  16. package/dist/{dist-25RTZO4E.js → dist-GVNWQXFR.js} +2 -2
  17. package/dist/index.js +34 -25
  18. package/dist/index.js.map +1 -1
  19. package/dist/{init-UYQE5DPU.js → init-GVBYCLJT.js} +14 -1
  20. package/dist/init-GVBYCLJT.js.map +1 -0
  21. package/dist/public/assets/{EventManagement-DSew47oL.js → EventManagement-DmRy5bu3.js} +1 -1
  22. package/dist/public/assets/{LoginPage-BwFMXS0X.js → LoginPage-B2bo8Eck.js} +1 -1
  23. package/dist/public/assets/{PublicViewer-70ErTigq.js → PublicViewer-B_3K2MkZ.js} +1 -1
  24. package/dist/public/assets/{SetupWizard-CR7XCMkq.js → SetupWizard-utnbmxeP.js} +1 -1
  25. package/dist/public/assets/{ShareManagement-B2ZU0Fdy.js → ShareManagement-6iYAjCrr.js} +1 -1
  26. package/dist/public/assets/{UserManagement-CHRB-6uy.js → UserManagement-DAOq9eUf.js} +1 -1
  27. package/dist/public/assets/{index-DcNtdUoV.js → index-BbSrYtxR.js} +3 -3
  28. package/dist/public/assets/{index.es-BC82iFuu.js → index.es-C-5Ej3mu.js} +1 -1
  29. package/dist/public/assets/{jspdf.es.min-DojRcwGj.js → jspdf.es.min-B-lLjljE.js} +3 -3
  30. package/dist/public/index.html +1 -1
  31. package/dist/{query-Q3B4TQTZ.js → query-P4TSQES4.js} +4 -4
  32. package/dist/{sample-PEHRM3TN.js → sample-3VDU6ZAV.js} +4 -4
  33. package/dist/{search-NBJHS4TZ.js → search-L5QA64T7.js} +5 -5
  34. package/dist/{source-resolver-2DIK3MK4.js → source-resolver-TTHGNPBK.js} +5 -5
  35. package/dist/source-resolver-TTHGNPBK.js.map +1 -0
  36. package/dist/{sync-warehouse-UGTZCZ7J.js → sync-warehouse-KGT6XSXI.js} +9 -9
  37. package/dist/{tables-ZERITKTS.js → tables-IG4RYPCG.js} +5 -5
  38. package/dist/templates/default/docs/yamchart-reference.md +50 -4
  39. package/dist/templates/default/yamchart.yaml +10 -0
  40. package/dist/templates/empty/yamchart.yaml +10 -0
  41. package/dist/{test-ME2Q6CSR.js → test-SN75DCIN.js} +4 -4
  42. package/package.json +4 -4
  43. package/dist/chunk-77CBXDCO.js.map +0 -1
  44. package/dist/chunk-GX2PNKES.js.map +0 -1
  45. package/dist/chunk-KP4CYPBL.js.map +0 -1
  46. package/dist/dev-IMKOBPDZ.js.map +0 -1
  47. package/dist/init-UYQE5DPU.js.map +0 -1
  48. /package/dist/{advisor-3V6WKALO.js.map → advisor-CSVLJFOG.js.map} +0 -0
  49. /package/dist/{chunk-T76DI6OA.js.map → chunk-QLBCPJDL.js.map} +0 -0
  50. /package/dist/{chunk-HRF7QVK5.js.map → chunk-VTLZAE3C.js.map} +0 -0
  51. /package/dist/{connection-utils-MI7RM5BP.js.map → connection-utils-2SZAG2QM.js.map} +0 -0
  52. /package/dist/{describe-46XBIND7.js.map → describe-ELE7CAVA.js.map} +0 -0
  53. /package/dist/{dist-ONU5AKOH.js.map → dist-2OQOI2PU.js.map} +0 -0
  54. /package/dist/{source-resolver-2DIK3MK4.js.map → dist-E2PVGIPT.js.map} +0 -0
  55. /package/dist/{dist-25RTZO4E.js.map → dist-GVNWQXFR.js.map} +0 -0
  56. /package/dist/{query-Q3B4TQTZ.js.map → query-P4TSQES4.js.map} +0 -0
  57. /package/dist/{sample-PEHRM3TN.js.map → sample-3VDU6ZAV.js.map} +0 -0
  58. /package/dist/{search-NBJHS4TZ.js.map → search-L5QA64T7.js.map} +0 -0
  59. /package/dist/{sync-warehouse-UGTZCZ7J.js.map → sync-warehouse-KGT6XSXI.js.map} +0 -0
  60. /package/dist/{tables-ZERITKTS.js.map → tables-IG4RYPCG.js.map} +0 -0
  61. /package/dist/{test-ME2Q6CSR.js.map → test-SN75DCIN.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createConnector,
3
3
  resolveConnection
4
- } from "./chunk-GX2PNKES.js";
4
+ } from "./chunk-VXDZEBAN.js";
5
5
  import {
6
6
  detail,
7
7
  error,
@@ -10,8 +10,8 @@ import {
10
10
  success,
11
11
  warning
12
12
  } from "./chunk-HJVVHYVN.js";
13
- import "./chunk-KP4CYPBL.js";
14
- import "./chunk-77CBXDCO.js";
13
+ import "./chunk-RYTMXP2R.js";
14
+ import "./chunk-5N3FYFBV.js";
15
15
  import "./chunk-UND73EOB.js";
16
16
  import "./chunk-DGUM43GV.js";
17
17
 
@@ -44,7 +44,7 @@ async function getDbtProjectPath(projectDir, override) {
44
44
  return null;
45
45
  }
46
46
  async function buildContext(projectDir, options) {
47
- const { parseModelMetadata } = await import("./dist-ONU5AKOH.js");
47
+ const { parseModelMetadata } = await import("./dist-E2PVGIPT.js");
48
48
  const modelsDir = join(projectDir, "models");
49
49
  const yamchartModels = [];
50
50
  try {
@@ -140,7 +140,7 @@ async function buildContext(projectDir, options) {
140
140
  };
141
141
  if (dbtPath) {
142
142
  try {
143
- const { detectConventions, listDbtModels } = await import("./dist-25RTZO4E.js");
143
+ const { detectConventions, listDbtModels } = await import("./dist-GVNWQXFR.js");
144
144
  const dbtProjectYml = await readFile(join(dbtPath, "dbt_project.yml"), "utf-8");
145
145
  const dbtConfig = parseYaml(dbtProjectYml);
146
146
  const conventions = await detectConventions(dbtPath);
@@ -236,7 +236,7 @@ async function runAdvisor(projectDir, questionOrMode, options) {
236
236
  `warehouse: ${context.warehouse ? `connected (${context.warehouse.connectionType})` : "not connected"}`
237
237
  );
238
238
  console.log("");
239
- const { AdvisorAgent, AnthropicProvider, buildModelPath } = await import("./dist-25RTZO4E.js");
239
+ const { AdvisorAgent, AnthropicProvider, buildModelPath } = await import("./dist-GVNWQXFR.js");
240
240
  const provider = new AnthropicProvider(apiKey);
241
241
  const agent = new AdvisorAgent(provider);
242
242
  const isAudit = questionOrMode === "audit";
@@ -281,7 +281,7 @@ ${pc.bold(`[${i + 1}]`)} ${formatProposal(proposal, context.dbt.conventions, bui
281
281
  spin2.stop();
282
282
  console.log(result.response);
283
283
  if (result.proposals.length > 0) {
284
- const { buildModelPath: bmp } = await import("./dist-25RTZO4E.js");
284
+ const { buildModelPath: bmp } = await import("./dist-GVNWQXFR.js");
285
285
  for (const proposal of result.proposals) {
286
286
  console.log(
287
287
  `
@@ -322,7 +322,7 @@ ${formatProposal(proposal, context.dbt.conventions, bmp)}`
322
322
  conversationHistory.length = 0;
323
323
  conversationHistory.push(...result.messages);
324
324
  if (result.proposals.length > 0) {
325
- const { buildModelPath: bmp } = await import("./dist-25RTZO4E.js");
325
+ const { buildModelPath: bmp } = await import("./dist-GVNWQXFR.js");
326
326
  for (const proposal of result.proposals) {
327
327
  console.log(
328
328
  `
@@ -340,7 +340,7 @@ async function offerApply(context, proposals) {
340
340
  return;
341
341
  }
342
342
  const { confirm } = await import("@inquirer/prompts");
343
- const { writeDbtModel, buildModelPath, formatModelSql, updateSchemaYml } = await import("./dist-25RTZO4E.js");
343
+ const { writeDbtModel, buildModelPath, formatModelSql, updateSchemaYml } = await import("./dist-GVNWQXFR.js");
344
344
  for (const proposal of proposals) {
345
345
  console.log("");
346
346
  const shouldApply = await confirm({
@@ -379,4 +379,4 @@ async function offerApply(context, proposals) {
379
379
  export {
380
380
  runAdvisor
381
381
  };
382
- //# sourceMappingURL=advisor-3V6WKALO.js.map
382
+ //# sourceMappingURL=advisor-CSVLJFOG.js.map
@@ -1329,6 +1329,76 @@ function resolveSnowflakeAuth(connection) {
1329
1329
  throw new Error(`Auth type "${auth.type}" not yet implemented for Snowflake`);
1330
1330
  }
1331
1331
 
1332
+ // ../../packages/query/dist/connectors/reconnecting.js
1333
+ var CONNECTION_ERROR_PATTERNS = [
1334
+ "terminated connection",
1335
+ "socket hang up",
1336
+ "connection reset",
1337
+ "ECONNRESET",
1338
+ "ECONNREFUSED",
1339
+ "ETIMEDOUT",
1340
+ "connection lost",
1341
+ "gone away",
1342
+ // MySQL: "server has gone away"
1343
+ "not connected"
1344
+ ];
1345
+ function isConnectionError(error) {
1346
+ const message = error instanceof Error ? error.message : String(error);
1347
+ const lower = message.toLowerCase();
1348
+ return CONNECTION_ERROR_PATTERNS.some((pattern) => lower.includes(pattern.toLowerCase()));
1349
+ }
1350
+ var ReconnectingConnector = class {
1351
+ inner;
1352
+ constructor(inner) {
1353
+ this.inner = inner;
1354
+ }
1355
+ async connect() {
1356
+ return this.inner.connect();
1357
+ }
1358
+ async disconnect() {
1359
+ return this.inner.disconnect();
1360
+ }
1361
+ isConnected() {
1362
+ return this.inner.isConnected();
1363
+ }
1364
+ async execute(sql) {
1365
+ await this.ensureConnected();
1366
+ try {
1367
+ return await this.inner.execute(sql);
1368
+ } catch (err) {
1369
+ if (isConnectionError(err)) {
1370
+ await this.reconnect();
1371
+ return this.inner.execute(sql);
1372
+ }
1373
+ throw err;
1374
+ }
1375
+ }
1376
+ async explain(sql) {
1377
+ await this.ensureConnected();
1378
+ try {
1379
+ return await this.inner.explain(sql);
1380
+ } catch (err) {
1381
+ if (isConnectionError(err)) {
1382
+ await this.reconnect();
1383
+ return this.inner.explain(sql);
1384
+ }
1385
+ throw err;
1386
+ }
1387
+ }
1388
+ async ensureConnected() {
1389
+ if (!this.inner.isConnected()) {
1390
+ await this.reconnect();
1391
+ }
1392
+ }
1393
+ async reconnect() {
1394
+ try {
1395
+ await this.inner.disconnect();
1396
+ } catch {
1397
+ }
1398
+ await this.inner.connect();
1399
+ }
1400
+ };
1401
+
1332
1402
  // ../../packages/query/dist/connectors/index.js
1333
1403
  function serializeDateValue(value) {
1334
1404
  if (value.getUTCHours() === 0 && value.getUTCMinutes() === 0 && value.getUTCSeconds() === 0 && value.getUTCMilliseconds() === 0) {
@@ -1516,6 +1586,7 @@ export {
1516
1586
  resolvePostgresAuth,
1517
1587
  resolveMySQLAuth,
1518
1588
  resolveSnowflakeAuth,
1589
+ ReconnectingConnector,
1519
1590
  serializeDateValue,
1520
1591
  expandThis,
1521
1592
  runAssertion,
@@ -1524,4 +1595,4 @@ export {
1524
1595
  checkSchema,
1525
1596
  VERSION
1526
1597
  };
1527
- //# sourceMappingURL=chunk-77CBXDCO.js.map
1598
+ //# sourceMappingURL=chunk-5N3FYFBV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../packages/query/src/parser.ts","../../../packages/query/src/presets.ts","../../../packages/query/src/template.ts","../../../packages/query/src/compiler.ts","../../../packages/query/src/connectors/duckdb.ts","../../../packages/query/src/connectors/postgres.ts","../../../packages/query/src/connectors/mysql.ts","../../../packages/query/src/connectors/sqlite.ts","../../../packages/query/src/connectors/snowflake.ts","../../../packages/query/src/connectors/auth.ts","../../../packages/query/src/connectors/reconnecting.ts","../../../packages/query/src/connectors/index.ts","../../../packages/query/src/test-runner.ts","../../../packages/query/src/index.ts"],"sourcesContent":["import type { ModelMetadata, ModelParam, ReturnColumn } from '@yamchart/schema';\n\nexport interface ParsedModel {\n metadata: ModelMetadata;\n sql: string;\n}\n\ninterface ParseResult extends ModelMetadata {\n sql: string;\n}\n\n/**\n * Parse model metadata from SQL comments.\n *\n * Supports:\n * - @name: model_name\n * - @description: text\n * - @owner: team-name\n * - @tags: [tag1, tag2]\n * - @param name: type = default {option1, option2}\n * - @returns: (multiline)\n * - @tests: (multiline)\n */\nexport function parseModelMetadata(sql: string): ParseResult {\n const lines = sql.split('\\n');\n const metadataLines: string[] = [];\n const sqlLines: string[] = [];\n\n let inMetadata = true;\n let inMultiline: 'returns' | 'tests' | null = null;\n\n for (const line of lines) {\n const trimmed = line.trim();\n\n // Check if this is a metadata comment\n if (trimmed.startsWith('-- @') || (inMultiline && trimmed.startsWith('--'))) {\n metadataLines.push(trimmed);\n inMetadata = true;\n } else if (trimmed.startsWith('--') && inMetadata && metadataLines.length > 0) {\n // Continuation of metadata block\n metadataLines.push(trimmed);\n } else if (trimmed === '' && inMetadata) {\n // Empty line in metadata section, keep going\n continue;\n } else {\n // SQL content\n inMetadata = false;\n sqlLines.push(line);\n }\n }\n\n // Parse metadata\n const metadata = parseMetadataLines(metadataLines);\n\n if (!metadata.name) {\n throw new Error('Model must have a @name');\n }\n\n return {\n ...metadata,\n name: metadata.name,\n sql: sqlLines.join('\\n').trim(),\n };\n}\n\nfunction parseMetadataLines(lines: string[]): Partial<ModelMetadata> & { sql?: string } {\n const result: Partial<ModelMetadata> = {};\n const params: ModelParam[] = [];\n const returns: ReturnColumn[] = [];\n const tests: string[] = [];\n\n let currentMultiline: 'returns' | 'tests' | null = null;\n\n for (const line of lines) {\n const content = line.replace(/^--\\s*/, '').trim();\n\n // Check for multiline content (indented with -)\n if (currentMultiline && content.startsWith('- ')) {\n const itemContent = content.slice(2).trim();\n\n if (currentMultiline === 'returns') {\n const returnCol = parseReturnColumn(itemContent);\n if (returnCol) returns.push(returnCol);\n } else if (currentMultiline === 'tests') {\n tests.push(itemContent);\n }\n continue;\n }\n\n // Check for new directive\n if (content.startsWith('@')) {\n currentMultiline = null;\n\n if (content.startsWith('@name:')) {\n result.name = content.slice(6).trim();\n } else if (content.startsWith('@description:')) {\n result.description = content.slice(13).trim();\n } else if (content.startsWith('@owner:')) {\n result.owner = content.slice(7).trim();\n } else if (content.startsWith('@tags:')) {\n result.tags = parseTags(content.slice(6).trim());\n } else if (content.startsWith('@param')) {\n const param = parseParam(content.slice(6).trim());\n if (param) params.push(param);\n } else if (content.startsWith('@returns:')) {\n currentMultiline = 'returns';\n } else if (content.startsWith('@tests:')) {\n currentMultiline = 'tests';\n }\n }\n }\n\n if (params.length > 0) result.params = params;\n if (returns.length > 0) result.returns = returns;\n if (tests.length > 0) result.tests = tests;\n\n return result;\n}\n\nfunction parseTags(input: string): string[] {\n // Parse [tag1, tag2, tag3]\n const match = input.match(/\\[(.*)\\]/);\n if (!match?.[1]) return [];\n return match[1].split(',').map(t => t.trim());\n}\n\nfunction parseParam(input: string): ModelParam | null {\n // Parse: name: type = default {option1, option2}\n // Or: name: type = default\n // Or: name: type\n\n const match = input.match(/^(\\w+):\\s*(\\w+(?:\\[\\])?)\\s*(?:=\\s*([^{]+))?\\s*(?:\\{([^}]+)\\})?/);\n if (!match) return null;\n\n const [, name, type, defaultValue, options] = match;\n if (!name || !type) return null;\n\n const param: ModelParam = {\n name: name.trim(),\n type: type.trim() as ModelParam['type'],\n };\n\n if (defaultValue) {\n param.default = defaultValue.trim();\n }\n\n if (options) {\n param.options = options.split(',').map(o => o.trim());\n }\n\n return param;\n}\n\nfunction parseReturnColumn(input: string): ReturnColumn | null {\n // Parse: name: type -- description\n // Or: name: type\n\n const match = input.match(/^(\\w+):\\s*(\\w+)\\s*(?:--\\s*(.+))?/);\n if (!match) return null;\n\n const [, name, type, description] = match;\n if (!name || !type) return null;\n\n const col: ReturnColumn = {\n name: name.trim(),\n type: type.trim(),\n };\n\n if (description) {\n col.description = description.trim();\n }\n\n return col;\n}\n","import {\n subDays,\n subWeeks,\n subMonths,\n subYears,\n subQuarters,\n addDays,\n addWeeks,\n addMonths,\n addYears,\n addQuarters,\n startOfDay,\n startOfWeek,\n startOfYear,\n startOfMonth,\n startOfQuarter,\n endOfDay,\n endOfWeek,\n endOfMonth,\n endOfQuarter,\n endOfYear,\n differenceInDays,\n parseISO,\n format,\n} from 'date-fns';\n\nexport interface DateRange {\n start_date: string;\n end_date: string;\n}\n\nexport interface CustomDateRange {\n type: 'custom';\n start: string;\n end: string;\n}\n\n/**\n * Check if a value is a custom date range object.\n */\nexport function isCustomDateRange(value: unknown): value is CustomDateRange {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'type' in value &&\n (value as CustomDateRange).type === 'custom' &&\n 'start' in value &&\n 'end' in value\n );\n}\n\n/**\n * Expand a custom date range into start_date and end_date.\n */\nexport function expandCustomDateRange(range: CustomDateRange): DateRange {\n return {\n start_date: range.start,\n end_date: range.end,\n };\n}\n\nexport const DATE_PRESETS = [\n 'today',\n 'yesterday',\n 'last_7_days',\n 'last_30_days',\n 'last_90_days',\n 'last_12_months',\n 'year_to_date',\n 'month_to_date',\n 'quarter_to_date',\n 'previous_month',\n 'previous_quarter',\n 'previous_year',\n] as const;\n\nexport type DatePreset = (typeof DATE_PRESETS)[number];\n\nconst DATE_FORMAT = 'yyyy-MM-dd';\n\nfunction formatDate(date: Date): string {\n return format(date, DATE_FORMAT);\n}\n\n/**\n * Expand a date preset into start_date and end_date.\n * Returns null if preset is not recognized.\n */\nexport function expandDatePreset(preset: string): DateRange | null {\n const now = new Date();\n const today = formatDate(now);\n\n switch (preset) {\n case 'today':\n return {\n start_date: today,\n end_date: today,\n };\n\n case 'yesterday': {\n const yesterday = formatDate(subDays(now, 1));\n return {\n start_date: yesterday,\n end_date: yesterday,\n };\n }\n\n case 'last_7_days': {\n const yesterday = formatDate(subDays(now, 1));\n return {\n start_date: formatDate(subDays(now, 7)),\n end_date: yesterday,\n };\n }\n\n case 'last_30_days': {\n const yesterday = formatDate(subDays(now, 1));\n return {\n start_date: formatDate(subDays(now, 30)),\n end_date: yesterday,\n };\n }\n\n case 'last_90_days': {\n const yesterday = formatDate(subDays(now, 1));\n return {\n start_date: formatDate(subDays(now, 90)),\n end_date: yesterday,\n };\n }\n\n case 'last_12_months': {\n const yesterday = formatDate(subDays(now, 1));\n return {\n start_date: formatDate(subMonths(now, 12)),\n end_date: yesterday,\n };\n }\n\n case 'year_to_date':\n return {\n start_date: formatDate(startOfYear(now)),\n end_date: today,\n };\n\n case 'month_to_date':\n return {\n start_date: formatDate(startOfMonth(now)),\n end_date: today,\n };\n\n case 'quarter_to_date':\n return {\n start_date: formatDate(startOfQuarter(now)),\n end_date: today,\n };\n\n case 'previous_month': {\n const lastMonth = subMonths(now, 1);\n return {\n start_date: formatDate(startOfMonth(lastMonth)),\n end_date: formatDate(endOfMonth(lastMonth)),\n };\n }\n\n case 'previous_quarter': {\n const lastQuarter = subMonths(now, 3);\n return {\n start_date: formatDate(startOfQuarter(lastQuarter)),\n end_date: formatDate(endOfQuarter(lastQuarter)),\n };\n }\n\n case 'previous_year': {\n const lastYear = subYears(now, 1);\n return {\n start_date: formatDate(startOfYear(lastYear)),\n end_date: formatDate(endOfYear(lastYear)),\n };\n }\n\n default:\n return null;\n }\n}\n\n/**\n * Compute the equivalent previous period for a given date range.\n * Uses semantic shifting for named presets, day-length shifting for custom ranges.\n */\nexport function computePreviousPeriod(\n startDate: string,\n endDate: string,\n presetName?: string\n): DateRange {\n const start = parseISO(startDate);\n const end = parseISO(endDate);\n\n switch (presetName) {\n case 'today':\n case 'yesterday': {\n return {\n start_date: formatDate(subDays(start, 1)),\n end_date: formatDate(subDays(end, 1)),\n };\n }\n case 'last_7_days': {\n return {\n start_date: formatDate(subDays(start, 7)),\n end_date: formatDate(subDays(end, 7)),\n };\n }\n case 'last_30_days': {\n return {\n start_date: formatDate(subDays(start, 30)),\n end_date: formatDate(subDays(end, 30)),\n };\n }\n case 'last_90_days': {\n return {\n start_date: formatDate(subDays(start, 90)),\n end_date: formatDate(subDays(end, 90)),\n };\n }\n case 'last_12_months':\n case 'last_365_days': {\n return {\n start_date: formatDate(subMonths(start, 12)),\n end_date: formatDate(subMonths(end, 12)),\n };\n }\n case 'year_to_date': {\n return {\n start_date: formatDate(subYears(start, 1)),\n end_date: formatDate(subYears(end, 1)),\n };\n }\n case 'month_to_date': {\n return {\n start_date: formatDate(subMonths(start, 1)),\n end_date: formatDate(subMonths(end, 1)),\n };\n }\n case 'quarter_to_date': {\n return {\n start_date: formatDate(subQuarters(start, 1)),\n end_date: formatDate(subQuarters(end, 1)),\n };\n }\n case 'previous_month': {\n const shifted = subMonths(start, 1);\n return {\n start_date: formatDate(startOfMonth(shifted)),\n end_date: formatDate(endOfMonth(shifted)),\n };\n }\n case 'previous_quarter': {\n const shifted = subQuarters(start, 1);\n return {\n start_date: formatDate(startOfQuarter(shifted)),\n end_date: formatDate(endOfQuarter(shifted)),\n };\n }\n case 'previous_year': {\n const shifted = subYears(start, 1);\n return {\n start_date: formatDate(startOfYear(shifted)),\n end_date: formatDate(endOfYear(shifted)),\n };\n }\n default: {\n // Custom range: shift back by the range length in days\n const days = differenceInDays(end, start);\n return {\n start_date: formatDate(subDays(start, days)),\n end_date: formatDate(subDays(end, days)),\n };\n }\n }\n}\n\n/**\n * Format a date range as a human-readable label.\n * Same year: \"Jan 17 – Feb 16\"\n * Cross year: \"Dec 18, 2025 – Jan 17, 2026\"\n * Single day: \"Feb 16\"\n */\nexport function formatPeriodLabel(startDate: string, endDate: string): string {\n const start = parseISO(startDate);\n const end = parseISO(endDate);\n\n if (startDate === endDate) {\n return format(start, 'MMM d');\n }\n\n const startYear = start.getFullYear();\n const endYear = end.getFullYear();\n\n if (startYear === endYear) {\n return `${format(start, 'MMM d')} – ${format(end, 'MMM d')}`;\n }\n\n return `${format(start, 'MMM d, yyyy')} – ${format(end, 'MMM d, yyyy')}`;\n}\n\n/**\n * Check if a string is a known date preset.\n */\nexport function isDatePreset(value: string): value is DatePreset {\n return DATE_PRESETS.includes(value as DatePreset);\n}\n\n// --- Relative date range support ---\n\nexport interface RelativeDateRange {\n type: 'relative';\n direction: 'previous' | 'current' | 'next';\n value?: number;\n unit: 'day' | 'week' | 'month' | 'quarter' | 'year';\n includeToday?: boolean;\n}\n\n/**\n * Check if a value is a relative date range object.\n */\nexport function isRelativeDateRange(value: unknown): value is RelativeDateRange {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'type' in value &&\n (value as RelativeDateRange).type === 'relative'\n );\n}\n\n/**\n * Expand a relative date range into start_date and end_date.\n */\nexport function expandRelativeDateRange(rel: RelativeDateRange): DateRange {\n const now = new Date();\n const today = startOfDay(now);\n\n if (rel.direction === 'current') {\n switch (rel.unit) {\n case 'day':\n return { start_date: formatDate(today), end_date: formatDate(today) };\n case 'week':\n return {\n start_date: formatDate(startOfWeek(today, { weekStartsOn: 1 })),\n end_date: formatDate(endOfWeek(today, { weekStartsOn: 1 })),\n };\n case 'month':\n return { start_date: formatDate(startOfMonth(today)), end_date: formatDate(endOfMonth(today)) };\n case 'quarter':\n return { start_date: formatDate(startOfQuarter(today)), end_date: formatDate(endOfQuarter(today)) };\n case 'year':\n return { start_date: formatDate(startOfYear(today)), end_date: formatDate(endOfYear(today)) };\n }\n }\n\n const n = rel.value ?? 1;\n\n if (rel.direction === 'previous') {\n const end = rel.includeToday ? today : subDays(today, 1);\n const shiftFns = { day: subDays, week: subWeeks, month: subMonths, quarter: subQuarters, year: subYears };\n const start = shiftFns[rel.unit](rel.includeToday ? today : today, n);\n return {\n start_date: formatDate(start < end ? start : end),\n end_date: formatDate(start < end ? end : start),\n };\n }\n\n // next\n const start = rel.includeToday ? today : addDays(today, 1);\n const shiftFns = { day: addDays, week: addWeeks, month: addMonths, quarter: addQuarters, year: addYears };\n const end = shiftFns[rel.unit](start, n);\n return {\n start_date: formatDate(start < end ? start : end),\n end_date: formatDate(start < end ? end : start),\n };\n}\n","import nunjucks from 'nunjucks';\n\n// Configure Nunjucks environment\nconst env = new nunjucks.Environment(null, {\n autoescape: false, // SQL doesn't need HTML escaping\n throwOnUndefined: false, // user.x may be undefined for RLS\n});\n\n/**\n * Array subclass that renders as SQL-safe quoted, comma-separated values.\n * Used for multi_select parameters so {{ param }} produces 'val1', 'val2'.\n * Remains iterable for {% for item in param %} loops.\n */\nexport class SqlList extends Array<string> {\n override toString(): string {\n return this.map(v => `'${String(v).replace(/'/g, \"''\")}'`).join(', ');\n }\n}\n\nexport interface TemplateContext {\n [key: string]: unknown;\n ref: (name: string) => string;\n}\n\nexport interface ModelRefs {\n [modelName: string]: string; // model name -> table/subquery\n}\n\n/**\n * Create a template context with parameters and ref() function.\n * Array values are wrapped in SqlList so {{ param }} auto-quotes for SQL IN clauses.\n */\nexport function createTemplateContext(\n params: Record<string, unknown>,\n refs: ModelRefs = {},\n userContext?: Record<string, unknown>\n): TemplateContext {\n const processed: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(params)) {\n if (Array.isArray(value)) {\n const list = new SqlList(...value);\n processed[key] = list;\n } else {\n processed[key] = value;\n }\n }\n\n return {\n ...processed,\n user: userContext ?? {},\n ref: (name: string): string => {\n const resolved = refs[name];\n if (resolved === undefined) {\n throw new Error(`Unknown model reference: ${name}`);\n }\n return resolved;\n },\n };\n}\n\n/**\n * Render a SQL template with the given context.\n */\nexport function renderTemplate(\n template: string,\n context: Record<string, unknown>\n): string {\n const rendered = env.renderString(template, context);\n // Clean up extra whitespace from conditionals\n return rendered\n .split('\\n')\n .map(line => line.trimEnd())\n .filter((line, i, arr) => {\n // Remove consecutive blank lines\n if (line === '' && arr[i - 1] === '') return false;\n return true;\n })\n .join('\\n')\n .trim();\n}\n\n/**\n * Check if a template contains a specific variable reference.\n */\nexport function templateHasVariable(template: string, varName: string): boolean {\n // Match {{ varName }} or {{ varName | filter }}\n const regex = new RegExp(`\\\\{\\\\{\\\\s*${varName}(?:\\\\s*\\\\|[^}]+)?\\\\s*\\\\}\\\\}`, 'g');\n return regex.test(template);\n}\n\n/**\n * Extract all variable names from a template.\n */\nexport function extractTemplateVariables(template: string): string[] {\n const variables = new Set<string>();\n\n // Match {{ variable }} or {{ variable | filter }}\n const regex = /\\{\\{\\s*(\\w+)(?:\\s*\\|[^}]+)?\\s*\\}\\}/g;\n let match;\n\n while ((match = regex.exec(template)) !== null) {\n const varName = match[1];\n // Exclude built-in functions\n if (varName && varName !== 'ref' && varName !== 'loop') {\n variables.add(varName);\n }\n }\n\n return Array.from(variables);\n}\n","import type { Chart, ModelMetadata } from '@yamchart/schema';\nimport { renderTemplate, createTemplateContext, type ModelRefs } from './template.js';\nimport { expandDatePreset, isDatePreset, isCustomDateRange, expandCustomDateRange, isRelativeDateRange, expandRelativeDateRange } from './presets.js';\nimport { createHash } from 'node:crypto';\nimport { format } from 'date-fns';\n\n/**\n * Resolve dynamic default values like current_date() to actual values\n */\nfunction resolveDynamicDefault(value: unknown): unknown {\n if (typeof value !== 'string') return value;\n\n const trimmed = value.trim().toLowerCase();\n\n // Handle current_date() and similar SQL date functions\n if (trimmed === 'current_date()' || trimmed === 'current_date' || trimmed === 'now()') {\n return format(new Date(), 'yyyy-MM-dd');\n }\n\n // Handle date arithmetic like current_date() - interval '1 month'\n // For now, just return today's date for any current_date reference\n if (trimmed.includes('current_date')) {\n return format(new Date(), 'yyyy-MM-dd');\n }\n\n return value;\n}\n\nexport interface CompiledQuery {\n sql: string;\n params: Record<string, unknown>;\n cacheKey: string;\n chartName: string;\n}\n\nexport interface CompilerConfig {\n models: Record<string, { metadata: ModelMetadata; sql: string }>;\n refs: ModelRefs;\n}\n\nexport class QueryCompiler {\n private models: Map<string, { metadata: ModelMetadata; sql: string }>;\n private refs: ModelRefs;\n\n constructor(config: CompilerConfig) {\n this.models = new Map(Object.entries(config.models));\n this.refs = config.refs;\n }\n\n /**\n * Compile a chart definition into an executable SQL query.\n */\n compile(\n chart: Chart,\n inputParams: Record<string, unknown>,\n userContext?: Record<string, unknown>\n ): CompiledQuery {\n // Get SQL template\n const { sql, modelParams } = this.getSQL(chart);\n\n // Merge parameters: model defaults < chart defaults < input params\n const params = this.resolveParams(chart, modelParams, inputParams);\n\n // Expand date presets (pass inputParams to avoid overwriting explicit start_date/end_date)\n const expandedParams = this.expandPresets(params, inputParams);\n\n // Create template context with params, refs, and user context\n const context = createTemplateContext(expandedParams, this.refs, userContext);\n\n // Render template\n const renderedSQL = renderTemplate(sql, context);\n\n // Generate cache key (includes user context hash for RLS)\n const cacheKey = this.generateCacheKey(chart.name, renderedSQL, expandedParams, userContext);\n\n return {\n sql: renderedSQL,\n params: expandedParams,\n cacheKey,\n chartName: chart.name,\n };\n }\n\n private getSQL(chart: Chart): { sql: string; modelParams: ModelMetadata['params'] } {\n if (chart.source.sql) {\n return { sql: chart.source.sql, modelParams: undefined };\n }\n\n if (chart.source.model) {\n const model = this.models.get(chart.source.model);\n if (!model) {\n throw new Error(`Unknown model: ${chart.source.model}`);\n }\n return { sql: model.sql, modelParams: model.metadata.params };\n }\n\n throw new Error('Chart source must specify either model or sql');\n }\n\n private resolveParams(\n chart: Chart,\n modelParams: ModelMetadata['params'],\n inputParams: Record<string, unknown>\n ): Record<string, unknown> {\n const params: Record<string, unknown> = {};\n\n // Apply model parameter defaults (resolve dynamic values like current_date())\n if (modelParams) {\n for (const param of modelParams) {\n if (param.default !== undefined) {\n params[param.name] = resolveDynamicDefault(param.default);\n }\n }\n }\n\n // Apply chart parameter defaults (resolve dynamic values)\n if (chart.parameters) {\n for (const param of chart.parameters) {\n if (param.default !== undefined) {\n params[param.name] = resolveDynamicDefault(param.default);\n }\n }\n }\n\n // Apply input params (overrides defaults)\n Object.assign(params, inputParams);\n\n return params;\n }\n\n private expandPresets(params: Record<string, unknown>, inputParams: Record<string, unknown>): Record<string, unknown> {\n const expanded: Record<string, unknown> = { ...params };\n\n // If input explicitly provided start_date and end_date, don't overwrite from date_range.\n // This prevents previous-period comparison queries from having their dates\n // clobbered by a default date_range parameter re-expanding to the current period.\n if (inputParams.start_date && inputParams.end_date) {\n return expanded;\n }\n\n // Check for date_range and expand it (preset string, custom range, or relative range)\n if (isRelativeDateRange(params.date_range)) {\n const dateRange = expandRelativeDateRange(params.date_range);\n expanded.start_date = dateRange.start_date;\n expanded.end_date = dateRange.end_date;\n } else if (isCustomDateRange(params.date_range)) {\n const dateRange = expandCustomDateRange(params.date_range);\n expanded.start_date = dateRange.start_date;\n expanded.end_date = dateRange.end_date;\n } else if (typeof params.date_range === 'string' && isDatePreset(params.date_range)) {\n const dateRange = expandDatePreset(params.date_range);\n if (dateRange) {\n expanded.start_date = dateRange.start_date;\n expanded.end_date = dateRange.end_date;\n }\n }\n\n return expanded;\n }\n\n private generateCacheKey(\n chartName: string,\n sql: string,\n params: Record<string, unknown>,\n userContext?: Record<string, unknown>\n ): string {\n const sqlHash = createHash('sha256').update(sql).digest('hex').slice(0, 8);\n const paramsHash = createHash('sha256')\n .update(JSON.stringify(params, Object.keys(params).sort()))\n .digest('hex')\n .slice(0, 8);\n\n let key = `${chartName}:${sqlHash}:${paramsHash}`;\n\n if (userContext && Object.keys(userContext).length > 0) {\n const userHash = createHash('sha256')\n .update(JSON.stringify(userContext, Object.keys(userContext).sort()))\n .digest('hex')\n .slice(0, 8);\n key += `:${userHash}`;\n }\n\n return key;\n }\n\n /**\n * Add or update a model in the compiler.\n */\n addModel(name: string, metadata: ModelMetadata, sql: string): void {\n this.models.set(name, { metadata, sql });\n }\n\n /**\n * Add or update a ref mapping.\n */\n addRef(name: string, target: string): void {\n this.refs[name] = target;\n }\n}\n","import duckdb from 'duckdb';\nimport { performance } from 'node:perf_hooks';\nimport { serializeDateValue, type Connector, type QueryResult } from './index.js';\n\nexport interface DuckDBConfig {\n path: string; // file path or ':memory:'\n}\n\nexport class DuckDBConnector implements Connector {\n private config: DuckDBConfig;\n private db: duckdb.Database | null = null;\n private connection: duckdb.Connection | null = null;\n\n constructor(config: DuckDBConfig) {\n this.config = config;\n }\n\n async connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.db = new duckdb.Database(this.config.path, (err) => {\n if (err) {\n reject(err);\n return;\n }\n this.connection = this.db!.connect();\n resolve();\n });\n });\n }\n\n async disconnect(): Promise<void> {\n return new Promise((resolve) => {\n if (this.connection) {\n this.connection.close(() => {\n this.connection = null;\n });\n }\n if (this.db) {\n this.db.close(() => {\n this.db = null;\n resolve();\n });\n } else {\n resolve();\n }\n });\n }\n\n async execute(sql: string): Promise<QueryResult> {\n if (!this.connection) {\n throw new Error('Not connected to database');\n }\n\n const startTime = performance.now();\n\n return new Promise((resolve, reject) => {\n const stmt = this.connection!.prepare(sql, (prepErr) => {\n if (prepErr) {\n reject(prepErr);\n return;\n }\n\n // Extract column metadata from the prepared statement\n const columnInfo = stmt.columns();\n\n stmt.all((err, rows) => {\n const durationMs = performance.now() - startTime;\n\n if (err) {\n reject(err);\n return;\n }\n\n const typedRows = rows as Array<Record<string, unknown>>;\n // Convert BigInt values to numbers for JSON serialization\n const serializedRows = typedRows.map((row) => this.serializeRow(row));\n\n const columns = columnInfo.map((col) => ({\n name: col.name,\n type: col.type.sql_type,\n }));\n\n stmt.finalize();\n\n resolve({\n columns,\n rows: serializedRows,\n rowCount: serializedRows.length,\n durationMs,\n });\n });\n });\n });\n }\n\n isConnected(): boolean {\n return this.connection !== null;\n }\n\n async explain(sql: string): Promise<{ valid: boolean; error?: string }> {\n if (!this.connection) {\n throw new Error('Not connected to database');\n }\n\n return new Promise((resolve) => {\n this.connection!.all(`EXPLAIN ${sql}`, (err) => {\n if (err) {\n resolve({ valid: false, error: err.message });\n } else {\n resolve({ valid: true });\n }\n });\n });\n }\n\n private serializeRow(row: Record<string, unknown>): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(row)) {\n if (typeof value === 'bigint') {\n // Convert BigInt to number for JSON serialization\n result[key] = Number(value);\n } else if (value instanceof Date) {\n result[key] = serializeDateValue(value);\n } else {\n result[key] = value;\n }\n }\n return result;\n }\n}\n","import { performance } from 'node:perf_hooks';\nimport { serializeDateValue, type Connector, type QueryResult } from './index.js';\n\nexport interface PostgresConfig {\n host: string;\n port: number;\n database: string;\n user: string;\n password: string;\n schema?: string;\n ssl?: boolean | object;\n // Pool settings\n min?: number;\n max?: number;\n idleTimeoutMillis?: number;\n connectTimeoutMillis?: number;\n // Query settings\n statementTimeout?: number;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet sdk: any = null;\nlet typeParserConfigured = false;\n\nasync function loadSDK() {\n if (!sdk) {\n try {\n sdk = await import('pg');\n } catch {\n throw new Error(\n 'pg is not installed. Install it with: npm install pg'\n );\n }\n\n // Configure pg to return int8 (bigint) as JavaScript BigInt instead of string\n // OID 20 = int8 in PostgreSQL\n if (!typeParserConfigured) {\n sdk.types.setTypeParser(20, (val: string) => {\n if (val === null) return null;\n return BigInt(val);\n });\n typeParserConfigured = true;\n }\n }\n return sdk;\n}\n\n// Safe identifier escaping for schema names\nfunction escapeIdentifier(identifier: string): string {\n // Only allow alphanumeric and underscores for safety\n if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(identifier)) {\n throw new Error(`Invalid identifier: ${identifier}`);\n }\n return `\"${identifier}\"`;\n}\n\nexport class PostgresConnector implements Connector {\n private config: PostgresConfig;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private pool: any = null;\n\n constructor(config: PostgresConfig) {\n this.config = config;\n }\n\n async connect(): Promise<void> {\n const pg = await loadSDK();\n\n const poolConfig = {\n host: this.config.host,\n port: this.config.port,\n database: this.config.database,\n user: this.config.user,\n password: this.config.password,\n ssl: this.config.ssl,\n min: this.config.min ?? 2,\n max: this.config.max ?? 10,\n idleTimeoutMillis: this.config.idleTimeoutMillis ?? 30000,\n connectionTimeoutMillis: this.config.connectTimeoutMillis ?? 10000,\n statement_timeout: this.config.statementTimeout,\n };\n\n this.pool = new pg.Pool(poolConfig);\n\n // Handle pool errors (idle client errors)\n this.pool.on('error', (err: Error) => {\n console.error('Unexpected postgres pool error:', err.message);\n });\n\n // Set search_path on each new client from the pool\n if (this.config.schema) {\n const schema = escapeIdentifier(this.config.schema);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n this.pool.on('connect', (client: any) => {\n client.query(`SET search_path TO ${schema}`).catch((err: Error) => {\n console.error('Failed to set search_path:', err.message);\n });\n });\n }\n\n // Verify connection works\n const client = await this.pool.connect();\n client.release();\n }\n\n async disconnect(): Promise<void> {\n if (this.pool) {\n await this.pool.end();\n this.pool = null;\n }\n }\n\n isConnected(): boolean {\n return this.pool !== null;\n }\n\n async execute(sql: string): Promise<QueryResult> {\n if (!this.pool) {\n throw new Error('Not connected to database');\n }\n\n const start = performance.now();\n const result = await this.pool.query(sql);\n const durationMs = performance.now() - start;\n\n return {\n columns: this.extractColumns(result),\n rows: result.rows.map((row: Record<string, unknown>) => this.serializeRow(row)),\n rowCount: result.rowCount ?? result.rows.length,\n durationMs,\n };\n }\n\n async explain(sql: string): Promise<{ valid: boolean; error?: string }> {\n if (!this.pool) {\n throw new Error('Not connected to database');\n }\n\n try {\n await this.pool.query(`EXPLAIN ${sql}`);\n return { valid: true };\n } catch (err) {\n return {\n valid: false,\n error: err instanceof Error ? err.message : String(err)\n };\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private extractColumns(result: any): Array<{ name: string; type: string }> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return result.fields.map((field: any) => ({\n name: field.name,\n type: this.pgTypeToString(field.dataTypeID),\n }));\n }\n\n private pgTypeToString(oid: number): string {\n // Common Postgres type OIDs\n const typeMap: Record<number, string> = {\n 16: 'boolean', // bool\n 20: 'integer', // int8\n 21: 'integer', // int2\n 23: 'integer', // int4\n 700: 'number', // float4\n 701: 'number', // float8\n 1700: 'number', // numeric\n 25: 'string', // text\n 1043: 'string', // varchar\n 1082: 'date', // date\n 1114: 'date', // timestamp\n 1184: 'date', // timestamptz\n 114: 'unknown', // json\n 3802: 'unknown', // jsonb\n };\n return typeMap[oid] ?? 'unknown';\n }\n\n private serializeRow(row: Record<string, unknown>): Record<string, unknown> {\n const serialized: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(row)) {\n serialized[key] = this.serializeValue(value);\n }\n return serialized;\n }\n\n private serializeValue(value: unknown): unknown {\n if (value === null || value === undefined) {\n return null;\n }\n if (typeof value === 'bigint') {\n // Return as string if value exceeds safe integer range to preserve precision\n if (value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER) {\n return value.toString();\n }\n return Number(value);\n }\n if (value instanceof Date) {\n return serializeDateValue(value);\n }\n return value;\n }\n}\n","import { performance } from 'node:perf_hooks';\nimport { serializeDateValue, type Connector, type QueryResult } from './index.js';\n\nexport interface MySQLConfig {\n host: string;\n port: number;\n database: string;\n user: string;\n password: string;\n ssl?: boolean | object;\n // Pool settings\n min?: number;\n max?: number;\n idleTimeoutMillis?: number;\n connectTimeoutMillis?: number;\n // Query settings\n statementTimeout?: number;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet sdk: any = null;\n\nasync function loadSDK() {\n if (!sdk) {\n try {\n sdk = await import('mysql2/promise');\n } catch {\n throw new Error(\n 'mysql2 is not installed. Install it with: npm install mysql2'\n );\n }\n }\n return sdk;\n}\n\nexport class MySQLConnector implements Connector {\n private config: MySQLConfig;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private pool: any = null;\n\n constructor(config: MySQLConfig) {\n this.config = config;\n }\n\n async connect(): Promise<void> {\n const mysql = await loadSDK();\n\n const poolConfig = {\n host: this.config.host,\n port: this.config.port,\n database: this.config.database,\n user: this.config.user,\n password: this.config.password,\n ssl: this.config.ssl ? {} : undefined,\n waitForConnections: true,\n connectionLimit: this.config.max ?? 10,\n queueLimit: 0,\n connectTimeout: this.config.connectTimeoutMillis ?? 10000,\n };\n\n this.pool = mysql.createPool(poolConfig);\n\n // Verify connection works\n const connection = await this.pool.getConnection();\n connection.release();\n }\n\n async disconnect(): Promise<void> {\n if (this.pool) {\n await this.pool.end();\n this.pool = null;\n }\n }\n\n isConnected(): boolean {\n return this.pool !== null;\n }\n\n async execute(sql: string): Promise<QueryResult> {\n if (!this.pool) {\n throw new Error('Not connected to database');\n }\n\n const start = performance.now();\n const [rows, fields] = await this.pool.query(sql);\n const durationMs = performance.now() - start;\n\n return {\n columns: this.extractColumns(fields),\n rows: rows.map((row: Record<string, unknown>) => this.serializeRow(row)),\n rowCount: rows.length,\n durationMs,\n };\n }\n\n async explain(sql: string): Promise<{ valid: boolean; error?: string }> {\n if (!this.pool) {\n throw new Error('Not connected to database');\n }\n\n try {\n await this.pool.query(`EXPLAIN ${sql}`);\n return { valid: true };\n } catch (err) {\n return {\n valid: false,\n error: err instanceof Error ? err.message : String(err)\n };\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private extractColumns(fields: any[]): Array<{ name: string; type: string }> {\n return fields.map(field => ({\n name: field.name,\n type: this.mysqlTypeToString(field.type),\n }));\n }\n\n private mysqlTypeToString(type: number | undefined): string {\n // MySQL field type constants\n const typeMap: Record<number, string> = {\n 0: 'number', // DECIMAL\n 1: 'integer', // TINY\n 2: 'integer', // SHORT\n 3: 'integer', // LONG\n 4: 'number', // FLOAT\n 5: 'number', // DOUBLE\n 7: 'date', // TIMESTAMP\n 8: 'integer', // LONGLONG\n 9: 'integer', // INT24\n 10: 'date', // DATE\n 11: 'string', // TIME\n 12: 'date', // DATETIME\n 13: 'integer', // YEAR\n 15: 'string', // VARCHAR\n 245: 'unknown', // JSON\n 246: 'number', // NEWDECIMAL\n 252: 'string', // BLOB\n 253: 'string', // VAR_STRING\n 254: 'string', // STRING\n };\n return typeMap[type ?? 0] ?? 'unknown';\n }\n\n private serializeRow(row: Record<string, unknown>): Record<string, unknown> {\n const serialized: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(row)) {\n serialized[key] = this.serializeValue(value);\n }\n return serialized;\n }\n\n private serializeValue(value: unknown): unknown {\n if (value === null || value === undefined) {\n return null;\n }\n if (typeof value === 'bigint') {\n if (value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER) {\n return value.toString();\n }\n return Number(value);\n }\n if (value instanceof Date) {\n return serializeDateValue(value);\n }\n if (Buffer.isBuffer(value)) {\n return value.toString('utf-8');\n }\n return value;\n }\n}\n","import Database, { type Database as DatabaseType } from 'better-sqlite3';\nimport { performance } from 'node:perf_hooks';\nimport type { Connector, QueryResult } from './index.js';\n\nexport interface SQLiteConfig {\n path: string; // file path or :memory:\n readonly?: boolean;\n}\n\nexport class SQLiteConnector implements Connector {\n private config: SQLiteConfig;\n private db: DatabaseType | null = null;\n\n constructor(config: SQLiteConfig) {\n this.config = config;\n }\n\n async connect(): Promise<void> {\n this.db = new Database(this.config.path, {\n readonly: this.config.readonly ?? false,\n });\n\n // Enable foreign keys and WAL mode for better performance\n this.db.pragma('journal_mode = WAL');\n this.db.pragma('foreign_keys = ON');\n }\n\n async disconnect(): Promise<void> {\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n }\n\n isConnected(): boolean {\n return this.db !== null;\n }\n\n async execute(sql: string): Promise<QueryResult> {\n if (!this.db) {\n throw new Error('Not connected to database');\n }\n\n const start = performance.now();\n const stmt = this.db.prepare(sql);\n const rows = stmt.all() as Record<string, unknown>[];\n const durationMs = performance.now() - start;\n\n // Extract column info from the statement\n const columns = stmt.columns().map(col => ({\n name: col.name,\n type: this.sqliteTypeToString(col.type),\n }));\n\n return {\n columns,\n rows: rows.map(row => this.serializeRow(row)),\n rowCount: rows.length,\n durationMs,\n };\n }\n\n async explain(sql: string): Promise<{ valid: boolean; error?: string }> {\n if (!this.db) {\n throw new Error('Not connected to database');\n }\n\n try {\n this.db.prepare(`EXPLAIN ${sql}`);\n return { valid: true };\n } catch (err) {\n return {\n valid: false,\n error: err instanceof Error ? err.message : String(err)\n };\n }\n }\n\n private sqliteTypeToString(type: string | null): string {\n if (!type) return 'unknown';\n\n const upperType = type.toUpperCase();\n\n if (upperType.includes('INT')) return 'integer';\n if (upperType.includes('CHAR') || upperType.includes('TEXT') || upperType.includes('CLOB')) return 'string';\n if (upperType.includes('BLOB')) return 'unknown';\n if (upperType.includes('REAL') || upperType.includes('FLOA') || upperType.includes('DOUB')) return 'number';\n if (upperType.includes('NUMERIC') || upperType.includes('DECIMAL')) return 'number';\n if (upperType.includes('DATE') || upperType.includes('TIME')) return 'date';\n if (upperType.includes('BOOL')) return 'boolean';\n\n return 'unknown';\n }\n\n private serializeRow(row: Record<string, unknown>): Record<string, unknown> {\n const serialized: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(row)) {\n serialized[key] = this.serializeValue(value);\n }\n return serialized;\n }\n\n private serializeValue(value: unknown): unknown {\n if (value === null || value === undefined) {\n return null;\n }\n if (typeof value === 'bigint') {\n if (value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER) {\n return value.toString();\n }\n return Number(value);\n }\n if (Buffer.isBuffer(value)) {\n return value.toString('base64');\n }\n return value;\n }\n}\n","import { performance } from 'node:perf_hooks';\nimport { serializeDateValue, type Connector, type QueryResult } from './index.js';\n\nexport interface SnowflakeConfig {\n account: string;\n username: string;\n password?: string;\n privateKey?: string;\n authenticator?: string;\n clientStoreTemporaryCredential?: boolean;\n warehouse: string;\n database: string;\n schema?: string;\n role?: string;\n // Connection settings\n connectTimeoutMillis?: number;\n // Query settings\n statementTimeout?: number;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet sdk: any = null;\n\nasync function loadSDK() {\n if (!sdk) {\n try {\n sdk = (await import('snowflake-sdk')).default;\n } catch {\n throw new Error(\n 'snowflake-sdk is not installed. Snowflake support requires a separate install:\\n' +\n ' npm install -g snowflake-sdk\\n' +\n 'This package is optional and not bundled with yamchart to keep the default install lightweight.'\n );\n }\n }\n return sdk;\n}\n\nexport class SnowflakeConnector implements Connector {\n private config: SnowflakeConfig;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private connection: any = null;\n\n constructor(config: SnowflakeConfig) {\n this.config = config;\n }\n\n async connect(): Promise<void> {\n const snowflake = await loadSDK();\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const connectionOptions: Record<string, any> = {\n account: this.config.account,\n username: this.config.username,\n password: this.config.password,\n privateKey: this.config.privateKey,\n warehouse: this.config.warehouse,\n database: this.config.database,\n schema: this.config.schema,\n role: this.config.role,\n timeout: this.config.connectTimeoutMillis ?? 60000,\n };\n\n if (this.config.authenticator) {\n connectionOptions.authenticator = this.config.authenticator;\n }\n if (this.config.clientStoreTemporaryCredential !== undefined) {\n connectionOptions.clientStoreTemporaryCredential = this.config.clientStoreTemporaryCredential;\n }\n\n this.connection = snowflake.createConnection(connectionOptions);\n\n if (this.config.authenticator === 'EXTERNALBROWSER') {\n // connectAsync handles browser-based SSO flow\n await this.connection!.connectAsync();\n } else {\n return new Promise((resolve, reject) => {\n this.connection!.connect((err: Error | undefined) => {\n if (err) {\n this.connection = null;\n reject(err);\n } else {\n resolve();\n }\n });\n });\n }\n }\n\n async disconnect(): Promise<void> {\n if (this.connection) {\n return new Promise((resolve, reject) => {\n this.connection!.destroy((err: Error | undefined) => {\n this.connection = null;\n if (err) {\n reject(err);\n } else {\n resolve();\n }\n });\n });\n }\n }\n\n isConnected(): boolean {\n return this.connection !== null && this.connection.isUp();\n }\n\n async execute(sql: string): Promise<QueryResult> {\n if (!this.connection) {\n throw new Error('Not connected to database');\n }\n\n const start = performance.now();\n\n return new Promise((resolve, reject) => {\n this.connection!.execute({\n sqlText: sql,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n complete: (err: Error | undefined, stmt: any, rows: any[]) => {\n const durationMs = performance.now() - start;\n\n if (err) {\n reject(err);\n return;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const columns = stmt ? stmt.getColumns().map((col: any) => ({\n name: col.getName(),\n type: this.snowflakeTypeToString(col.getType()),\n })) : [];\n\n resolve({\n columns,\n rows: (rows || []).map(row => this.serializeRow(row as Record<string, unknown>)),\n rowCount: rows?.length ?? 0,\n durationMs,\n });\n },\n });\n });\n }\n\n async explain(sql: string): Promise<{ valid: boolean; error?: string }> {\n if (!this.connection) {\n throw new Error('Not connected to database');\n }\n\n try {\n await this.execute(`EXPLAIN ${sql}`);\n return { valid: true };\n } catch (err) {\n return {\n valid: false,\n error: err instanceof Error ? err.message : String(err)\n };\n }\n }\n\n private snowflakeTypeToString(type: string): string {\n const typeMap: Record<string, string> = {\n 'NUMBER': 'number',\n 'DECIMAL': 'number',\n 'NUMERIC': 'number',\n 'INT': 'integer',\n 'INTEGER': 'integer',\n 'BIGINT': 'integer',\n 'SMALLINT': 'integer',\n 'TINYINT': 'integer',\n 'BYTEINT': 'integer',\n 'FLOAT': 'number',\n 'FLOAT4': 'number',\n 'FLOAT8': 'number',\n 'DOUBLE': 'number',\n 'DOUBLE PRECISION': 'number',\n 'REAL': 'number',\n 'VARCHAR': 'string',\n 'CHAR': 'string',\n 'CHARACTER': 'string',\n 'STRING': 'string',\n 'TEXT': 'string',\n 'BINARY': 'unknown',\n 'VARBINARY': 'unknown',\n 'BOOLEAN': 'boolean',\n 'DATE': 'date',\n 'DATETIME': 'date',\n 'TIME': 'string',\n 'TIMESTAMP': 'date',\n 'TIMESTAMP_LTZ': 'date',\n 'TIMESTAMP_NTZ': 'date',\n 'TIMESTAMP_TZ': 'date',\n 'VARIANT': 'unknown',\n 'OBJECT': 'unknown',\n 'ARRAY': 'unknown',\n };\n\n const upperType = type.toUpperCase();\n return typeMap[upperType] ?? 'unknown';\n }\n\n private serializeRow(row: Record<string, unknown>): Record<string, unknown> {\n const serialized: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(row)) {\n serialized[key] = this.serializeValue(value);\n }\n return serialized;\n }\n\n private serializeValue(value: unknown): unknown {\n if (value === null || value === undefined) {\n return null;\n }\n if (typeof value === 'bigint') {\n if (value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER) {\n return value.toString();\n }\n return Number(value);\n }\n if (value instanceof Date) {\n return serializeDateValue(value);\n }\n return value;\n }\n}\n","import type { PostgresConnection, MySQLConnection, SnowflakeConnection } from '@yamchart/schema';\n\nexport interface ResolvedCredentials {\n user: string;\n password: string;\n}\n\nexport interface ResolvedSnowflakeCredentials {\n username: string;\n password?: string;\n privateKey?: string;\n authenticator?: string;\n clientStoreTemporaryCredential?: boolean;\n}\n\nexport function resolvePostgresAuth(connection: PostgresConnection): ResolvedCredentials {\n const auth = connection.auth;\n\n // Auth is optional for Postgres (local dev with trust auth)\n if (!auth) {\n return {\n user: process.env.PGUSER ?? 'postgres',\n password: process.env.PGPASSWORD ?? '',\n };\n }\n\n if (auth.type === 'env') {\n const user = process.env[auth.user_var];\n const password = process.env[auth.password_var];\n\n if (!user) {\n throw new Error(`Missing environment variable: ${auth.user_var}`);\n }\n\n return { user, password: password ?? '' };\n }\n\n // key_pair and secret_manager deferred to post-MVP\n throw new Error(`Auth type \"${auth.type}\" not yet implemented`);\n}\n\nexport function resolveMySQLAuth(connection: MySQLConnection): ResolvedCredentials {\n const auth = connection.auth;\n\n // Auth is optional for MySQL (local dev)\n if (!auth) {\n return {\n user: process.env.MYSQL_USER ?? 'root',\n password: process.env.MYSQL_PASSWORD ?? '',\n };\n }\n\n if (auth.type === 'env') {\n const user = process.env[auth.user_var];\n const password = process.env[auth.password_var];\n\n if (!user) {\n throw new Error(`Missing environment variable: ${auth.user_var}`);\n }\n\n return { user, password: password ?? '' };\n }\n\n throw new Error(`Auth type \"${auth.type}\" not yet implemented`);\n}\n\nexport function resolveSnowflakeAuth(connection: SnowflakeConnection): ResolvedSnowflakeCredentials {\n const auth = connection.auth;\n\n if (auth.type === 'env') {\n const username = process.env[auth.user_var];\n const password = process.env[auth.password_var];\n\n if (!username) {\n throw new Error(`Missing environment variable: ${auth.user_var}`);\n }\n\n return { username, password: password ?? undefined };\n }\n\n if (auth.type === 'key_pair') {\n const username = process.env[auth.user_var];\n\n if (!username) {\n throw new Error(`Missing environment variable: ${auth.user_var}`);\n }\n\n // Read private key from file path\n const fs = require('fs');\n const privateKey = fs.readFileSync(auth.private_key_path, 'utf-8');\n\n return { username, privateKey };\n }\n\n if (auth.type === 'externalbrowser') {\n const username = process.env[auth.user_var];\n\n if (!username) {\n throw new Error(`Missing environment variable: ${auth.user_var}`);\n }\n\n return {\n username,\n authenticator: 'EXTERNALBROWSER',\n clientStoreTemporaryCredential: auth.cache_token ?? false,\n };\n }\n\n throw new Error(`Auth type \"${auth.type}\" not yet implemented for Snowflake`);\n}\n","import type { Connector, QueryResult } from './index.js';\n\n/**\n * Error patterns that indicate a stale/terminated connection rather than\n * a query-level error. When these are encountered, the connector will\n * automatically reconnect and retry the operation once.\n */\nconst CONNECTION_ERROR_PATTERNS = [\n 'terminated connection',\n 'socket hang up',\n 'connection reset',\n 'ECONNRESET',\n 'ECONNREFUSED',\n 'ETIMEDOUT',\n 'connection lost',\n 'gone away', // MySQL: \"server has gone away\"\n 'not connected',\n];\n\nfunction isConnectionError(error: unknown): boolean {\n const message = error instanceof Error ? error.message : String(error);\n const lower = message.toLowerCase();\n return CONNECTION_ERROR_PATTERNS.some((pattern) => lower.includes(pattern.toLowerCase()));\n}\n\n/**\n * Wraps a Connector with automatic reconnection logic.\n * When a query fails due to a connection error (e.g. terminated connection\n * after process suspend/resume), the wrapper disconnects, reconnects, and\n * retries the operation once.\n */\nexport class ReconnectingConnector implements Connector {\n private inner: Connector;\n\n constructor(inner: Connector) {\n this.inner = inner;\n }\n\n async connect(): Promise<void> {\n return this.inner.connect();\n }\n\n async disconnect(): Promise<void> {\n return this.inner.disconnect();\n }\n\n isConnected(): boolean {\n return this.inner.isConnected();\n }\n\n async execute(sql: string): Promise<QueryResult> {\n await this.ensureConnected();\n\n try {\n return await this.inner.execute(sql);\n } catch (err) {\n if (isConnectionError(err)) {\n await this.reconnect();\n return this.inner.execute(sql);\n }\n throw err;\n }\n }\n\n async explain(sql: string): Promise<{ valid: boolean; error?: string }> {\n await this.ensureConnected();\n\n try {\n return await this.inner.explain(sql);\n } catch (err) {\n if (isConnectionError(err)) {\n await this.reconnect();\n return this.inner.explain(sql);\n }\n throw err;\n }\n }\n\n private async ensureConnected(): Promise<void> {\n if (!this.inner.isConnected()) {\n await this.reconnect();\n }\n }\n\n private async reconnect(): Promise<void> {\n try { await this.inner.disconnect(); } catch { /* may already be disconnected */ }\n await this.inner.connect();\n }\n}\n","export interface QueryResult {\n columns: Array<{\n name: string;\n type: string;\n }>;\n rows: Array<Record<string, unknown>>;\n rowCount: number;\n durationMs: number;\n}\n\nexport interface Connector {\n connect(): Promise<void>;\n disconnect(): Promise<void>;\n execute(sql: string): Promise<QueryResult>;\n explain(sql: string): Promise<{ valid: boolean; error?: string }>;\n isConnected(): boolean;\n}\n\n/**\n * Serialize a Date value for JSON responses. Dates at midnight UTC are\n * formatted as date-only strings (\"2026-02-19\") to avoid timezone-shift\n * issues on the client. Database DATE columns and day-level aggregations\n * (e.g. date_trunc('day', ...)) produce midnight UTC timestamps that would\n * otherwise display as the previous day in timezones west of UTC.\n */\nexport function serializeDateValue(value: Date): string {\n if (\n value.getUTCHours() === 0 &&\n value.getUTCMinutes() === 0 &&\n value.getUTCSeconds() === 0 &&\n value.getUTCMilliseconds() === 0\n ) {\n const y = value.getUTCFullYear();\n const m = String(value.getUTCMonth() + 1).padStart(2, '0');\n const d = String(value.getUTCDate()).padStart(2, '0');\n return `${y}-${m}-${d}`;\n }\n return value.toISOString();\n}\n\nexport * from './duckdb.js';\nexport * from './postgres.js';\nexport * from './mysql.js';\nexport * from './sqlite.js';\nexport * from './snowflake.js';\nexport * from './auth.js';\nexport * from './reconnecting.js';\n","import type { ModelMetadata, ReturnColumn } from '@yamchart/schema';\nimport type { Connector, QueryResult } from './connectors/index.js';\n\nexport interface AssertionResult {\n sql: string;\n passed: boolean;\n violationCount?: number;\n sampleViolations?: Array<Record<string, unknown>>;\n error?: string;\n warning?: string;\n}\n\nexport interface SchemaCheckResult {\n passed: boolean;\n expectedColumns: string[];\n actualColumns: string[];\n missingColumns: string[];\n extraColumns: string[];\n typeMismatches: Array<{ column: string; expected: string; actual: string }>;\n}\n\nexport interface ModelTestResult {\n modelName: string;\n schemaCheck?: SchemaCheckResult;\n assertions: AssertionResult[];\n durationMs: number;\n error?: string;\n}\n\nexport interface TestSuiteResult {\n models: ModelTestResult[];\n passed: number;\n failed: number;\n skipped: number;\n durationMs: number;\n}\n\nexport interface TestModelInput {\n compiledSql: string;\n metadata: ModelMetadata;\n}\n\nconst TYPE_MAP: Record<string, string[]> = {\n date: ['date', 'timestamp', 'datetime', 'timestamptz', 'timestamp with time zone'],\n number: ['integer', 'int', 'bigint', 'float', 'double', 'decimal', 'numeric', 'real', 'smallint', 'tinyint', 'hugeint', 'int4', 'int8', 'float4', 'float8'],\n integer: ['integer', 'int', 'bigint', 'smallint', 'tinyint', 'hugeint', 'int4', 'int8'],\n string: ['varchar', 'text', 'char', 'string', 'character varying', 'nvarchar'],\n boolean: ['boolean', 'bool'],\n};\n\nfunction typesMatch(expectedType: string, actualType: string): boolean {\n const expected = expectedType.toLowerCase();\n const actual = actualType.toLowerCase();\n if (expected === actual) return true;\n const acceptedTypes = TYPE_MAP[expected];\n if (acceptedTypes) return acceptedTypes.includes(actual);\n return false;\n}\n\n/**\n * Replace {{this}} (with optional whitespace) with compiled model SQL.\n */\nexport function expandThis(assertionSql: string, compiledSql: string): string {\n return assertionSql.replace(/\\{\\{\\s*this\\s*\\}\\}/g, compiledSql);\n}\n\nconst MAX_SAMPLE_VIOLATIONS = 5;\n\nexport async function runAssertion(\n compiledSql: string,\n assertionSql: string,\n connector: Connector,\n): Promise<AssertionResult> {\n const warning = !/\\{\\{\\s*this\\s*\\}\\}/.test(assertionSql)\n ? 'Test assertion does not reference {{this}} — did you mean to include it?'\n : undefined;\n\n const expandedSql = expandThis(assertionSql, compiledSql);\n\n try {\n const result = await connector.execute(expandedSql);\n\n return {\n sql: assertionSql,\n passed: result.rowCount === 0,\n violationCount: result.rowCount,\n sampleViolations: result.rows.slice(0, MAX_SAMPLE_VIOLATIONS),\n warning,\n };\n } catch (err) {\n return {\n sql: assertionSql,\n passed: false,\n error: err instanceof Error ? err.message : String(err),\n warning,\n };\n }\n}\n\nexport async function runModel(\n compiledSql: string,\n metadata: ModelMetadata,\n connector: Connector,\n): Promise<ModelTestResult> {\n const start = performance.now();\n const hasReturns = metadata.returns && metadata.returns.length > 0;\n const hasTests = metadata.tests && metadata.tests.length > 0;\n\n // Nothing to test\n if (!hasReturns && !hasTests) {\n return {\n modelName: metadata.name,\n assertions: [],\n durationMs: performance.now() - start,\n };\n }\n\n // Schema check\n let schemaCheckResult: SchemaCheckResult | undefined;\n if (hasReturns) {\n try {\n schemaCheckResult = await checkSchema(compiledSql, connector, metadata.returns!);\n } catch (err) {\n return {\n modelName: metadata.name,\n assertions: [],\n durationMs: performance.now() - start,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n\n // Data assertions\n const assertions: AssertionResult[] = [];\n if (hasTests) {\n for (const testSql of metadata.tests!) {\n const result = await runAssertion(compiledSql, testSql, connector);\n assertions.push(result);\n }\n }\n\n return {\n modelName: metadata.name,\n schemaCheck: schemaCheckResult,\n assertions,\n durationMs: performance.now() - start,\n };\n}\n\nexport async function runAll(\n models: TestModelInput[],\n connector: Connector,\n): Promise<TestSuiteResult> {\n const start = performance.now();\n const results: ModelTestResult[] = [];\n let passed = 0;\n let failed = 0;\n let skipped = 0;\n\n for (const model of models) {\n const result = await runModel(model.compiledSql, model.metadata, connector);\n results.push(result);\n\n const hasAnyCheck = result.schemaCheck || result.assertions.length > 0;\n if (!hasAnyCheck && !result.error) {\n skipped++;\n continue;\n }\n\n if (result.error) {\n failed++;\n continue;\n }\n\n // Count individual checks\n if (result.schemaCheck) {\n if (result.schemaCheck.passed) passed++;\n else failed++;\n }\n for (const assertion of result.assertions) {\n if (assertion.passed) passed++;\n else failed++;\n }\n }\n\n return {\n models: results,\n passed,\n failed,\n skipped,\n durationMs: performance.now() - start,\n };\n}\n\nexport async function checkSchema(\n compiledSql: string,\n connector: Connector,\n expectedReturns: ReturnColumn[],\n): Promise<SchemaCheckResult> {\n const wrappedSql = `SELECT * FROM (${compiledSql}) AS _model LIMIT 0`;\n const result = await connector.execute(wrappedSql);\n\n const actualColumns = result.columns.map((c) => c.name);\n const expectedColumns = expectedReturns.map((c) => c.name);\n\n const missingColumns = expectedColumns.filter((name) => !actualColumns.includes(name));\n const extraColumns = actualColumns.filter((name) => !expectedColumns.includes(name));\n\n const typeMismatches: SchemaCheckResult['typeMismatches'] = [];\n for (const expected of expectedReturns) {\n const actual = result.columns.find((c) => c.name === expected.name);\n if (actual && !typesMatch(expected.type, actual.type)) {\n typeMismatches.push({\n column: expected.name,\n expected: expected.type,\n actual: actual.type,\n });\n }\n }\n\n return {\n passed: missingColumns.length === 0 && typeMismatches.length === 0,\n expectedColumns,\n actualColumns,\n missingColumns,\n extraColumns,\n typeMismatches,\n };\n}\n","// Yamchart Query Engine\nexport const VERSION = '0.1.0';\n\nexport * from './parser.js';\nexport * from './presets.js';\nexport * from './template.js';\nexport * from './compiler.js';\nexport * from './connectors/index.js';\nexport * from './test-runner.js';\nexport * from './semantic/index.js';\n"],"mappings":"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","names":["end","shiftFns","start","format","performance","performance","performance","client","performance","performance","sdk","loadSDK","performance","performance","performance","sdk","loadSDK","performance"]}
@@ -4,10 +4,10 @@ import {
4
4
  DashboardSchema,
5
5
  ProjectSchema,
6
6
  ScheduleSchema
7
- } from "./chunk-KP4CYPBL.js";
7
+ } from "./chunk-RYTMXP2R.js";
8
8
  import {
9
9
  parseModelMetadata
10
- } from "./chunk-77CBXDCO.js";
10
+ } from "./chunk-5N3FYFBV.js";
11
11
 
12
12
  // src/commands/validate.ts
13
13
  import { readFile, readdir, access } from "fs/promises";
@@ -277,7 +277,7 @@ function levenshtein(a, b) {
277
277
  return matrix[b.length][a.length];
278
278
  }
279
279
  async function dryRunValidation(projectDir, config, connectionName, errors) {
280
- const { DuckDBConnector } = await import("./dist-ONU5AKOH.js");
280
+ const { DuckDBConnector } = await import("./dist-E2PVGIPT.js");
281
281
  let passed = 0;
282
282
  let failed = 0;
283
283
  const connName = connectionName || config.project?.defaults?.connection;
@@ -360,4 +360,4 @@ export {
360
360
  findProjectRoot,
361
361
  loadEnvFile
362
362
  };
363
- //# sourceMappingURL=chunk-T76DI6OA.js.map
363
+ //# sourceMappingURL=chunk-QLBCPJDL.js.map
@@ -597,10 +597,6 @@ var DefaultsSchema = z4.object({
597
597
  base_url: z4.string().url().optional(),
598
598
  week_start: z4.enum(["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"]).optional()
599
599
  });
600
- var EnvironmentSchema = z4.object({
601
- connection: z4.string().optional(),
602
- base_url: z4.string().url().optional()
603
- });
604
600
  var GitSchema = z4.object({
605
601
  provider: z4.enum(["github", "gitlab", "bitbucket"]).optional(),
606
602
  repo: z4.string().optional(),
@@ -677,12 +673,39 @@ var ThemeSchema = z4.object({
677
673
  sidebar: SidebarConfigSchema.optional(),
678
674
  customCss: z4.string().optional()
679
675
  });
676
+ var EnvironmentOverrideSchema = z4.object({
677
+ defaults: DefaultsSchema.optional(),
678
+ git: GitSchema.optional(),
679
+ auth: AuthSchema2.optional(),
680
+ features: FeaturesSchema.optional(),
681
+ theme: ThemeSchema.optional(),
682
+ semantic: SemanticConfigSchema.optional()
683
+ }).passthrough();
684
+ function deepMerge(base, override) {
685
+ if (!override)
686
+ return { ...base };
687
+ const result = { ...base };
688
+ for (const [key, value] of Object.entries(override)) {
689
+ if (value !== null && typeof value === "object" && !Array.isArray(value) && typeof result[key] === "object" && result[key] !== null && !Array.isArray(result[key])) {
690
+ result[key] = deepMerge(result[key], value);
691
+ } else {
692
+ result[key] = value;
693
+ }
694
+ }
695
+ return result;
696
+ }
697
+ function resolveProjectConfig(raw, env) {
698
+ const { environments, ...base } = raw;
699
+ const envBlocks = environments;
700
+ const envOverride = envBlocks?.[env];
701
+ return deepMerge(base, envOverride);
702
+ }
680
703
  var ProjectSchema = z4.object({
681
704
  version: z4.string().min(1),
682
705
  name: z4.string().min(1),
683
706
  description: z4.string().optional(),
684
707
  defaults: DefaultsSchema.optional(),
685
- environments: z4.record(z4.string(), EnvironmentSchema).optional(),
708
+ environments: z4.record(z4.string(), EnvironmentOverrideSchema).optional(),
686
709
  git: GitSchema.optional(),
687
710
  auth: AuthSchema2.optional(),
688
711
  features: FeaturesSchema.optional(),
@@ -844,14 +867,33 @@ var EventsFileSchema = z8.object({
844
867
  events: z8.array(EventSchema).default([])
845
868
  });
846
869
 
870
+ // ../../packages/schema/dist/index.js
871
+ var VERSION = "0.1.0";
872
+
847
873
  export {
848
874
  ConnectionSchema,
875
+ ParameterSchema,
849
876
  ChartSchema,
877
+ MeasureTypeSchema,
878
+ DimensionTypeSchema,
879
+ MeasureSchema,
880
+ DimensionSchema,
881
+ SemanticEntitySchema,
882
+ RelationshipSchema,
883
+ SemanticModelSchema,
884
+ SemanticFilterOperatorSchema,
885
+ SemanticFilterSchema,
850
886
  SemanticQuerySchema,
887
+ SemanticConfigSchema,
888
+ deepMerge,
889
+ resolveProjectConfig,
851
890
  ProjectSchema,
891
+ ModelMetadataSchema,
892
+ ModelSchema,
852
893
  DashboardSchema,
853
894
  ScheduleSchema,
854
895
  EventSchema,
855
- EventsFileSchema
896
+ EventsFileSchema,
897
+ VERSION
856
898
  };
857
- //# sourceMappingURL=chunk-KP4CYPBL.js.map
899
+ //# sourceMappingURL=chunk-RYTMXP2R.js.map