6.2 KiB
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
})