refactor: 降级 Drizzle ORM 至 0.45.x 稳定版,对齐 Better Auth 兼容性
- drizzle-orm 1.0.0-beta.15 → 0.45.2, drizzle-kit → 0.31.10 - RQBv2 defineRelations() → 旧版 relations() 回调语法 - drizzle-orm/zod → drizzle-zod 独立包 - auth/schema.ts 改由 Better Auth CLI 生成(bun run db:auth) - db/schema/index.ts 选择性导出表(不导出生成文件中的旧版 relations) - 删除 db:push script,强制 db:generate → db:migrate 工作流 - 重建迁移基线(删除旧迁移目录,全新生成初始迁移)
This commit is contained in:
+20
-17
@@ -8,7 +8,7 @@ TanStack Start fullstack web app with ORPC (contract-first RPC) and shadcn/ui.
|
||||
|
||||
- **Framework**: TanStack Start (React 19 SSR, file-based routing)
|
||||
- **Styling**: Tailwind CSS v4 + shadcn/ui (base-nova style, `@base-ui/react`)
|
||||
- **Database**: PostgreSQL + Drizzle ORM v1 beta (`drizzle-orm/postgres-js`, RQBv2)
|
||||
- **Database**: PostgreSQL + Drizzle ORM 0.45.x (`drizzle-orm/postgres-js`)
|
||||
- **State**: TanStack Query v5 (with MutationCache auto-invalidation)
|
||||
- **RPC**: ORPC (contract-first, type-safe)
|
||||
- **Auth**: Better Auth (email+password, single-owner, self-hosted)
|
||||
@@ -99,7 +99,7 @@ src/
|
||||
### 1. Define Contract (in module: `src/modules/feature/contract.ts`)
|
||||
```typescript
|
||||
import { oc } from '@orpc/contract'
|
||||
import { createInsertSchema, createSelectSchema, createUpdateSchema } from 'drizzle-orm/zod'
|
||||
import { createInsertSchema, createSelectSchema, createUpdateSchema } from 'drizzle-zod'
|
||||
import { z } from 'zod'
|
||||
import * as schema from '@/modules/feature/schema'
|
||||
import { generatedFieldKeys } from '@/server/db/fields'
|
||||
@@ -128,8 +128,8 @@ export const myResource = {
|
||||
.use(dbMiddleware).use(authMiddleware)
|
||||
.handler(async ({ context }) => {
|
||||
return await context.db.query.myTable.findMany({
|
||||
where: { userId: context.user.id },
|
||||
orderBy: { createdAt: 'desc' },
|
||||
where: (t, { eq }) => eq(t.userId, context.user.id),
|
||||
orderBy: (t, { desc }) => desc(t.createdAt),
|
||||
})
|
||||
}),
|
||||
|
||||
@@ -244,14 +244,16 @@ toast.success('操作成功')
|
||||
toast.error('操作失败')
|
||||
```
|
||||
|
||||
## Database (Drizzle ORM v1 beta)
|
||||
## Database (Drizzle ORM 0.45.x)
|
||||
|
||||
- **Driver**: `drizzle-orm/postgres-js` (NOT `bun-sql`)
|
||||
- **Validation**: `drizzle-orm/zod` (built-in, NOT separate `drizzle-zod` package)
|
||||
- **Relations**: `defineRelations()` in `src/server/db/relations.ts` — RQBv2 object syntax
|
||||
- **Validation**: `drizzle-zod` (separate package, NOT `drizzle-orm/zod`)
|
||||
- **Relations**: `relations()` from `drizzle-orm` in `src/server/db/relations.ts` — callback syntax
|
||||
- **Table naming**: No `Table` suffix — `user`, `category`, `bookmark`
|
||||
- **DB instance**: Module-level singleton `export const db = drizzle(...)` (NOT factory pattern)
|
||||
- **DB instance**: Module-level singleton `export const db = drizzle(client, { schema })` (NOT factory pattern)
|
||||
- **Shared fields**: Use `...generatedFields` spread for id/createdAt/updatedAt
|
||||
- **Auth schema**: Generated by Better Auth CLI (`bun run db:auth`), **never hand-edit**
|
||||
- **Schema re-export**: `db/schema/index.ts` selectively exports tables only (not relations) from auth schema
|
||||
- **Migration workflow**: Always `db:generate` → `db:migrate`. **Never** use `db:push`.
|
||||
- **Path alias exception**: Files in the Drizzle schema chain (`db/schema/index.ts`, module `schema.ts`) MUST use relative imports — `drizzle-kit` does not resolve `@/*` aliases.
|
||||
|
||||
@@ -263,11 +265,12 @@ export const myTable = pgTable('my_table', {
|
||||
userId: text('user_id').notNull().references(() => user.id, { onDelete: 'cascade' }),
|
||||
})
|
||||
|
||||
// Relations — RQBv2 defineRelations
|
||||
export const relations = defineRelations(schema, (r) => ({
|
||||
myTable: {
|
||||
user: r.one.user({ from: r.myTable.userId, to: r.user.id }),
|
||||
},
|
||||
// Relations — callback syntax
|
||||
export const myTableRelations = relations(myTable, ({ one }) => ({
|
||||
user: one(user, {
|
||||
fields: [myTable.userId],
|
||||
references: [user.id],
|
||||
}),
|
||||
}))
|
||||
```
|
||||
|
||||
@@ -293,8 +296,8 @@ Kairos is a self-hosted single-user app. There is NO public registration. The fi
|
||||
- Use `@/*` path aliases (not relative imports)
|
||||
- Use `render` prop (NOT `asChild`) for base-ui component delegation
|
||||
- Use `ORPCError` with proper codes
|
||||
- Use `drizzle-orm/zod` (NOT `drizzle-zod`)
|
||||
- Use RQBv2 object syntax for `orderBy` and `where`
|
||||
- Use `drizzle-zod` for schema validation (NOT `drizzle-orm/zod`)
|
||||
- Use callback syntax for `orderBy` and `where` in relational queries
|
||||
- Use `move()` from `@dnd-kit/helpers` for DnD reordering
|
||||
- Use `useState` callback ref for virtualizer scroll elements inside Dialogs
|
||||
|
||||
@@ -302,9 +305,9 @@ Kairos is a self-hosted single-user app. There is NO public registration. The fi
|
||||
- Add new `src/components/ui/*.tsx` without CLI (use `bunx shadcn@latest add` to scaffold, then freely customize)
|
||||
- Edit `src/routeTree.gen.ts` (auto-generated)
|
||||
- Use `asChild` prop (base-ui uses `render`, NOT Radix)
|
||||
- Import from `drizzle-zod` (use `drizzle-orm/zod`)
|
||||
- Import from `drizzle-orm/zod` (use `drizzle-zod`)
|
||||
- Use `drizzle-orm/bun-sql` driver
|
||||
- Pass `schema` to `drizzle()` constructor (only `relations` needed in RQBv2)
|
||||
- Hand-edit `src/server/auth/schema.ts` (generated by Better Auth CLI, use `bun run db:auth`)
|
||||
- Add `Table` suffix to Drizzle table exports
|
||||
- Use `useRef` for scroll elements inside Dialog/conditional rendering
|
||||
- Use `db:push` — always use `db:generate` → `db:migrate`
|
||||
|
||||
Reference in New Issue
Block a user