关于 electric-orm
面向将 Electric 与 ORM 集成的开发者,说明使用 Drizzle ORM 或 Prisma 进行写入及迁移时需要关注的配置。重点包括事务内 txid、REPLICA IDENTITY 和 TanStack DB 集合。
主要功能
- 01集成 Drizzle ORM
- 02集成 Prisma
- 03迁移中设置 REPLICA IDENTITY
- 04通过 txid 协调写入
- 05配置 TanStack DB 集合
适用场景
- 01通过 ORM 写入并协调 Electric 同步
- 02创建支持更新和删除流式传输的迁移
- 03将 ORM 写入连接到 TanStack DB 集合
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ electric-sql/ electric --skill electric-orm安装后在 Claude Code 中输入/electric-orm确认已加载。
详细介绍
此技能基于 electric-shapes 和 electric-schema-shapes。请先阅读这两项内容。
Electric — ORM 集成
设置
Drizzle ORM
import { drizzle } from 'drizzle-orm/node-postgres'
import { sql } from 'drizzle-orm'
import { todos } from './schema'
const db = drizzle(pool)
// Write with txid for Electric reconciliation
async function createTodo(text: string, userId: string) {
return await db.transaction(async (tx) => {
const [row] = await tx
.insert(todos)
.values({
id: crypto.randomUUID(),
text,
userId,
})
.returning()
const [{ txid }] = await tx.execute<{ txid: string }>(
sql`SELECT pg_current_xact_id()::xid::text AS txid`
)
return { id: row.id, txid: parseInt(txid) }
})
}
Prisma
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
async function createTodo(text: string, userId: string) {
return await prisma.$transaction(async (tx) => {
const todo = await tx.todo.create({
data: { id: crypto.randomUUID(), text, userId },
})
const [{ txid }] = await tx.$queryRaw<[{ txid: string }]>`
SELECT pg_current_xact_id()::xid::text AS txid
`
return { id: todo.id, txid: parseInt(txid) }
})
}
核心模式
使用 REPLICA IDENTITY 进行 Drizzle 迁移
// In migration file
import { sql } from 'drizzle-orm'
export async function up(db) {
await db.execute(sql`
CREATE TABLE todos (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
text TEXT NOT NULL,
completed BOOLEAN DEFAULT false
)
`)
await db.execute(sql`ALTER TABLE todos REPLICA IDENTITY FULL`)
}
使用 REPLICA IDENTITY 进行 Prisma 迁移
-- prisma/migrations/001_init/migration.sql
CREATE TABLE "todos" (
"id" UUID PRIMARY KEY DEFAULT gen_random_uuid(),
"text" TEXT NOT NULL,
"completed" BOOLEAN DEFAULT false
);
ALTER TABLE "todos" REPLICA IDENTITY FULL;
使用 ORM 的 Collection onInsert
import { createCollection } from '@tanstack/react-db'
import { electricCollectionOptions } from '@tanstack/electric-db-collection'
export const todoCollection = createCollection(
electricCollectionOptions({
id: 'todos',
schema: todoSchema,
getKey: (row) => row.id,
shapeOptions: { url: '/api/todos' },
onInsert: async ({ transaction }) => {
const newTodo = transaction.mutations[0].modified
const { txid } = await createTodo(newTodo.text, newTodo.userId)
return { txid }
},
})
)
常见错误
高:ORM 写入操作未返回 txid
错误:
// Drizzle — no txid returned
const [todo] = await db.insert(todos).values({ text: 'New' }).returning()
return { id: todo.id }
正确:
// Drizzle — txid in same transaction
const result = await db.transaction(async (tx) => {
const [row] = await tx.insert(todos).values({ text: 'New' }).returning()
const [{ txid }] = await tx.execute<{ txid: string }>(
sql`SELECT pg_current_xact_id()::xid::text AS txid`
)
return { id: row.id, txid: parseInt(txid) }
})
ORM 默认不会返回 pg_current_xact_id()。请在同一事务中添加原始 SQL 查询以获取 txid。否则,同步版本到达前,乐观状态可能会消失,导致 UI 闪烁。
来源:AGENTS.md:116-119
中:运行会删除副本标识的迁移
错误:
// ORM migration recreates table without REPLICA IDENTITY
await db.execute(sql`DROP TABLE todos`)
await db.execute(sql`CREATE TABLE todos (...)`)
// Missing: ALTER TABLE todos REPLICA IDENTITY FULL
正确:
await db.execute(sql`DROP TABLE todos`)
await db.execute(sql`CREATE TABLE todos (...)`)
await db.execute(sql`ALTER TABLE todos REPLICA IDENTITY FULL`)
某些迁移工具会重置表属性。请务必确保重建表后设置了 REPLICA IDENTITY FULL。否则,Electric 将无法正确流式传输更新和删除操作。
来源:website/docs/guides/troubleshooting.md:373
另请参阅:electric-new-feature/SKILL.md — 完整写入路径流程,包括 txid 握手。 另请参阅:electric-schema-shapes/SKILL.md — 架构设计会影响 shapes 和 ORM 查询。
版本
目标版本为 @electric-sql/client v1.5.10。
评论
支持 Markdown