UNPKG

@cloudflare/actors

Version:

An easier way to build with Cloudflare Durable Objects

145 lines 4.97 kB
import { SQLSchemaMigrations } from "./sql-schema-migrations"; /** * Handler class for executing SQL queries and transactions against a SQL storage backend. * Provides methods for executing single queries and transactions with proper error handling * and result formatting. * * This class also provides access to methods from the underlying DurableObjectStorage * through the proxy pattern. */ export class Storage { /** * Gets the current migrations array */ get migrations() { return this._migrationsArray; } /** * Sets the migrations array and updates the SQLSchemaMigrations instance if available */ set migrations(value) { this._migrationsArray = value; // Update the SQLSchemaMigrations instance if it exists if (this.raw && this._migrations) { this._migrations = new SQLSchemaMigrations({ doStorage: this.raw, migrations: value }); } } /** * Creates a new instance of Storage. * @param sql - The SQL storage instance to use for queries * @param storage - The Durable Object storage instance */ constructor(storage) { this._migrationsArray = []; this.hasRanMigrations = false; this.raw = storage; this.sqlStorage = storage?.sql; if (storage) { this._migrations = new SQLSchemaMigrations({ doStorage: storage, migrations: this._migrationsArray }); } } /** * Executes a raw SQL query with optional parameters. * @param opts - Options containing the SQL query and optional parameters * @returns Promise resolving to a cursor containing the query results * @throws Error if the SQL execution fails */ async executeRawQuery(opts) { const { sql, params } = opts; try { let cursor; if (params && params.length) { cursor = this.sqlStorage?.exec(sql, ...params); } else { cursor = this.sqlStorage?.exec(sql); } if (!cursor) { console.log('No cursor returned from query'); return null; } return cursor; } catch (error) { console.error('SQL Execution Error:', error); throw error; } } /** * Execute SQL queries against the Agent's database * @template T Type of the returned rows * @param strings SQL query template strings * @param values Values to be inserted into the query * @returns Array of query results */ sql(strings, ...values) { let query = ""; try { // Construct the SQL query with placeholders query = strings.reduce((acc, str, i) => acc + str + (i < values.length ? "?" : ""), ""); if (!this.sqlStorage) { throw new Error('No SQL storage provided'); } // Execute the SQL query with the provided values return [...this.sqlStorage.exec(query, ...values)]; } catch (e) { console.error(`failed to execute sql query: ${query}`, e); throw e; } } /** * Executes a SQL query and formats the results based on the specified options. * @param opts - Options containing the SQL query, parameters, and result format preference * @returns Promise resolving to either raw query results or formatted array */ async query(sql, params, isRaw) { // Now proceed with executing the query const cursor = await this.executeRawQuery({ sql, params }); if (!cursor) return []; if (isRaw) { return { columns: cursor.columnNames, rows: Array.from(cursor.raw()), meta: { rows_read: cursor.rowsRead, rows_written: cursor.rowsWritten, }, }; } return cursor.toArray(); } async runMigrations() { if (this.hasRanMigrations) return; if (!this._migrations) { throw new Error('No migrations provided'); } const response = await this._migrations.runAll(); this.hasRanMigrations = true; return response; } async __studio(cmd) { const storage = this.raw; if (cmd.type === 'query') { return this.query(cmd.statement, cmd.params); } else if (cmd.type === 'transaction') { return storage.transaction(async () => { const results = []; for (const statement of cmd.statements) { results.push(await this.query(statement, cmd.params, true)); } return results; }); } } } //# sourceMappingURL=index.js.map