'use strict'; var nodeApi = require('@duckdb/node-api'); var base = require('@mastra/core/base'); // src/storage/db/index.ts function bindParam(stmt, index, value) { if (value === null || value === void 0) { stmt.bindNull(index); } else if (typeof value === "string") { stmt.bindVarchar(index, value); } else if (typeof value === "number") { if (Number.isInteger(value) && value >= -2147483648 && value <= 2147483647) { stmt.bindInteger(index, value); } else { stmt.bindDouble(index, value); } } else if (typeof value === "boolean") { stmt.bindBoolean(index, value); } else if (typeof value === "bigint") { stmt.bindBigInt(index, value); } else if (value instanceof Date) { stmt.bindTimestamp(index, new nodeApi.DuckDBTimestampValue(BigInt(value.getTime()) * 1000n)); } else if (value instanceof nodeApi.DuckDBTimestampValue) { stmt.bindTimestamp(index, value); } else if (value instanceof nodeApi.DuckDBTimestampTZValue) { stmt.bindTimestampTZ(index, value); } else { stmt.bindVarchar(index, JSON.stringify(value)); } } function toJsValue(val) { if (val === null || val === void 0) return val; if (val instanceof nodeApi.DuckDBTimestampValue) { return new Date(Number(val.micros / 1000n)); } if (typeof val === "bigint") { return Number(val); } return val; } var DuckDBConnection = class extends base.MastraBase { instance = null; initialized = false; initPromise = null; path; constructor(config = {}) { super({ component: "STORAGE", name: "DUCKDB" }); this.path = config.path ?? "mastra.duckdb"; } async initialize() { if (this.initialized && this.instance) return; if (this.initPromise) { await this.initPromise; if (this.instance) return; this.initPromise = null; this.initialized = false; } this.initPromise = (async () => { try { this.instance = await nodeApi.DuckDBInstance.create(this.path); this.initialized = true; } catch (error) { this.instance = null; this.initialized = false; this.initPromise = null; throw error; } })(); return this.initPromise; } /** Create a new connection to the DuckDB instance, initializing if needed. */ async getConnection() { await this.initialize(); if (!this.instance) { throw new Error("DuckDB instance not initialized"); } return this.instance.connect(); } closeConnection(connection) { const conn = connection; try { if (typeof conn?.closeSync === "function") { conn.closeSync(); return; } if (typeof conn?.disconnectSync === "function") { conn.disconnectSync(); return; } if (typeof conn?.close === "function") { conn.close(); return; } if (typeof conn?.disconnect === "function") { conn.disconnect(); } } catch { } } /** * Execute a SQL query and return results as objects. */ async query(sql, params = []) { const connection = await this.getConnection(); try { if (params.length === 0) { const result2 = await connection.run(sql); const rows2 = await result2.getRows(); const columns2 = result2.columnNames(); return rows2.map((row) => { const obj = {}; columns2.forEach((col, i) => { obj[col] = toJsValue(row[i]); }); return obj; }); } let paramIndex = 0; const preparedSql = sql.replace(/\?/g, () => `$${++paramIndex}`); const stmt = await connection.prepare(preparedSql); for (let i = 0; i < params.length; i++) { bindParam(stmt, i + 1, params[i]); } const result = await stmt.run(); const rows = await result.getRows(); const columns = result.columnNames(); return rows.map((row) => { const obj = {}; columns.forEach((col, i) => { obj[col] = toJsValue(row[i]); }); return obj; }); } finally { this.closeConnection(connection); } } /** * Execute a SQL statement without returning results. */ async execute(sql, params = []) { const connection = await this.getConnection(); try { if (params.length === 0) { await connection.run(sql); return; } let paramIndex = 0; const preparedSql = sql.replace(/\?/g, () => `$${++paramIndex}`); const stmt = await connection.prepare(preparedSql); for (let i = 0; i < params.length; i++) { bindParam(stmt, i + 1, params[i]); } await stmt.run(); } finally { this.closeConnection(connection); } } /** * Execute multiple SQL statements in order using a single DuckDB connection. * * This is intended for schema setup/migrations where statements have no * parameters and must remain ordered, but opening a connection per statement * would dominate initialization cost. Blank statements are skipped. Like * calling execute() repeatedly, this does not wrap statements in a transaction, * so prior statements can remain applied if a later statement fails. */ async executeBatch(sqlStatements) { const statements = sqlStatements.map((statement) => statement.trim()).filter(Boolean); if (statements.length === 0) return; const connection = await this.getConnection(); try { const sql = statements.map((statement, i) => `-- executeBatch statement ${i + 1} ${statement}`).join("\n;\n") + "\n;"; await connection.run(sql); } finally { this.closeConnection(connection); } } /** * Escape a value for safe inline SQL use. * DuckDB prepared statements can't handle NULL for parameters typed as ANY, * so for complex INSERT/UPDATE operations we inline values safely. */ static sqlValue(value) { if (value === null || value === void 0) return "NULL"; if (typeof value === "number") { if (!Number.isFinite(value)) return "NULL"; return String(value); } if (typeof value === "boolean") return value ? "TRUE" : "FALSE"; if (value instanceof Date) return `'${value.toISOString()}'::TIMESTAMP`; if (typeof value === "string") return `'${value.replace(/'/g, "''")}'`; return `'${JSON.stringify(value).replace(/'/g, "''")}'`; } /** Release the DuckDB instance, allowing garbage collection. */ async close() { if (this.instance) { try { const instance = this.instance; if (typeof instance.closeSync === "function") { instance.closeSync(); } else if (typeof instance.close === "function") { instance.close(); } } catch { } this.instance = null; this.initialized = false; this.initPromise = null; } } }; exports.DuckDBConnection = DuckDBConnection; exports.bindParam = bindParam; //# sourceMappingURL=chunk-SMRZJTCI.cjs.map //# sourceMappingURL=chunk-SMRZJTCI.cjs.map