Files
gh-lttr-claude-marketplace-…/skills/nuxt/references/drizzle-db0.md
2025-11-30 08:38:06 +08:00

6.2 KiB

Database with Drizzle ORM and db0

Check if installed: Look for drizzle-orm and optionally db0 in package.json before using.

Overview

Drizzle ORM is a TypeScript-first ORM. In Nuxt, it's commonly used with Nitro's db0 for database access.

Setup

Database Configuration

// server/database/index.ts
import { drizzle } from "drizzle-orm/better-sqlite3"
import Database from "better-sqlite3"

const sqlite = new Database("sqlite.db")
export const db = drizzle(sqlite)

Schema Definition

// server/database/schema.ts
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core"

export const users = sqliteTable("users", {
  id: integer("id").primaryKey({ autoIncrement: true }),
  name: text("name").notNull(),
  email: text("email").notNull().unique(),
  createdAt: integer("created_at", { mode: "timestamp" }).$defaultFn(
    () => new Date(),
  ),
})

export const posts = sqliteTable("posts", {
  id: integer("id").primaryKey({ autoIncrement: true }),
  title: text("title").notNull(),
  content: text("content"),
  authorId: integer("author_id").references(() => users.id),
  createdAt: integer("created_at", { mode: "timestamp" }).$defaultFn(
    () => new Date(),
  ),
})

CRUD Operations

Insert

// server/api/users.post.ts
import { db } from "~/server/database"
import { users } from "~/server/database/schema"

export default defineEventHandler(async (event) => {
  const body = await readBody(event)

  const [user] = await db
    .insert(users)
    .values({
      name: body.name,
      email: body.email,
    })
    .returning()

  return user
})

Select

// server/api/users.get.ts
import { db } from "~/server/database"
import { users } from "~/server/database/schema"
import { eq } from "drizzle-orm"

export default defineEventHandler(async () => {
  // Get all users
  const allUsers = await db.select().from(users)

  // Get user by id
  const user = await db.select().from(users).where(eq(users.id, 1))

  // Get with specific columns
  const userEmails = await db
    .select({
      email: users.email,
      name: users.name,
    })
    .from(users)

  return allUsers
})

Update

import { db } from "~/server/database"
import { users } from "~/server/database/schema"
import { eq } from "drizzle-orm"

export default defineEventHandler(async (event) => {
  const id = getRouterParam(event, "id")
  const body = await readBody(event)

  const [updated] = await db
    .update(users)
    .set({ name: body.name })
    .where(eq(users.id, Number(id)))
    .returning()

  return updated
})

Delete

import { db } from "~/server/database"
import { users } from "~/server/database/schema"
import { eq } from "drizzle-orm"

export default defineEventHandler(async (event) => {
  const id = getRouterParam(event, "id")

  await db.delete(users).where(eq(users.id, Number(id)))

  return { success: true }
})

Queries

With Joins

import { db } from "~/server/database"
import { users, posts } from "~/server/database/schema"
import { eq } from "drizzle-orm"

export default defineEventHandler(async () => {
  const usersWithPosts = await db
    .select()
    .from(users)
    .leftJoin(posts, eq(users.id, posts.authorId))

  return usersWithPosts
})

Relational Queries

// Define relations
import { relations } from "drizzle-orm"

export const usersRelations = relations(users, ({ many }) => ({
  posts: many(posts),
}))

export const postsRelations = relations(posts, ({ one }) => ({
  author: one(users, {
    fields: [posts.authorId],
    references: [users.id],
  }),
}))

// Query with relations
const usersWithPosts = await db.query.users.findMany({
  with: {
    posts: true,
  },
})

Filtering

import { eq, ne, gt, gte, lt, lte, like, and, or } from "drizzle-orm"

// Equal
const user = await db.select().from(users).where(eq(users.id, 1))

// Greater than
const recentPosts = await db
  .select()
  .from(posts)
  .where(gt(posts.createdAt, new Date("2024-01-01")))

// Like (pattern matching)
const searchUsers = await db
  .select()
  .from(users)
  .where(like(users.name, "%john%"))

// Multiple conditions
const filtered = await db
  .select()
  .from(users)
  .where(
    and(eq(users.active, true), gt(users.createdAt, new Date("2024-01-01"))),
  )

Ordering and Limiting

import { desc, asc } from "drizzle-orm"

const latestPosts = await db
  .select()
  .from(posts)
  .orderBy(desc(posts.createdAt))
  .limit(10)

const paginatedUsers = await db
  .select()
  .from(users)
  .orderBy(asc(users.name))
  .limit(20)
  .offset(40)

Transactions

export default defineEventHandler(async (event) => {
  const body = await readBody(event)

  const result = await db.transaction(async (tx) => {
    const [user] = await tx
      .insert(users)
      .values({
        name: body.name,
        email: body.email,
      })
      .returning()

    const [post] = await tx
      .insert(posts)
      .values({
        title: body.postTitle,
        authorId: user.id,
      })
      .returning()

    return { user, post }
  })

  return result
})

Migrations

Generate Migration

npx drizzle-kit generate:sqlite

Run Migration

// server/database/migrate.ts
import { migrate } from "drizzle-orm/better-sqlite3/migrator"
import { db } from "./index"

migrate(db, { migrationsFolder: "./drizzle" })

Type Safety

Drizzle provides full TypeScript type inference:

// Types are inferred automatically
const users = await db.select().from(users)
// users: { id: number; name: string; email: string; createdAt: Date }[]

// Partial selects are typed too
const names = await db.select({ name: users.name }).from(users)
// names: { name: string }[]

Using with db0 (Nitro)

// server/database/index.ts
import { drizzle } from "drizzle-orm/d1"

export default defineNitroPlugin(() => {
  // Access db0 database
  const db = drizzle(useDatabase())

  return {
    provide: {
      db,
    },
  }
})

// Usage in API routes
export default defineEventHandler(async (event) => {
  const { $db } = event.context
  const users = await $db.select().from(users)
  return users
})