Initial commit
This commit is contained in:
313
skills/nuxt/references/drizzle-db0.md
Normal file
313
skills/nuxt/references/drizzle-db0.md
Normal file
@@ -0,0 +1,313 @@
|
||||
# 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
|
||||
|
||||
```typescript
|
||||
// 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
|
||||
|
||||
```typescript
|
||||
// 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
|
||||
|
||||
```typescript
|
||||
// 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
|
||||
|
||||
```typescript
|
||||
// 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
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```typescript
|
||||
// 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
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```bash
|
||||
npx drizzle-kit generate:sqlite
|
||||
```
|
||||
|
||||
### Run Migration
|
||||
|
||||
```typescript
|
||||
// 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:
|
||||
|
||||
```typescript
|
||||
// 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)
|
||||
|
||||
```typescript
|
||||
// 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
|
||||
})
|
||||
```
|
||||
Reference in New Issue
Block a user