mcpField
D
drizzle-sqlite-scaffold

drizzle-sqlite-scaffold

github.com/pproenca数据与数据库218140 次安装11 周前更新
代码仓库

关于 drizzle-sqlite-scaffold

这项模板技能可用于初始化 Drizzle 与 SQLite 项目,或为现有项目添加表和 CRUD 仓库模块,适合希望统一配置、模式与代码约定的开发者。

主要功能

  1. 01项目初始化模板
  2. 02按表生成模式与 CRUD 模板
  3. 03可选 SQLite 驱动配置
  4. 04可选 drizzle-zod 验证器
  5. 05迁移操作指引

适用场景

  1. 01启动 Drizzle SQLite 项目
  2. 02为现有模式添加数据表
  3. 03为现有数据表创建 CRUD 模块
  4. 04统一手写 Drizzle 配置

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/pproenca/dot-skills --skill drizzle-sqlite-scaffold

安装后在 Claude Code 中输入/drizzle-sqlite-scaffold确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

config.json
gotchas.md
metadata.json
assets/templates/
client.better-sqlite3.ts.template
client.bun-sqlite.ts.template
client.libsql.ts.template
drizzle.config.local.ts.template
drizzle.config.turso.ts.template
gitignore.template
repository.ts.template
schema-index.ts.template
table.ts.template
validators.ts.template
references/
conventions.md

详细介绍

Drizzle SQLite 脚手架

用于在全新项目中引导 Drizzle + SQLite,或在现有项目中添加新表/仓库的参数化模板。每个输出都遵循 references/conventions.md 中记录的约定——显式主键、带索引的外键、relations() 声明、$inferSelect/$inferInsert 导出、timestamp_ms 日期、布尔模式的布尔值、WAL + foreign_keys=ON + busy_timeout pragma、带 HMR 保护的单例客户端,以及使用 .returning() + inArray() + .onConflictDoUpdate() 的 CRUD 辅助函数。

适用场景

以下情况可使用这些模板:

  • 开始一个将使用 Drizzle 和 SQLite(任意驱动)的新项目
  • 为现有 Drizzle 项目添加新表——表文件应符合现有模式
  • 为现有表添加 CRUD 仓库模块
  • 重构手动搭建的 Drizzle 设置,例如缺少 pragma、没有 relations(),或手写的 User 类型与架构定义不一致
  • 从其他 ORM(Prisma、Kysely)迁移到 Drizzle,并希望从一开始就保持结构一致

设置

必需参数(首次使用时询问,并保存到 config.json)
参数必需默认值取值
driver是—better-sqlite3 | libsql | bun-sqlite(D1 的生命周期不同——参见下文“Cloudflare D1”)
db_url_env否DATABASE_URL环境变量名称
schema_dir否./src/db/schema每个表对应的架构文件
repository_dir否./src/db/repository每个表对应的 CRUD 模块
validators_dir否./src/db/validatorsdrizzle-zod 架构(当 with_zod=true 时)
client_path否./src/db/client.ts单例客户端模块
migrations_dir否./drizzledrizzle-kit 输出目录

如果 config.json 中已有值,此技能会使用这些值;否则会通过 AskUserQuestion 询问。

每表参数(每次搭建新表时询问)
参数必需默认值描述
name是—单数形式的 kebab-case 名称:user、order-item。用于文件名和 TS 标识符(派生出 name_camel、name_pascal)。
table_name否name 的 snake_case 复数形式SQL 表名:users、order_items
pk否serial-intserial-int | uuid | cuid2 | text
timestamps否true添加 createdAt/updatedAt 列
soft_delete否false添加可空的 deletedAt + 部分索引
relations否[]相关表名列表——用于扩展 relations() 主体
with_zod否true生成 drizzle-zod 验证器文件

可用模板

项目初始化模板(仅生成一次)
模板输出文件使用时机
drizzle.config.local.ts.templatedrizzle.config.tsdriver 为 better-sqlite3、bun-sqlite,或使用 file: URL 的 libsql
drizzle.config.turso.ts.templatedrizzle.config.tsdriver 为连接到 Turso 的 libsql(远程 libsql: URL)
client.better-sqlite3.ts.template{{client_path}}driver 为 better-sqlite3
client.libsql.ts.template{{client_path}}driver 为 libsql
client.bun-sqlite.ts.template{{client_path}}driver 为 bun-sqlite
schema-index.ts.template{{schema_dir}}/index.ts始终(初始为空;添加表时追加导出项)
gitignore.template.gitignore(追加)始终
每张表的模板(每张表生成一次)
模板输出文件适用时机
table.ts.template{{schema_dir}}/{{name}}.ts每张表
repository.ts.template{{repository_dir}}/{{name}}.ts每张表
validators.ts.template{{validators_dir}}/{{name}}.tswith_zod=true 时,每张表

使用方法

流程 A — 初始化新项目(运行一次)
  1. 解析项目参数。 读取 config.json。对于任何未填写的必填字段,通过 AskUserQuestion 询问用户(只有 driver 是严格必填项;其余字段都有合理的默认值)。

  2. 先安装运行时和工具,确保渲染后的文件能立即通过类型检查:

    # Pick the driver-specific runtime package:
    npm install drizzle-orm @libsql/client      # for libsql
    npm install drizzle-orm better-sqlite3      # for better-sqlite3
    npm install drizzle-orm                     # bun:sqlite is built into Bun
    
    # Dev tools (all drivers):
    npm install -D drizzle-kit
    npm install -D @types/better-sqlite3        # better-sqlite3 only
    npm install -D drizzle-zod zod              # if with_zod=true
    
  3. 根据解析出的 driver 选择配置和客户端变体:

    • better-sqlite3 → drizzle.config.local.ts.template + client.better-sqlite3.ts.template
    • 使用 file: URL 的 libsql → drizzle.config.local.ts.template + client.libsql.ts.template
    • 使用远程 Turso URL 的 libsql → drizzle.config.turso.ts.template + client.libsql.ts.template
    • bun-sqlite → drizzle.config.local.ts.template + client.bun-sqlite.ts.template
  4. 渲染并写入项目初始化文件:

    • drizzle.config.ts
    • {{client_path}}(通常为 src/db/client.ts)
    • {{schema_dir}}/index.ts(空的汇总文件)
    • 将 gitignore.template 中的代码块追加到项目的 .gitignore
  5. **对于 libsql:**客户端模板使用顶层 await migrate(...)。确认 tsconfig.json 中的 "module": "ESNext"(或 "NodeNext")和 "target": "ES2022"+,以支持顶层 await。如果运行时使用 CommonJS,则将顶层 await 替换为一个导出的 async function init(),并由应用在启动时调用。

  6. 将解析出的值保存到 config.json,以便后续添加表时无需再次询问。

流程 B — 添加新表(每张表运行一次)
  1. 解析每张表的参数。 先询问用户 name,然后为 table_name(snake_case 复数)、pk、timestamps、soft_delete、relations、with_zod 提供默认值。对于用户希望使用的任何非默认值,使用 AskUserQuestion 询问。

  2. 计算派生标识符:

    • name_camel — name 的 camelCase 形式(user、orderItem)
    • name_pascal — name 的 PascalCase 形式(User、OrderItem)
    • pk_field — PK 列名(所有 4 种 pk 模式均为 id)
    • pk_ts_type — PK 的 TS 类型(serial-int 对应 number,uuid/cuid2/text 对应 string)
    • pk_definition — 实际代码行,例如 id: integer().primaryKey({ autoIncrement: true }),(参见下方的 PK 变体表)
  3. **渲染表模板:**读取 table.ts.template,替换 {{name}}、{{name_camel}}、{{name_pascal}}、{{table_name}}、{{pk_definition}}、{{pk_extra_imports}} 等占位符。根据参数展开 {{timestamps_block}} 和 {{soft_delete_block}}(参见下方的“代码块展开”)。写入 {{schema_dir}}/{{name}}.ts。

  4. **使用相同的参数渲染仓库模板。**写入 {{repository_dir}}/{{name}}.ts。

  5. 如果 with_zod=true,渲染验证器模板。写入 {{validators_dir}}/{{name}}.ts。

  6. **追加到 schema 汇总文件:**将 export * from './{{name}}'; 添加到 {{schema_dir}}/index.ts。

  7. **生成迁移:**告知用户运行 npx drizzle-kit generate 以生成 SQL 文件。提醒用户,如果此脚手架替换了名称不同的现有表,必须明确回答重命名提示。

  8. **应用迁移:**针对开发数据库运行 npx drizzle-kit migrate。客户端模板也会在启动时调用 migrate(...),但在开发循环中先应用一次,可以在下次进程重启前确认 SQL 能正常运行。

流程 C — 为现有表添加 CRUD 模块(不更改 schema)

与流程 B 的步骤 1-2 相同,但跳过 table.ts.template 渲染,仅生成 repository 模块(以及可选的 validators 模块)。

主键变体

pk 值pk_definitionpk_ts_type额外导入
serial-int(默认)id: integer().primaryKey({ autoIncrement: true }),number—
uuidid: text().primaryKey().$defaultFn(() => crypto.randomUUID()),string—(使用 Web Crypto)
cuid2id: text().primaryKey().$defaultFn(() => createId()),stringimport { createId } from '@paralleldrive/cuid2';
textid: text().primaryKey(),string—(由调用方提供 ID)

占位符参考

模板使用的每个 {{placeholder}} 及其派生规则。标记为 简单替换 的项目可直接查找并替换;标记为 块 的项目需要 Agent 按下一节中的规则展开。

占位符类型来源 / 派生规则
{{driver}}简单替换config.json:driver
{{db_url_env}}简单替换config.json:db_url_env
{{schema_dir}}简单替换config.json:schema_dir
{{repository_dir}}简单替换config.json:repository_dir
{{validators_dir}}简单替换config.json:validators_dir
{{client_path}}简单替换config.json:client_path
{{migrations_dir}}简单替换config.json:migrations_dir
{{schema_index_import}}简单替换派生:client_path → 到 {{schema_dir}}/index.ts 的相对路径(通常为 './schema')
{{client_import}}简单替换派生:从 repository 文件返回 client_path 的相对路径(通常为 '../client')
{{schema_import}}简单替换派生:从 repository 或 validators 文件到对应表文件的相对路径(通常为 '../schema/{{name}}')
{{name}}简单替换每表参数——kebab-case 单数形式(user)
{{name_camel}}简单替换根据 name 派生(user、orderItem)
{{name_pascal}}简单替换根据 name 派生(User、OrderItem)
{{table_name}}简单替换每表参数,默认值为 name 的 snake_case 复数形式(users、order_items)
{{pk}}元数据每表参数——serial-int | uuid | cuid2 | text(决定下面各行的内容)
{{pk_definition}}块实际的 PK 列定义行——参见“PK 变体”表
{{pk_field}}简单替换此技能提供的四种 PK 变体均为 id
{{pk_ts_type}}简单替换serial-int 对应 number,uuid / cuid2 / text 对应 string
{{pk_extra_imports}}块serial-int / uuid / text 时为空;cuid2 时为 import { createId } from '@paralleldrive/cuid2';
{{relation_imports}}块对于 relations[] 中的每张表,生成一行 import { {{relatedCamel}} } from './{{related-kebab}}';
{{domain_columns}}块Agent(或用户)将其替换为实体中实际的非 PK、非时间戳列。如果用户尚未提供这些列,请保留为 TODO 注释。
{{timestamps_block}}块参见下方展开规则——当 timestamps=true 时生成;当为 false 时删除整行
{{soft_delete_block}}块参见下方展开规则——当 soft_delete=true 时在列块中生成
{{indexes}}块每个外键列生成一行 index(...)(以及用户需要的任何 (authorId, publishedAt) 风格的复合索引)
{{soft_delete_index}}块deletedAt 上的部分索引(参见下方展开规则);仅当 soft_delete=true 时生成
{{relations_body}}块每张相关表生成一行 one(...) / many(...);参见下方展开规则
{{insert_refinements}}块INSERT 形状的 drizzle-zod refinement 回调;如果未提供,请保留示例注释
{{update_refinements}}块与部分 UPDATE 形状相同
{{exports}}块在 schema-index.ts.template 中,每张表生成一行 export * from './{{name}}';;每次新增表时追加

如果模板输出了本表未列出的 {{placeholder}},则说明存在错误——请记录到 gotchas.md 中。

块展开

table.ts.template 使用占位符 块 表示形状可变的部分——Agent 必须根据参数展开,而不能只进行文本替换。

{{timestamps_block}}(当 timestamps=true 时)
createdAt: integer({ mode: 'timestamp_ms' })
  .notNull()
  .$defaultFn(() => new Date()),
updatedAt: integer({ mode: 'timestamp_ms' })
  .notNull()
  .$defaultFn(() => new Date())
  .$onUpdateFn(() => new Date()),

当 timestamps=false 时,删除整行(不要保留注释标记)。

{{soft_delete_block}}(当 soft_delete=true 时)

在列块中:

deletedAt: integer({ mode: 'timestamp_ms' }),

在索引块中:

index('{{table_name}}_active_idx').on(table.deletedAt).where(sql`deleted_at IS NULL`),

相应调整 sql 导入。

{{relations_body}}(当 relations 非空时)

对于 relations[] 中的每个关联表,Agent 会根据外键所在的位置判断它是 one 还是 many:如果外键位于当前表中,则为 one;如果位于关联表中,则为 many:

// FK on current table — `one`:
parent: one(parents, { fields: [users.parentId], references: [parents.id] }),

// FK on related table — `many`:
posts: many(posts),

如果用户不容易判断,请默认各提供一个示例,并留下注释。

{{indexes}} 块

对于每个外键列,生成:

index('{{table_name}}_{{column}}_idx').on(table.{{columnCamel}}),

Cloudflare D1 说明

D1 的生命周期有所不同:客户端会在每个请求中根据 env.DB(绑定)创建,而不是作为模块级单例。此技能不提供 D1 客户端模板;请遵循官方 D1 + Drizzle 指南进行接线。table.ts.template、repository.ts.template 和 validators.ts.template 仍可用于 D1,只有客户端模块不同。

参考文件

文件说明
references/conventions.md强制执行的 11 项约定,包含原因和规则交叉引用
gotchas.md随时间发现的边缘情况
metadata.json版本和驱动程序参考
config.json项目级参数存储

相关技能

  • drizzle-sqlite — 这些模板所编码的库参考规则。约定文档会引用其中的特定规则文件名。需要做出有依据的例外、调试生成的文件,或搭建模板范围之外的内容(自定义迁移、复杂查询、性能工作)时,请阅读此文档。
  • better-auth-scaffold — 在 Drizzle DB 上搭建 Better Auth;此技能提供客户端后,可运行此技能。

评论

支持 Markdown