Chuyển đến nội dung chính

レッスン 14: Nuxt のデータベースと ORM

Drizzle ORM、Nuxt の Prisma。データベースの移行、シード。 D1/R2 (Cloudflare) 用の nuxt-hub。リポジトリ パターン、サーバー側 CRUD。

💻 プログラミング — レッスン 14 レッスン 14: Nuxt のデータベースと ORM

Vue.js と Nuxt: 基本から高度まで

パート 4: Nuxt アドバンストおよびフルスタック

xdev.asia

1.霧雨ORMのセットアップ

npm install drizzle-orm postgres
npm install -D drizzle-kit
// server/db/schema.ts
import { pgTable, text, timestamp, boolean, integer } from 'drizzle-orm/pg-core'

export const users = pgTable('users', {
  id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
  name: text('name').notNull(),
  email: text('email').notNull().unique(),
  hashedPassword: text('hashed_password'),
  role: text('role').default('user'),
  createdAt: timestamp('created_at').defaultNow(),
})

export const posts = pgTable('posts', {
  id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
  title: text('title').notNull(),
  slug: text('slug').notNull().unique(),
  content: text('content'),
  published: boolean('published').default(false),
  authorId: text('author_id').references(() => users.id),
  viewCount: integer('view_count').default(0),
  createdAt: timestamp('created_at').defaultNow(),
  updatedAt: timestamp('updated_at').defaultNow(),
})
// server/db/index.ts
import { drizzle } from 'drizzle-orm/postgres-js'
import postgres from 'postgres'
import * as schema from './schema'

const client = postgres(process.env.DATABASE_URL!)
export const db = drizzle(client, { schema })

2. 移行

// drizzle.config.ts
import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  schema: './server/db/schema.ts',
  out: './server/db/migrations',
  dialect: 'postgresql',
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
})
npx drizzle-kit generate  # Generate migration
npx drizzle-kit migrate   # Apply migration
npx drizzle-kit studio    # Visual editor

3. CRUD操作

// server/api/posts/index.get.ts
import { db } from '~/server/db'
import { posts, users } from '~/server/db/schema'
import { eq, desc, like, and, sql } from 'drizzle-orm'

export default defineEventHandler(async (event) => {
  const query = getQuery(event)
  const page = Number(query.page || 1)
  const limit = Number(query.limit || 10)
  const search = query.search as string

  const conditions = [eq(posts.published, true)]
  if (search) {
    conditions.push(like(posts.title, `%${search}%`))
  }

  const [data, [{ count }]] = await Promise.all([
    db.select({
      id: posts.id,
      title: posts.title,
      slug: posts.slug,
      createdAt: posts.createdAt,
      author: { name: users.name },
    })
    .from(posts)
    .leftJoin(users, eq(posts.authorId, users.id))
    .where(and(...conditions))
    .orderBy(desc(posts.createdAt))
    .offset((page - 1) * limit)
    .limit(limit),

    db.select({ count: sql`count(*)`.mapWith(Number) })
      .from(posts)
      .where(and(...conditions)),
  ])

  return { data, total: count, page, limit }
})

// server/api/posts/index.post.ts
export default defineEventHandler(async (event) => {
  const user = await requireAuth(event)
  const body = await readBody(event)

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

  setResponseStatus(event, 201)
  return post
})

// server/api/posts/[id].put.ts
export default defineEventHandler(async (event) => {
  const id = getRouterParam(event, 'id')!
  const body = await readBody(event)

  const [updated] = await db.update(posts)
    .set({ ...body, updatedAt: new Date() })
    .where(eq(posts.id, id))
    .returning()

  return updated
})

4.NuxtHub (クラウドフレア)

npx nuxthub init my-app
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxthub/core'],
  hub: {
    database: true, // Cloudflare D1
    blob: true,     // Cloudflare R2
    kv: true,       // Cloudflare KV
  },
})

// server/api/posts.get.ts — using D1
export default defineEventHandler(async () => {
  const db = hubDatabase()
  return db.prepare('SELECT * FROM posts WHERE published = 1').all()
})

次の記事: ファイルのアップロード、画像、SEO — アップロード、@nuxt/image、メタデータ。