使用Drizzle ORM(PostgreSQL)执行onConflictDoUpdate时数组追加报错
问题解决:Drizzle ORM PostgreSQL数组更新语法错误
问题背景
使用Drizzle ORM操作PostgreSQL的users表时,尝试在ON CONFLICT逻辑中用array_append更新INET类型数组字段ipList,代码触发syntax error at or near ")"报错;移除该更新字段后代码可正常运行,希望保留类型安全,不想使用db.execute()执行原生SQL。
当前代码:
const res = await db.insert(UsersTable) .values(newUser) .onConflictDoUpdate({ target: UsersTable.email, set: { ipList:sql`array_append(${UsersTable.ipList}, ${newUser.ipList})` } }) .returning({ insertedId: UsersTable.id });
期望生成的SQL:
INSERT INTO users (email, ip_list, name, phone, is_admin, password) VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (email) DO UPDATE SET ip_list = array_append(users.ip_list, $7::INET[]) RETURNING id;
解决方案
方案1:使用Drizzle内置数组操作函数(推荐,保留类型安全)
从drizzle-orm/pg-core导入arrayAppend函数,直接用它构建更新逻辑,Drizzle会自动处理参数绑定与类型转换:
import { arrayAppend } from 'drizzle-orm/pg-core'; // ... const res = await db.insert(UsersTable) .values(newUser) .onConflictDoUpdate({ target: UsersTable.email, set: { ipList: arrayAppend(UsersTable.ipList, newUser.ipList), } }) .returning({ insertedId: UsersTable.id });
方案2:手动在SQL模板中指定类型转换
如果不想使用内置函数,可在SQL模板里明确给参数添加类型转换,确保PostgreSQL正确识别数组类型:
const res = await db.insert(UsersTable) .values(newUser) .onConflictDoUpdate({ target: UsersTable.email, set: { ipList: sql`array_append(${UsersTable.ipList}, ${newUser.ipList}::inet[])`, } }) .returning({ insertedId: UsersTable.id });
原因分析
之前的写法报错,是因为Drizzle处理直接传入的数组参数时,未自动完成正确的类型序列化,导致生成的SQL中数组格式不符合PostgreSQL要求,触发语法错误。上述两种方法要么通过内置函数自动处理类型,要么手动指定类型转换,都能让Drizzle生成符合预期的SQL,同时保留TypeScript的类型安全特性。
内容的提问来源于stack exchange,提问作者Pedro Santos
相关产品推荐
相关产品推荐

