UNPKG

@storecraft/database-cloudflare-d1

Version:

`Storecraft` database driver for `cloudflare` D1 (cloud sqlite)

97 lines (88 loc) 2.73 kB
/** * @import {DatabaseIntrospector, Kysely} from "kysely"; */ import { DEFAULT_MIGRATION_LOCK_TABLE, DEFAULT_MIGRATION_TABLE, sql } from "kysely"; /** * This is a custom introspector for the D1 database. * Thre reason we did not use the regular SqliteIntrospector is that, `d1` will * raise `SQLITE_AUTH` for querying pragma tables with a reference, which is what * the normal SqliteIntrospector does. * * @implements {DatabaseIntrospector} */ export class D1Introspector { /** @type {Kysely} */ #db; /** * * @param {Kysely} db */ constructor(db) { this.#db = db; } /** @type {DatabaseIntrospector["getSchemas"]} */ async getSchemas() { // Sqlite doesn't support schemas. return []; } /** @type {DatabaseIntrospector["getTables"]} */ async getTables(options = { withInternalKyselyTables: false }) { let query = this.#db .selectFrom('sqlite_master') .where('type', 'in', ['table', 'view']) .where('name', 'not like', 'sqlite_%') .select('name') .orderBy('name') .$castTo(); if (!options.withInternalKyselyTables) { query = query .where('name', '!=', DEFAULT_MIGRATION_TABLE) .where('name', '!=', DEFAULT_MIGRATION_LOCK_TABLE); } const tables = await query.execute(); return Promise.all(tables.map(({ name }) => this.#getTableMetadata(name))); } /** @type {DatabaseIntrospector["getMetadata"]} */ async getMetadata(options) { return { tables: await this.getTables(options), }; } /** * @param {string} table */ async #getTableMetadata(table) { const db = this.#db; // Get the SQL that was used to create the table. const tableDefinition = await db .selectFrom('sqlite_master') .where('name', '=', table) .select(['sql', 'type']) .$castTo() .executeTakeFirstOrThrow(); // Try to find the name of the column that has `autoincrement` 🤦 const autoIncrementCol = tableDefinition.sql ?.split(/[\(\),]/) ?.find((it) => it.toLowerCase().includes('autoincrement')) ?.trimStart() ?.split(/\s+/)?.[0] ?.replace(/["`]/g, ''); const columns = await db .selectFrom(sql `pragma_table_info(${table})`.as('table_info')) .select(['name', 'type', 'notnull', 'dflt_value']) .orderBy('cid') .execute(); return { name: table, isView: tableDefinition.type === 'view', columns: columns.map((col) => ({ name: col.name, dataType: col.type, isNullable: !col.notnull, isAutoIncrementing: col.name === autoIncrementCol, hasDefaultValue: col.dflt_value != null, comment: undefined, })), }; } }