Saltar al contenido principal

Drizze y D1

  • SQLite para Cloudflare Workers

1. Instalaciones

bun add drizzle-orm

bun add -D drizzle-kit
npm i drizzle-orm

npm i -D drizzle-kit

2. Esquemas

Crear esquemas y verificar que las importaciones sean del lugar correcto, dependiendo si se utiliza PostgreSQL, D1, SQLite, etc..

src\db\schema\units.ts
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";

export const units = sqliteTable("units", {
  id: integer({ mode: "number" }).primaryKey({ autoIncrement: true }),
  displayOrder: integer("display_order", { mode: "number" }).notNull(),
  title: text({ length: 255 }).notNull(),
  imageSrc: text("image_src", { length: 255 }).notNull(),
});
  • Sin ORM
src\db\schema.sql
DROP TABLE IF EXISTS inventory;

CREATE TABLE IF NOT EXISTS inventory (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  name TEXT NOT NULL,
  quantity INTEGER NOT NULL,
  price REAL NOT NULL
);

CREATE INDEX idx_inventory_name ON inventory (name);
Nota

Dependiendo si las tablas o la base de datos no existe entonces es necesario ejecutar las migraciones con Drizzle Kit, si ya existen entonces solo se realizan las consultas.

3. Cloudflare D1

1. Crear base de datos

  • Con Wrangler o desde la web de Cloudflare
npx wrangler d1 create <dbName>

2. Agregar credenciales

wrangler.toml
name = "<app-name>"
main = "src/index.ts"
compatibility_date = "2024-10-29"
compatibility_flags = ["nodejs_compat"]

[[d1_databases]]
binding = "DB"
database_name = "dbName"
database_id = "dbId"
migrations_dir = "drizzle/migrations"

Drizzle Kit

1. Archivo de configuración

Puede ser TS, JS o JSON, para especificar donde se guardaran las migraciones, dónde están los esquemas y otras configuraciones.

drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
out: "./drizzle",
//schema: "./src/db/schema.ts", // Un archivo
schema: './src/db/schema', // Varios archivos
dialect: "sqlite",
});
{
  "dialect": "sqlite", // "postgresql"
  "out": "drizzle",
  "schema": "src/db/schema.ts"
}

2. Generar migraciones

# Bun
bunx drizzle-kit generate --name=init

# NPM
npx drizzle-kit generate --name=init

3. Aplicar migraciones a la base de datos

D1 HTTP

  • Si se establecieron las credenciales para D1 en drizzle.config.ts
bunx drizzle-kit migrate

Manual

  • Migraciones a la base de datos en la nube
bunx wrangler d1 execute <DB_NAME> --remote --file drizzle/0000_init.sql
  • Migraciones a la base de datos local
bunx wrangler d1 execute <dbName> --local --file drizzle/0000_init.sql

Ejemplo sin middleware

  • La principal diferencia al crear el cliente de una base de datos SQLite, PostgreSQL, etc. son las importaciones que se hacen, por ejemplo import { drizzle } from "drizzle-orm/d1";
  • Sin middleware es necesario crear el cliente en cada ruta
src\units\index.ts
import { drizzle } from "drizzle-orm/d1";
import { Hono } from "hono";
import { posts } from "./db/schema";

export type Env = {
  DB: D1Database;
};

const unitsApp = new Hono<{ Bindings: Bindings }>();

unitsApp.get("/", async (c) => {
  const db = drizzle(c.env.DB);
  const result = await db.select().from(units);
  return c.json(result);
});

unitsApp.post("/", async (c) => {
  const db = drizzle(c.env.DB);
  // Aun no tiene validaciones
  // Error 500 si el JSON no trae los campos
  const { displayOrder, title, imageSrc } = await c.req.json();
  const result = await db
    .insert(units)
    .values({ displayOrder, title, imageSrc })
    .returning();

  return c.json(result);
});

export default unitsApp;

Ejemplo con middleware

  • Con middleware se extrae la base de datos del contexto

Middleware*

src\db\drizzle-middleware.ts
import { drizzle } from "drizzle-orm/d1";
import { Context, MiddlewareHandler } from "hono";

export const ctxDB = "ctx-db";

export const drizzleMiddleware: MiddlewareHandler = async (c, next) => {
  // Verificar si el cliente ya está en el contexto
  if (getDrizzle(c)) return await next();
 
  // Crear cliente de Drizzle y agregarlo al contexto
  c.set(ctxDB, drizzle(c.env.DB));
  await next();
};

// Función para obtener el cliente Drizzle del contexto
export const getDrizzle = (c: Context) => c.get(ctxDB);

Uso

  1. Agregar middleware, puede ser en algún módulo como usersApp.use(), o en el principal, app.use()
  2. Extraer DB
  3. Usar DB
src\units\index.ts
import { drizzleMiddleware, getDrizzle } from "../db/drizzle-middleware";

const unitsApp = new Hono<{ Bindings: Bindings }>();

unitsApp.use("*", drizzleMiddleware); // <==============================

unitsApp.get("/", async (c) => {
  const db = getDrizzle(c); // <==============================
 
  const result = await db.select().from(units);
  return c.json(result);
});

export default unitsApp;