JSPM

drizzle-orm-crsqlite-wasm

0.0.2
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 101
  • Score
    100M100P100Q55657F
  • License ISC

Drizzle ORM adapter for CR-SQLite WASM

Package Exports

  • drizzle-orm-crsqlite-wasm
  • drizzle-orm-crsqlite-wasm/migrator

Readme

[!TIP] The goal of this package is to get merged into the official drizzle-orm package. In the meantime it provides a way to use crsqlite-wasm as the underlying database engine for drizzle.

What is this?

This package is an adapter for drizzle to use crsqlite-wasm as the underlying database engine. It is meant to work in the browser (uses web crypto for hashing). It is similar to the other adapters you might find in the official drizzle-orm package (like drizzle-orm/libsql or drizzle-orm/better-sqlite3).

Quick start

npm i drizzle-orm-crsqlite-wasm
import { initWasm } from "@vlcn.io/crsqlite-wasm"
import * as schema from "my-regular-drizzle-schema.ts"
import { drizzle } from "drizzle-orm-crsqlite-wasm"

const sqlite = await initWasm()
const sql = await sqlite.open("test")
const db = drizzle(sql)
const countries = await db.select().from(schema.countries).all()

How to use it?

  1. export all migrations from the drizzle migrations folder (following example uses Vite)

    // <drizzle-migrations>/index.ts
    export const migrations = Object.fromEntries(
        Object.entries(
            import.meta.glob("./*.sql", {
                eager: true,
                query: "?raw",
                import: "default",
            })
        ).map(([key, value]) => [key.slice(2, -4), value])
    )
  2. create browser equivalent of node's crypto.createHash("sha256")

    // <drizzle-migrations>/hash.ts
    async function createSha256Hash(query: string) {
        const encoder = new TextEncoder()
        const data = encoder.encode(query)
        const hash = await globalThis.crypto.subtle.digest("SHA-256", data)
        const hashArray = Array.from(new Uint8Array(hash))
        const hashHex = hashArray
            .map((b) => b.toString(16).padStart(2, "0"))
            .join("")
        return hashHex
    }
  3. process all migration data into a format useable by drizzle

    import migrationJournal from "<drizzle-migrations>/meta/_journal.json"
    import { migrations } from "<drizzle-migrations>/index.ts"
    import { createSha256Hash } from "<drizzle-migrations>/hash.ts"
    
    function getMigrations() {
        const journal = migrationJournal as {
            entries: Array<{
                idx: number
                when: number
                tag: string
                breakpoints: boolean
            }>
        }
        const migrationQueries: MigrationMeta[] = []
        for (const journalEntry of journal.entries) {
            const query = migrations[journalEntry.tag as keyof typeof migrations]
            const result = query.split("--> statement-breakpoint")
            migrationQueries.push({
                sql: result,
                bps: journalEntry.breakpoints,
                folderMillis: journalEntry.when,
                hash: await createSha256Hash(query),
            })
        }
        return migrationQueries
    }
  4. create a drizzle instance and run the migrations

    import { initWasm } from "@vlcn.io/crsqlite-wasm"
    import * as schema from "my-regular-drizzle-schema.ts"
    import { drizzle } from "drizzle-orm-crsqlite-wasm"
    import { migrate } from "drizzle-orm-crsqlite-wasm/migrator"
    
    const sqlite = await initWasm()
    const sql = await sqlite.open()
    const db = drizzle(sql, { schema, logger: true })
    await migrate(db, { migrations: await getMigrations() })
  5. use as a regular drizzle instance

    const [country] = await db
        .select()
        .from(schema.countries)
        .where(eq(schema.countries.name, "Peru"))
  6. prepared queries should be finalized to avoid memory leaks

    const query = db
        .select()
        .from(schema.countries)
        .where(eq(schema.countries.name, sql.placeholder("countryName")))
        .prepare()
    
    const [country] = await query.all({ countryName: "Peru" })
    
    // @ts-expect-error
    await query.finalize()

[!CAUTION] The .finalize() method is indeed exposed on the CRSQLitePreparedQuery object returned by calling .prepare() on a drizzle query-builder. However typescript does not know about it because to expose it would require modifications to the drizzle-orm package.