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);

:::tip 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;