Community编程与开发github.com

lobehub/drizzle

LobeHub Drizzle ORM 的架构和查询样式。适用于 pgTable 架构、索引、连接、推断类型、db.select/db.query、架构字段、外键、连接表或 Postgres 查询模式。

drizzle 是什么?

该技能提供了 LobeHub 团队使用的 Drizzle ORM 编码风格和最佳实践,专为 PostgreSQL 数据库设计。它涵盖了 pgTable 架构定义、索引创建、表连接、类型推断、标准 db.select/db.query 查询、架构字段配置、外键约束、连接表(多对多辅助表)以及各种 Postgres 查询模式。技能文档详细展示了如何定义表结构(包括列约束、默认值、生成列)、创建复合索引、构建显式外键关系以及处理可选字段。此外,还说明了如何通过 Drizzle 的类型推断功能获取精确的插入/选择类型,以及如何在 db.select 中使用带 where 过滤器的复杂查询和 db.query 的链式查询语法。该技能适用于任何使用 Drizzle ORM 的 PostgreSQL 项目,尤其是希望保持代码风格一致性和高效开发的组织。支持平台包括但不仅限于 Claude Code、Cursor、Codex 等支持自定义技能/规则的 AI 编码助手。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/lobehub/lobe-chat/tree/main/skills/drizzle

Installed? Explore more 编程与开发 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

drizzle 是做什么的?

LobeHub Drizzle ORM 架构和查询样式。适用于 pgTable 架构、索引、连接、推断类型、db.select/db.query、架构字段、外键、连接表或 Postgres 查询模式。

表定义

使用 pgTable 定义表,并通过 inferSelectSchema 和 inferInsertSchema 推断类型。

import { pgTable, uuid, text, timestamp, integer, boolean, jsonb, foreignKey, uniqueIndex } from 'drizzle-orm/pg-core';
import { createInsertSchema, createSelectSchema } from 'drizzle-zod';

export const users = pgTable('users', {
  id: uuid('id').defaultRandom().primaryKey(),
  name: text('name').notNull(),
  email: text('email').notNull().unique(),
  age: integer('age'),
  isActive: boolean('is_active').default(true),
  metadata: jsonb('metadata').$type<Record<string, unknown>>().default({}),
  createdAt: timestamp('created_at').defaultNow().notNull(),
  updatedAt: timestamp('updated_at').defaultNow().notNull(),
});

// 推断类型
export type User = typeof users.$inferSelect;
export type NewUser = typeof users.$inferInsert;

索引和约束

import { index, uniqueIndex, foreignKey } from 'drizzle-orm/pg-core';

export const posts = pgTable('posts', {
  id: uuid('id').defaultRandom().primaryKey(),
  title: text('title').notNull(),
  slug: text('slug').notNull().unique(),
  content: text('content'),
  authorId: uuid('author_id').notNull(),
  publishedAt: timestamp('published_at'),
  createdAt: timestamp('created_at').defaultNow().notNull(),
}, (table) => ({
  titleIdx: index('title_idx').on(table.title),
  authorIdx: index('author_idx').on(table.authorId),
  uniqueSlugIdx: uniqueIndex('unique_slug_idx').on(table.slug),
  authorFk: foreignKey({
    columns: [table.authorId],
    foreignColumns: [users.id],
    name: 'fk_post_author'
  }),
}));

连接表

export const categories = pgTable('categories', {
  id: uuid('id').defaultRandom().primaryKey(),
  name: text('name').notNull(),
  slug: text('slug').notNull().unique(),
});

export const postCategories = pgTable('post_categories', {
  postId: uuid('post_id').notNull().references(() => posts.id, { onDelete: 'cascade' }),
  categoryId: uuid('category_id').notNull().references(() => categories.id, { onDelete: 'cascade' }),
}, (table) => ({
  pk: primaryKey({ columns: [table.postId, table.categoryId] }),
}));

查询模式

使用 db.select

// 基础查询
const allUsers = await db.select().from(users);

// 带过滤器的查询
const activeUsers = await db.select()
  .from(users)
  .where(eq(users.isActive, true));

// 连接查询
const postsWithAuthor = await db.select({
  post: posts,
  author: users,
})
  .from(posts)
  .leftJoin(users, eq(posts.authorId, users.id));

// 聚合查询
import { count, avg } from 'drizzle-orm';
const userStats = await db.select({
  totalUsers: count(),
  averageAge: avg(users.age),
})
  .from(users);

使用 db.query

// 通过主键查找
const user = await db.query.users.findFirst({
  where: eq(users.id, userId),
});

// 带关系的查找
const postWithRelations = await db.query.posts.findFirst({
  where: eq(posts.id, postId),
  with: {
    author: true,
    categories: {
      with: {
        category: true,
      },
    },
  },
});

// 列表查询
const recentPosts = await db.query.posts.findMany({
  limit: 10,
  orderBy: [desc(posts.createdAt)],
  where: isNotNull(posts.publishedAt),
});

插入和更新

// 插入
const newUser = await db.insert(users).values({
  name: 'John Doe',
  email: '[email protected]',
}).returning();

// 批量插入
await db.insert(users).values([
  { name: 'User 1', email: '[email protected]' },
  { name: 'User 2', email: '[email protected]' },
]);

// 更新
await db.update(users)
  .set({ name: 'Jane Doe', updatedAt: new Date() })
  .where(eq(users.id, userId));

// 删除
await db.delete(users)
  .where(eq(users.id, userId));

可选字段和默认值

export const products = pgTable('products', {
  id: uuid('id').defaultRandom().primaryKey(),
  name: text('name').notNull(),
  description: text('description'), // 可选字段
  price: integer('price').notNull(),
  discount: integer('discount').default(0),
  isAvailable: boolean('is_available').default(true),
  attributes: jsonb('attributes').$type<Record<string, unknown>>().default({}),
  createdAt: timestamp('created_at').defaultNow().notNull(),
});

生成的列

// Drizzle Kit 支持生成列(PostgreSQL 15+)
export const orders = pgTable('orders', {
  id: uuid('id').defaultRandom().primaryKey(),
  subtotal: integer('subtotal').notNull(),
  tax: integer('tax').notNull(),
  total: integer('total').generatedAlwaysAs().notNull(), // 计算列
});

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

相关技能