UNPKG

@lucidcms/libsql-adapter

Version:

The official LibSQL adapter for Lucid CMS

268 lines (261 loc) 8.18 kB
import { DatabaseAdapter } from "@lucidcms/core"; import { createClient } from "@libsql/client/web"; import { ParseJSONResultsPlugin, SqliteAdapter, SqliteIntrospector, SqliteQueryCompiler, sql } from "kysely"; import { jsonArrayFrom } from "kysely/helpers/sqlite"; //#region src/lib/kysely-libsql.ts var LibsqlDialect = class { #config; constructor(config) { this.#config = config; } createAdapter() { return new SqliteAdapter(); } createDriver() { let client; let closeClient; if ("client" in this.#config) { client = this.#config.client; closeClient = false; } else if (this.#config.url !== void 0) { client = createClient(this.#config); closeClient = true; } else throw new Error("Please specify either `client` or `url` in the LibsqlDialect config"); return new LibsqlDriver(client, closeClient); } createIntrospector(db) { return new SqliteIntrospector(db); } createQueryCompiler() { return new SqliteQueryCompiler(); } }; var LibsqlDriver = class { client; #closeClient; constructor(client, closeClient) { this.client = client; this.#closeClient = closeClient; } async init() {} async acquireConnection() { return new LibsqlConnection(this.client); } async beginTransaction(connection, _settings) { await connection.beginTransaction(); } async commitTransaction(connection) { await connection.commitTransaction(); } async rollbackTransaction(connection) { await connection.rollbackTransaction(); } async releaseConnection(_conn) {} async destroy() { if (this.#closeClient) this.client.close(); } }; var LibsqlConnection = class { client; #transaction; constructor(client) { this.client = client; } async executeQuery(compiledQuery) { const target = this.#transaction ?? this.client; const result = await target.execute({ sql: compiledQuery.sql, args: compiledQuery.parameters }); return { insertId: result.lastInsertRowid, numAffectedRows: BigInt(result.rowsAffected), rows: result.rows }; } async beginTransaction() { if (this.#transaction) throw new Error("Transaction already in progress"); this.#transaction = await this.client.transaction(); } async commitTransaction() { if (!this.#transaction) throw new Error("No transaction to commit"); await this.#transaction.commit(); this.#transaction = void 0; } async rollbackTransaction() { if (!this.#transaction) throw new Error("No transaction to rollback"); await this.#transaction.rollback(); this.#transaction = void 0; } async *streamQuery(_compiledQuery, _chunkSize) { throw new Error("Libsql Driver does not support streaming yet"); } }; //#endregion //#region src/utils/format-default-value.ts const formatDefaultValue = (type, defaultValue) => { if (defaultValue === null) return null; if (defaultValue === "''") return ""; if (type === "json" && defaultValue.startsWith("'") && defaultValue.endsWith("'")) try { return JSON.parse(defaultValue.slice(1, -1)); } catch { return null; } if (defaultValue.startsWith("'") && defaultValue.endsWith("'")) return defaultValue.slice(1, -1); if (/^-?\d+(\.\d+)?$/.test(defaultValue)) return type === "integer" || type === "bigint" ? Number.parseInt(defaultValue, 10) : Number.parseFloat(defaultValue); return defaultValue; }; var format_default_value_default = formatDefaultValue; //#endregion //#region src/utils/format-on-delete.ts const formatOnDelete = (value) => { return value?.toLowerCase() ?? "no action"; }; var format_on_delete_default = formatOnDelete; //#endregion //#region src/utils/format-on-update.ts const formatOnUpdate = (value) => { return value?.toLowerCase() ?? "no action"; }; var format_on_update_default = formatOnUpdate; //#endregion //#region src/utils/format-type.ts const formatType = (type) => { return type.toLowerCase(); }; var format_type_default = formatType; //#endregion //#region src/index.ts var LibSQLAdapter = class extends DatabaseAdapter { constructor(config) { super({ adapter: "libsql", dialect: new LibsqlDialect(config), plugins: [new ParseJSONResultsPlugin()] }); } async initialise() { await sql`PRAGMA foreign_keys = ON`.execute(this.client); } get jsonArrayFrom() { return jsonArrayFrom; } get config() { return { support: { alterColumn: false, multipleAlterTables: false, boolean: false, autoIncrement: true }, dataTypes: { primary: "integer", integer: "integer", boolean: "integer", json: "json", text: "text", timestamp: "timestamp", char: "text", varchar: "text" }, defaults: { timestamp: { now: "CURRENT_TIMESTAMP" }, boolean: { true: 1, false: 0 } }, fuzzOperator: "like" }; } async inferSchema(tx) { const res = await sql` WITH RECURSIVE tables AS ( SELECT name as table_name FROM sqlite_master WHERE type='table' AND name LIKE 'lucid_%' AND name NOT LIKE 'sqlite_%' ), table_info AS ( SELECT tables.table_name, p.* FROM tables CROSS JOIN pragma_table_info(tables.table_name) as p ), foreign_keys AS ( SELECT tables.table_name, fk.'from' as column_name, fk.'table' as referenced_table, fk.'to' as referenced_column, fk.'on_update' as on_update, fk.'on_delete' as on_delete FROM tables CROSS JOIN pragma_foreign_key_list(tables.table_name) as fk ), unique_constraints AS ( SELECT tables.table_name, idx.name as index_name, idx.'unique' as is_unique, info.name as column_name FROM tables CROSS JOIN pragma_index_list(tables.table_name) as idx CROSS JOIN pragma_index_info(idx.name) as info WHERE idx.'unique' = 1 ) SELECT t.*, fk.referenced_table as fk_table, fk.referenced_column as fk_column, fk.on_update as fk_on_update, fk.on_delete as fk_on_delete, CASE WHEN uc.column_name IS NOT NULL THEN 1 ELSE 0 END as is_unique FROM table_info t LEFT JOIN foreign_keys fk ON t.table_name = fk.table_name AND t.name = fk.column_name LEFT JOIN unique_constraints uc ON t.table_name = uc.table_name AND t.name = uc.column_name `.execute(tx ?? this.client); const tableMap = /* @__PURE__ */ new Map(); for (const row of res.rows) { let table = tableMap.get(row.table_name); if (!table) { table = { name: row.table_name, columns: [] }; tableMap.set(row.table_name, table); } table.columns.push({ name: row.name, type: format_type_default(row.type), nullable: !row.notnull, default: format_default_value_default(format_type_default(row.type), row.dflt_value), primary: Boolean(row.pk), unique: Boolean(row.is_unique), foreignKey: row.fk_table && row.fk_column ? { table: row.fk_table, column: row.fk_column, onUpdate: format_on_update_default(row.fk_on_update), onDelete: format_on_delete_default(row.fk_on_delete) } : void 0 }); } return Array.from(tableMap.values()); } formatDefaultValue(type, value) { if (type === "timestamp" && typeof value === "string") return sql.raw(value); if (typeof value === "object" && value !== null) return JSON.stringify(value); return value; } }; var src_default = LibSQLAdapter; //#endregion export { src_default as default }; //# sourceMappingURL=index.js.map