yamchart 0.3.9 → 0.3.11
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/chunk-2OTODCAK.js +162 -0
- package/dist/chunk-2OTODCAK.js.map +1 -0
- package/dist/chunk-54TOYXNP.js +169 -0
- package/dist/chunk-54TOYXNP.js.map +1 -0
- package/dist/{chunk-UHJGHWDE.js → chunk-DMGAHFXP.js} +2 -2
- package/dist/chunk-DMGAHFXP.js.map +1 -0
- package/dist/chunk-OKBTMI6E.js +368 -0
- package/dist/chunk-OKBTMI6E.js.map +1 -0
- package/dist/{chunk-ENOTMVPI.js → chunk-WZ3BKGIJ.js} +2 -362
- package/dist/chunk-WZ3BKGIJ.js.map +1 -0
- package/dist/connection-utils-7DJFKDG5.js +18 -0
- package/dist/describe-ZEUC5ESE.js +38 -0
- package/dist/describe-ZEUC5ESE.js.map +1 -0
- package/dist/{dev-CPZ3M5EE.js → dev-VCAUJDHF.js} +9 -8
- package/dist/dev-VCAUJDHF.js.map +1 -0
- package/dist/{dist-H363SX4Y.js → dist-A7VMHB26.js} +2 -2
- package/dist/dist-A7VMHB26.js.map +1 -0
- package/dist/index.js +99 -5
- package/dist/index.js.map +1 -1
- package/dist/query-AZUI2ZLX.js +32 -0
- package/dist/query-AZUI2ZLX.js.map +1 -0
- package/dist/{sync-dbt-6WY7HKP7.js → sync-dbt-X43KQ2IX.js} +52 -6
- package/dist/sync-dbt-X43KQ2IX.js.map +1 -0
- package/dist/tables-HBEA5CFW.js +39 -0
- package/dist/tables-HBEA5CFW.js.map +1 -0
- package/dist/{test-5QJ5GMND.js → test-ZZRTZ34Y.js} +2 -2
- package/package.json +3 -3
- package/dist/chunk-ENOTMVPI.js.map +0 -1
- package/dist/chunk-UHJGHWDE.js.map +0 -1
- package/dist/dev-CPZ3M5EE.js.map +0 -1
- package/dist/sync-dbt-6WY7HKP7.js.map +0 -1
- /package/dist/{dist-H363SX4Y.js.map → connection-utils-7DJFKDG5.js.map} +0 -0
- /package/dist/{test-5QJ5GMND.js.map → test-ZZRTZ34Y.js.map} +0 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
// src/commands/introspection.ts
|
|
2
|
+
function escapeSqlValue(value) {
|
|
3
|
+
return value.replace(/'/g, "''");
|
|
4
|
+
}
|
|
5
|
+
function normalizeTableType(tableType) {
|
|
6
|
+
const upper = tableType.toUpperCase();
|
|
7
|
+
if (upper === "BASE TABLE") return "TABLE";
|
|
8
|
+
return upper;
|
|
9
|
+
}
|
|
10
|
+
function getField(row, lowercase, uppercase) {
|
|
11
|
+
if (lowercase in row) return row[lowercase];
|
|
12
|
+
if (uppercase in row) return row[uppercase];
|
|
13
|
+
return void 0;
|
|
14
|
+
}
|
|
15
|
+
function getTablesQuery(type, options) {
|
|
16
|
+
switch (type) {
|
|
17
|
+
case "duckdb":
|
|
18
|
+
case "postgres": {
|
|
19
|
+
const conditions = [
|
|
20
|
+
"table_schema NOT IN ('information_schema', 'pg_catalog')"
|
|
21
|
+
];
|
|
22
|
+
if (options?.schema) {
|
|
23
|
+
conditions.push(`table_schema = '${escapeSqlValue(options.schema)}'`);
|
|
24
|
+
}
|
|
25
|
+
const sql = `SELECT table_schema, table_name, table_type FROM information_schema.tables WHERE ${conditions.join(" AND ")}`;
|
|
26
|
+
return {
|
|
27
|
+
sql,
|
|
28
|
+
normalize: (rows) => rows.map((row) => ({
|
|
29
|
+
schema: String(row.table_schema),
|
|
30
|
+
name: String(row.table_name),
|
|
31
|
+
type: normalizeTableType(String(row.table_type))
|
|
32
|
+
}))
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
case "mysql": {
|
|
36
|
+
let sql = "SELECT table_schema, table_name, table_type FROM information_schema.tables";
|
|
37
|
+
if (options?.schema) {
|
|
38
|
+
sql += ` WHERE table_schema = '${escapeSqlValue(options.schema)}'`;
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
sql,
|
|
42
|
+
normalize: (rows) => rows.map((row) => ({
|
|
43
|
+
schema: String(getField(row, "table_schema", "TABLE_SCHEMA")),
|
|
44
|
+
name: String(getField(row, "table_name", "TABLE_NAME")),
|
|
45
|
+
type: normalizeTableType(String(getField(row, "table_type", "TABLE_TYPE")))
|
|
46
|
+
}))
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
case "snowflake": {
|
|
50
|
+
const conditions = [];
|
|
51
|
+
if (options?.schema) {
|
|
52
|
+
conditions.push(`TABLE_SCHEMA = '${escapeSqlValue(options.schema)}'`);
|
|
53
|
+
}
|
|
54
|
+
if (options?.database) {
|
|
55
|
+
conditions.push(`TABLE_CATALOG = '${escapeSqlValue(options.database)}'`);
|
|
56
|
+
}
|
|
57
|
+
let sql = "SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE FROM INFORMATION_SCHEMA.TABLES";
|
|
58
|
+
if (conditions.length > 0) {
|
|
59
|
+
sql += ` WHERE ${conditions.join(" AND ")}`;
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
sql,
|
|
63
|
+
normalize: (rows) => rows.map((row) => ({
|
|
64
|
+
schema: String(row.TABLE_SCHEMA),
|
|
65
|
+
name: String(row.TABLE_NAME),
|
|
66
|
+
type: normalizeTableType(String(row.TABLE_TYPE))
|
|
67
|
+
}))
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
case "sqlite": {
|
|
71
|
+
const sql = "SELECT name, type FROM sqlite_master WHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%'";
|
|
72
|
+
return {
|
|
73
|
+
sql,
|
|
74
|
+
normalize: (rows) => rows.map((row) => ({
|
|
75
|
+
schema: "",
|
|
76
|
+
name: String(row.name),
|
|
77
|
+
type: String(row.type).toUpperCase()
|
|
78
|
+
}))
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
default:
|
|
82
|
+
throw new Error(`Unsupported database type: ${type}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function getDescribeQuery(type, table) {
|
|
86
|
+
switch (type) {
|
|
87
|
+
case "duckdb": {
|
|
88
|
+
return {
|
|
89
|
+
sql: `DESCRIBE ${table}`,
|
|
90
|
+
normalize: (rows) => rows.map((row) => ({
|
|
91
|
+
name: String(row.column_name),
|
|
92
|
+
type: String(row.column_type),
|
|
93
|
+
nullable: String(row.null)
|
|
94
|
+
}))
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
case "postgres": {
|
|
98
|
+
const parts = table.split(".");
|
|
99
|
+
const tableName = parts.length > 1 ? parts[parts.length - 1] : table;
|
|
100
|
+
const schemaName = parts.length > 1 ? parts[0] : null;
|
|
101
|
+
const conditions = [`table_name = '${escapeSqlValue(tableName)}'`];
|
|
102
|
+
if (schemaName) {
|
|
103
|
+
conditions.push(`table_schema = '${escapeSqlValue(schemaName)}'`);
|
|
104
|
+
}
|
|
105
|
+
const sql = `SELECT column_name, data_type, is_nullable FROM information_schema.columns WHERE ${conditions.join(" AND ")} ORDER BY ordinal_position`;
|
|
106
|
+
return {
|
|
107
|
+
sql,
|
|
108
|
+
normalize: (rows) => rows.map((row) => ({
|
|
109
|
+
name: String(row.column_name),
|
|
110
|
+
type: String(row.data_type),
|
|
111
|
+
nullable: String(row.is_nullable)
|
|
112
|
+
}))
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
case "mysql": {
|
|
116
|
+
const parts = table.split(".");
|
|
117
|
+
const tableName = parts.length > 1 ? parts[parts.length - 1] : table;
|
|
118
|
+
const schemaName = parts.length > 1 ? parts[0] : null;
|
|
119
|
+
const conditions = [`table_name = '${escapeSqlValue(tableName)}'`];
|
|
120
|
+
if (schemaName) {
|
|
121
|
+
conditions.push(`table_schema = '${escapeSqlValue(schemaName)}'`);
|
|
122
|
+
}
|
|
123
|
+
const sql = `SELECT column_name, column_type, is_nullable FROM information_schema.columns WHERE ${conditions.join(" AND ")} ORDER BY ordinal_position`;
|
|
124
|
+
return {
|
|
125
|
+
sql,
|
|
126
|
+
normalize: (rows) => rows.map((row) => ({
|
|
127
|
+
name: String(getField(row, "column_name", "COLUMN_NAME")),
|
|
128
|
+
type: String(getField(row, "column_type", "COLUMN_TYPE")),
|
|
129
|
+
nullable: String(getField(row, "is_nullable", "IS_NULLABLE"))
|
|
130
|
+
}))
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
case "snowflake": {
|
|
134
|
+
return {
|
|
135
|
+
sql: `DESCRIBE TABLE ${table}`,
|
|
136
|
+
normalize: (rows) => rows.map((row) => ({
|
|
137
|
+
name: String(row.name),
|
|
138
|
+
type: String(row.type),
|
|
139
|
+
nullable: String(row["null?"]) === "Y" ? "YES" : "NO"
|
|
140
|
+
}))
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
case "sqlite": {
|
|
144
|
+
return {
|
|
145
|
+
sql: `PRAGMA table_info(${table})`,
|
|
146
|
+
normalize: (rows) => rows.map((row) => ({
|
|
147
|
+
name: String(row.name),
|
|
148
|
+
type: String(row.type),
|
|
149
|
+
nullable: Number(row.notnull) === 1 ? "NO" : "YES"
|
|
150
|
+
}))
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
default:
|
|
154
|
+
throw new Error(`Unsupported database type: ${type}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export {
|
|
159
|
+
getTablesQuery,
|
|
160
|
+
getDescribeQuery
|
|
161
|
+
};
|
|
162
|
+
//# sourceMappingURL=chunk-2OTODCAK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/introspection.ts"],"sourcesContent":["/**\n * Per-engine SQL generation and result normalization for database introspection.\n *\n * Pure logic — no I/O, no connectors. Generates SQL strings and provides\n * normalize functions to transform raw query results into consistent shapes.\n */\n\nexport interface NormalizedTable {\n schema: string;\n name: string;\n type: string;\n}\n\nexport interface NormalizedColumn {\n name: string;\n type: string;\n nullable: string;\n}\n\nexport interface TablesQuery {\n sql: string;\n normalize: (rows: Record<string, unknown>[]) => NormalizedTable[];\n}\n\nexport interface DescribeQuery {\n sql: string;\n normalize: (rows: Record<string, unknown>[]) => NormalizedColumn[];\n}\n\n/**\n * Escape a SQL string literal value by doubling single quotes.\n */\nfunction escapeSqlValue(value: string): string {\n return value.replace(/'/g, \"''\");\n}\n\n/**\n * Normalize table_type values: 'BASE TABLE' -> 'TABLE', everything else uppercased.\n */\nfunction normalizeTableType(tableType: string): string {\n const upper = tableType.toUpperCase();\n if (upper === 'BASE TABLE') return 'TABLE';\n return upper;\n}\n\n/**\n * Helper to read a property from a row, trying lowercase first then uppercase.\n * MySQL drivers may return column names in either case.\n */\nfunction getField(row: Record<string, unknown>, lowercase: string, uppercase: string): unknown {\n if (lowercase in row) return row[lowercase];\n if (uppercase in row) return row[uppercase];\n return undefined;\n}\n\n/**\n * Generate a SQL query to list tables/views and a normalizer for the results.\n *\n * Supported types: duckdb, postgres, mysql, snowflake, sqlite.\n */\nexport function getTablesQuery(\n type: string,\n options?: { schema?: string; database?: string },\n): TablesQuery {\n switch (type) {\n case 'duckdb':\n case 'postgres': {\n const conditions = [\n \"table_schema NOT IN ('information_schema', 'pg_catalog')\",\n ];\n if (options?.schema) {\n conditions.push(`table_schema = '${escapeSqlValue(options.schema)}'`);\n }\n const sql = `SELECT table_schema, table_name, table_type FROM information_schema.tables WHERE ${conditions.join(' AND ')}`;\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n schema: String(row.table_schema),\n name: String(row.table_name),\n type: normalizeTableType(String(row.table_type)),\n })),\n };\n }\n\n case 'mysql': {\n let sql = 'SELECT table_schema, table_name, table_type FROM information_schema.tables';\n if (options?.schema) {\n sql += ` WHERE table_schema = '${escapeSqlValue(options.schema)}'`;\n }\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n schema: String(getField(row, 'table_schema', 'TABLE_SCHEMA')),\n name: String(getField(row, 'table_name', 'TABLE_NAME')),\n type: normalizeTableType(String(getField(row, 'table_type', 'TABLE_TYPE'))),\n })),\n };\n }\n\n case 'snowflake': {\n const conditions: string[] = [];\n if (options?.schema) {\n conditions.push(`TABLE_SCHEMA = '${escapeSqlValue(options.schema)}'`);\n }\n if (options?.database) {\n conditions.push(`TABLE_CATALOG = '${escapeSqlValue(options.database)}'`);\n }\n let sql = 'SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE FROM INFORMATION_SCHEMA.TABLES';\n if (conditions.length > 0) {\n sql += ` WHERE ${conditions.join(' AND ')}`;\n }\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n schema: String(row.TABLE_SCHEMA),\n name: String(row.TABLE_NAME),\n type: normalizeTableType(String(row.TABLE_TYPE)),\n })),\n };\n }\n\n case 'sqlite': {\n const sql = \"SELECT name, type FROM sqlite_master WHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%'\";\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n schema: '',\n name: String(row.name),\n type: String(row.type).toUpperCase(),\n })),\n };\n }\n\n default:\n throw new Error(`Unsupported database type: ${type}`);\n }\n}\n\n/**\n * Generate a SQL query to describe a table's columns and a normalizer for the results.\n *\n * Supported types: duckdb, postgres, mysql, snowflake, sqlite.\n * Accepts schema-qualified names (e.g. 'public.orders', 'ANALYTICS.PUBLIC.ORDERS').\n */\nexport function getDescribeQuery(type: string, table: string): DescribeQuery {\n switch (type) {\n case 'duckdb': {\n return {\n sql: `DESCRIBE ${table}`,\n normalize: (rows) =>\n rows.map((row) => ({\n name: String(row.column_name),\n type: String(row.column_type),\n nullable: String(row.null),\n })),\n };\n }\n\n case 'postgres': {\n const parts = table.split('.');\n const tableName = parts.length > 1 ? parts[parts.length - 1]! : table;\n const schemaName = parts.length > 1 ? parts[0]! : null;\n\n const conditions = [`table_name = '${escapeSqlValue(tableName)}'`];\n if (schemaName) {\n conditions.push(`table_schema = '${escapeSqlValue(schemaName)}'`);\n }\n\n const sql = `SELECT column_name, data_type, is_nullable FROM information_schema.columns WHERE ${conditions.join(' AND ')} ORDER BY ordinal_position`;\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n name: String(row.column_name),\n type: String(row.data_type),\n nullable: String(row.is_nullable),\n })),\n };\n }\n\n case 'mysql': {\n const parts = table.split('.');\n const tableName = parts.length > 1 ? parts[parts.length - 1]! : table;\n const schemaName = parts.length > 1 ? parts[0]! : null;\n\n const conditions = [`table_name = '${escapeSqlValue(tableName)}'`];\n if (schemaName) {\n conditions.push(`table_schema = '${escapeSqlValue(schemaName)}'`);\n }\n\n const sql = `SELECT column_name, column_type, is_nullable FROM information_schema.columns WHERE ${conditions.join(' AND ')} ORDER BY ordinal_position`;\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n name: String(getField(row, 'column_name', 'COLUMN_NAME')),\n type: String(getField(row, 'column_type', 'COLUMN_TYPE')),\n nullable: String(getField(row, 'is_nullable', 'IS_NULLABLE')),\n })),\n };\n }\n\n case 'snowflake': {\n return {\n sql: `DESCRIBE TABLE ${table}`,\n normalize: (rows) =>\n rows.map((row) => ({\n name: String(row.name),\n type: String(row.type),\n nullable: String(row['null?']) === 'Y' ? 'YES' : 'NO',\n })),\n };\n }\n\n case 'sqlite': {\n return {\n sql: `PRAGMA table_info(${table})`,\n normalize: (rows) =>\n rows.map((row) => ({\n name: String(row.name),\n type: String(row.type),\n nullable: Number(row.notnull) === 1 ? 'NO' : 'YES',\n })),\n };\n }\n\n default:\n throw new Error(`Unsupported database type: ${type}`);\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ConnectionSchema
|
|
3
|
+
} from "./chunk-WZ3BKGIJ.js";
|
|
4
|
+
import {
|
|
5
|
+
DuckDBConnector,
|
|
6
|
+
MySQLConnector,
|
|
7
|
+
PostgresConnector,
|
|
8
|
+
SQLiteConnector,
|
|
9
|
+
SnowflakeConnector,
|
|
10
|
+
resolveMySQLAuth,
|
|
11
|
+
resolvePostgresAuth,
|
|
12
|
+
resolveSnowflakeAuth
|
|
13
|
+
} from "./chunk-DMGAHFXP.js";
|
|
14
|
+
|
|
15
|
+
// src/commands/connection-utils.ts
|
|
16
|
+
import { readFile, access } from "fs/promises";
|
|
17
|
+
import { join } from "path";
|
|
18
|
+
import { parse as parseYaml } from "yaml";
|
|
19
|
+
async function loadProjectConfig(projectDir) {
|
|
20
|
+
const configPath = join(projectDir, "yamchart.yaml");
|
|
21
|
+
const content = await readFile(configPath, "utf-8");
|
|
22
|
+
return parseYaml(content);
|
|
23
|
+
}
|
|
24
|
+
async function resolveConnection(projectDir, overrideName) {
|
|
25
|
+
const config = await loadProjectConfig(projectDir);
|
|
26
|
+
const connName = overrideName || config.defaults?.connection;
|
|
27
|
+
if (!connName) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
"No connection specified. Use --connection or set defaults.connection in yamchart.yaml"
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
const yamlPath = join(projectDir, "connections", `${connName}.yaml`);
|
|
33
|
+
const ymlPath = join(projectDir, "connections", `${connName}.yml`);
|
|
34
|
+
let connPath = yamlPath;
|
|
35
|
+
try {
|
|
36
|
+
await access(yamlPath);
|
|
37
|
+
} catch {
|
|
38
|
+
try {
|
|
39
|
+
await access(ymlPath);
|
|
40
|
+
connPath = ymlPath;
|
|
41
|
+
} catch {
|
|
42
|
+
throw new Error(`Connection "${connName}" not found at connections/${connName}.yaml`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const content = await readFile(connPath, "utf-8");
|
|
46
|
+
const raw = parseYaml(content);
|
|
47
|
+
const parsed = ConnectionSchema.parse(raw);
|
|
48
|
+
return parsed;
|
|
49
|
+
}
|
|
50
|
+
function createConnector(connection, projectDir) {
|
|
51
|
+
switch (connection.type) {
|
|
52
|
+
case "duckdb": {
|
|
53
|
+
const duckdbConn = connection;
|
|
54
|
+
const dbPath = duckdbConn.config.path.startsWith("/") ? duckdbConn.config.path : duckdbConn.config.path === ":memory:" ? ":memory:" : join(projectDir, duckdbConn.config.path);
|
|
55
|
+
return new DuckDBConnector({ path: dbPath });
|
|
56
|
+
}
|
|
57
|
+
case "postgres": {
|
|
58
|
+
const pgConn = connection;
|
|
59
|
+
const credentials = resolvePostgresAuth(pgConn);
|
|
60
|
+
return new PostgresConnector({
|
|
61
|
+
host: pgConn.config.host,
|
|
62
|
+
port: pgConn.config.port,
|
|
63
|
+
database: pgConn.config.database,
|
|
64
|
+
schema: pgConn.config.schema,
|
|
65
|
+
ssl: pgConn.config.ssl,
|
|
66
|
+
user: credentials.user,
|
|
67
|
+
password: credentials.password,
|
|
68
|
+
min: pgConn.pool?.min_connections,
|
|
69
|
+
max: pgConn.pool?.max_connections,
|
|
70
|
+
idleTimeoutMillis: pgConn.pool?.idle_timeout,
|
|
71
|
+
statementTimeout: pgConn.query?.timeout
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
case "mysql": {
|
|
75
|
+
const mysqlConn = connection;
|
|
76
|
+
const credentials = resolveMySQLAuth(mysqlConn);
|
|
77
|
+
return new MySQLConnector({
|
|
78
|
+
host: mysqlConn.config.host,
|
|
79
|
+
port: mysqlConn.config.port,
|
|
80
|
+
database: mysqlConn.config.database,
|
|
81
|
+
ssl: mysqlConn.config.ssl,
|
|
82
|
+
user: credentials.user,
|
|
83
|
+
password: credentials.password,
|
|
84
|
+
min: mysqlConn.pool?.min_connections,
|
|
85
|
+
max: mysqlConn.pool?.max_connections,
|
|
86
|
+
idleTimeoutMillis: mysqlConn.pool?.idle_timeout,
|
|
87
|
+
statementTimeout: mysqlConn.query?.timeout
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
case "sqlite": {
|
|
91
|
+
const sqliteConn = connection;
|
|
92
|
+
const dbPath = sqliteConn.config.path.startsWith("/") ? sqliteConn.config.path : sqliteConn.config.path === ":memory:" ? ":memory:" : join(projectDir, sqliteConn.config.path);
|
|
93
|
+
return new SQLiteConnector({ path: dbPath });
|
|
94
|
+
}
|
|
95
|
+
case "snowflake": {
|
|
96
|
+
const sfConn = connection;
|
|
97
|
+
const credentials = resolveSnowflakeAuth(sfConn);
|
|
98
|
+
return new SnowflakeConnector({
|
|
99
|
+
account: sfConn.config.account,
|
|
100
|
+
username: credentials.username,
|
|
101
|
+
password: credentials.password,
|
|
102
|
+
privateKey: credentials.privateKey,
|
|
103
|
+
authenticator: credentials.authenticator,
|
|
104
|
+
clientStoreTemporaryCredential: credentials.clientStoreTemporaryCredential,
|
|
105
|
+
warehouse: sfConn.config.warehouse,
|
|
106
|
+
database: sfConn.config.database,
|
|
107
|
+
schema: sfConn.config.schema,
|
|
108
|
+
role: sfConn.config.role,
|
|
109
|
+
statementTimeout: sfConn.query?.timeout
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
default:
|
|
113
|
+
throw new Error(`Unsupported connection type: ${connection.type}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function formatTable(result) {
|
|
117
|
+
const { columns, rows, rowCount, durationMs } = result;
|
|
118
|
+
const maxWidth = 40;
|
|
119
|
+
const truncate = (val) => {
|
|
120
|
+
if (val === null || val === void 0) return "NULL";
|
|
121
|
+
const str = String(val);
|
|
122
|
+
if (str.length > maxWidth) return str.slice(0, maxWidth - 3) + "...";
|
|
123
|
+
return str;
|
|
124
|
+
};
|
|
125
|
+
const headers = columns.map((c) => c.name);
|
|
126
|
+
const formattedRows = rows.map(
|
|
127
|
+
(row) => columns.map((c) => truncate(row[c.name]))
|
|
128
|
+
);
|
|
129
|
+
const colWidths = headers.map((h, i) => {
|
|
130
|
+
const dataMax = formattedRows.reduce(
|
|
131
|
+
(max, row) => Math.max(max, row[i].length),
|
|
132
|
+
0
|
|
133
|
+
);
|
|
134
|
+
return Math.max(h.length, dataMax);
|
|
135
|
+
});
|
|
136
|
+
const lines = [];
|
|
137
|
+
const headerLine = headers.map((h, i) => h.padEnd(colWidths[i])).join(" ");
|
|
138
|
+
lines.push(headerLine);
|
|
139
|
+
const separator = colWidths.map((w) => "-".repeat(w)).join(" ");
|
|
140
|
+
lines.push(separator);
|
|
141
|
+
for (const row of formattedRows) {
|
|
142
|
+
const line = row.map((val, i) => val.padEnd(colWidths[i])).join(" ");
|
|
143
|
+
lines.push(line);
|
|
144
|
+
}
|
|
145
|
+
lines.push("");
|
|
146
|
+
lines.push(`${rowCount} row(s) (${Math.round(durationMs)}ms)`);
|
|
147
|
+
return lines.join("\n");
|
|
148
|
+
}
|
|
149
|
+
function formatJSON(result) {
|
|
150
|
+
return JSON.stringify(
|
|
151
|
+
{
|
|
152
|
+
columns: result.columns,
|
|
153
|
+
rows: result.rows,
|
|
154
|
+
rowCount: result.rowCount,
|
|
155
|
+
durationMs: result.durationMs
|
|
156
|
+
},
|
|
157
|
+
null,
|
|
158
|
+
2
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export {
|
|
163
|
+
loadProjectConfig,
|
|
164
|
+
resolveConnection,
|
|
165
|
+
createConnector,
|
|
166
|
+
formatTable,
|
|
167
|
+
formatJSON
|
|
168
|
+
};
|
|
169
|
+
//# sourceMappingURL=chunk-54TOYXNP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/connection-utils.ts"],"sourcesContent":["import { readFile, access } from 'fs/promises';\nimport { join } from 'path';\nimport { parse as parseYaml } from 'yaml';\nimport {\n DuckDBConnector,\n PostgresConnector,\n MySQLConnector,\n SQLiteConnector,\n SnowflakeConnector,\n resolvePostgresAuth,\n resolveMySQLAuth,\n resolveSnowflakeAuth,\n type Connector,\n type QueryResult,\n} from '@yamchart/query';\nimport {\n ConnectionSchema,\n type Connection,\n type DuckDBConnection,\n type PostgresConnection,\n type MySQLConnection,\n type SQLiteConnection,\n type SnowflakeConnection,\n} from '@yamchart/schema';\n\nexport interface ProjectConfig {\n name: string;\n version?: string;\n defaults?: {\n connection?: string;\n };\n}\n\n/**\n * Read and parse yamchart.yaml from a project directory.\n */\nexport async function loadProjectConfig(projectDir: string): Promise<ProjectConfig> {\n const configPath = join(projectDir, 'yamchart.yaml');\n const content = await readFile(configPath, 'utf-8');\n return parseYaml(content) as ProjectConfig;\n}\n\n/**\n * Load and validate a connection YAML file.\n * Tries .yaml then .yml extensions.\n * If no overrideName, falls back to defaults.connection from project config.\n */\nexport async function resolveConnection(\n projectDir: string,\n overrideName?: string,\n): Promise<Connection> {\n const config = await loadProjectConfig(projectDir);\n const connName = overrideName || config.defaults?.connection;\n\n if (!connName) {\n throw new Error(\n 'No connection specified. Use --connection or set defaults.connection in yamchart.yaml',\n );\n }\n\n const yamlPath = join(projectDir, 'connections', `${connName}.yaml`);\n const ymlPath = join(projectDir, 'connections', `${connName}.yml`);\n\n let connPath = yamlPath;\n try {\n await access(yamlPath);\n } catch {\n try {\n await access(ymlPath);\n connPath = ymlPath;\n } catch {\n throw new Error(`Connection \"${connName}\" not found at connections/${connName}.yaml`);\n }\n }\n\n const content = await readFile(connPath, 'utf-8');\n const raw = parseYaml(content);\n const parsed = ConnectionSchema.parse(raw);\n return parsed;\n}\n\n/**\n * Instantiate the right connector class based on connection.type.\n * Resolves auth and relative paths. Does NOT call connect().\n */\nexport function createConnector(connection: Connection, projectDir: string): Connector {\n switch (connection.type) {\n case 'duckdb': {\n const duckdbConn = connection as DuckDBConnection;\n const dbPath = duckdbConn.config.path.startsWith('/')\n ? duckdbConn.config.path\n : duckdbConn.config.path === ':memory:'\n ? ':memory:'\n : join(projectDir, duckdbConn.config.path);\n return new DuckDBConnector({ path: dbPath });\n }\n\n case 'postgres': {\n const pgConn = connection as PostgresConnection;\n const credentials = resolvePostgresAuth(pgConn);\n return new PostgresConnector({\n host: pgConn.config.host,\n port: pgConn.config.port,\n database: pgConn.config.database,\n schema: pgConn.config.schema,\n ssl: pgConn.config.ssl,\n user: credentials.user,\n password: credentials.password,\n min: pgConn.pool?.min_connections,\n max: pgConn.pool?.max_connections,\n idleTimeoutMillis: pgConn.pool?.idle_timeout,\n statementTimeout: pgConn.query?.timeout,\n });\n }\n\n case 'mysql': {\n const mysqlConn = connection as MySQLConnection;\n const credentials = resolveMySQLAuth(mysqlConn);\n return new MySQLConnector({\n host: mysqlConn.config.host,\n port: mysqlConn.config.port,\n database: mysqlConn.config.database,\n ssl: mysqlConn.config.ssl,\n user: credentials.user,\n password: credentials.password,\n min: mysqlConn.pool?.min_connections,\n max: mysqlConn.pool?.max_connections,\n idleTimeoutMillis: mysqlConn.pool?.idle_timeout,\n statementTimeout: mysqlConn.query?.timeout,\n });\n }\n\n case 'sqlite': {\n const sqliteConn = connection as SQLiteConnection;\n const dbPath = sqliteConn.config.path.startsWith('/')\n ? sqliteConn.config.path\n : sqliteConn.config.path === ':memory:'\n ? ':memory:'\n : join(projectDir, sqliteConn.config.path);\n return new SQLiteConnector({ path: dbPath });\n }\n\n case 'snowflake': {\n const sfConn = connection as SnowflakeConnection;\n const credentials = resolveSnowflakeAuth(sfConn);\n return new SnowflakeConnector({\n account: sfConn.config.account,\n username: credentials.username,\n password: credentials.password,\n privateKey: credentials.privateKey,\n authenticator: credentials.authenticator,\n clientStoreTemporaryCredential: credentials.clientStoreTemporaryCredential,\n warehouse: sfConn.config.warehouse,\n database: sfConn.config.database,\n schema: sfConn.config.schema,\n role: sfConn.config.role,\n statementTimeout: sfConn.query?.timeout,\n });\n }\n\n default:\n throw new Error(`Unsupported connection type: ${(connection as Connection).type}`);\n }\n}\n\n/**\n * Format a query result as an aligned terminal table.\n * Truncates values longer than 40 characters.\n */\nexport function formatTable(result: QueryResult): string {\n const { columns, rows, rowCount, durationMs } = result;\n const maxWidth = 40;\n\n const truncate = (val: unknown): string => {\n if (val === null || val === undefined) return 'NULL';\n const str = String(val);\n if (str.length > maxWidth) return str.slice(0, maxWidth - 3) + '...';\n return str;\n };\n\n // Calculate column widths\n const headers = columns.map((c) => c.name);\n const formattedRows = rows.map((row) =>\n columns.map((c) => truncate(row[c.name])),\n );\n\n const colWidths = headers.map((h, i) => {\n const dataMax = formattedRows.reduce(\n (max, row) => Math.max(max, row[i]!.length),\n 0,\n );\n return Math.max(h.length, dataMax);\n });\n\n // Build lines\n const lines: string[] = [];\n\n // Header\n const headerLine = headers.map((h, i) => h.padEnd(colWidths[i]!)).join(' ');\n lines.push(headerLine);\n\n // Separator\n const separator = colWidths.map((w) => '-'.repeat(w)).join(' ');\n lines.push(separator);\n\n // Data rows\n for (const row of formattedRows) {\n const line = row.map((val, i) => val.padEnd(colWidths[i]!)).join(' ');\n lines.push(line);\n }\n\n // Footer\n lines.push('');\n lines.push(`${rowCount} row(s) (${Math.round(durationMs)}ms)`);\n\n return lines.join('\\n');\n}\n\n/**\n * Format a query result as a JSON string.\n */\nexport function formatJSON(result: QueryResult): string {\n return JSON.stringify(\n {\n columns: result.columns,\n rows: result.rows,\n rowCount: result.rowCount,\n durationMs: result.durationMs,\n },\n null,\n 2,\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -906,7 +906,7 @@ async function loadSDK3() {
|
|
|
906
906
|
try {
|
|
907
907
|
sdk3 = (await import("snowflake-sdk")).default;
|
|
908
908
|
} catch {
|
|
909
|
-
throw new Error("snowflake-sdk is not installed.
|
|
909
|
+
throw new Error("snowflake-sdk is not installed. Snowflake support requires a separate install:\n npm install -g snowflake-sdk\nThis package is optional and not bundled with yamchart to keep the default install lightweight.");
|
|
910
910
|
}
|
|
911
911
|
}
|
|
912
912
|
return sdk3;
|
|
@@ -1324,4 +1324,4 @@ export {
|
|
|
1324
1324
|
checkSchema,
|
|
1325
1325
|
VERSION
|
|
1326
1326
|
};
|
|
1327
|
-
//# sourceMappingURL=chunk-
|
|
1327
|
+
//# sourceMappingURL=chunk-DMGAHFXP.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/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 subMonths,\n subYears,\n startOfYear,\n startOfMonth,\n startOfQuarter,\n endOfMonth,\n endOfQuarter,\n endOfYear,\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 '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 'last_7_days':\n return {\n start_date: formatDate(subDays(now, 7)),\n end_date: today,\n };\n\n case 'last_30_days':\n return {\n start_date: formatDate(subDays(now, 30)),\n end_date: today,\n };\n\n case 'last_90_days':\n return {\n start_date: formatDate(subDays(now, 90)),\n end_date: today,\n };\n\n case 'last_12_months':\n return {\n start_date: formatDate(subMonths(now, 12)),\n end_date: today,\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 * 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","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\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 */\nexport function createTemplateContext(\n params: Record<string, unknown>,\n refs: ModelRefs = {},\n userContext?: Record<string, unknown>\n): TemplateContext {\n return {\n ...params,\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 } 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\n const expandedParams = this.expandPresets(params);\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>): Record<string, unknown> {\n const expanded: Record<string, unknown> = { ...params };\n\n // Check for date_range and expand it (preset string or custom range object)\n 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 type { Connector, 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 {\n result[key] = value;\n }\n }\n return result;\n }\n}\n","import { performance } from 'node:perf_hooks';\nimport type { Connector, 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 value.toISOString();\n }\n return value;\n }\n}\n","import { performance } from 'node:perf_hooks';\nimport type { Connector, 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 value.toISOString();\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 type { Connector, 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 value.toISOString();\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 { 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","// Dashbook 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';\n"],"mappings":"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","names":["format","performance","performance","client","performance","sdk","loadSDK","performance","performance","sdk","loadSDK"]}
|