import type { DatabaseTransaction } from '@atlas/database'; import { ApiError } from './api-error.js'; /** * Shared optimistic-lock conflict response. Versioned writes still keep their * domain-specific SET clauses, but they must use a conditional `revision = * expected` update and this helper when no row was affected. */ const resources = { collection_item: { table: 'atlas.collection_items', label: '采集记录', active: ' AND deleted_at IS NULL', }, product: { table: 'atlas.products', label: '商品', active: '' }, product_platform_profile: { table: 'atlas.product_platform_profiles', label: '商品发布配置', active: '', }, } as const; export async function throwRevisionConflict( transaction: DatabaseTransaction, resource: keyof typeof resources, id: string, expected: number, ): Promise { const target = resources[resource]; const current = await transaction.query<{ revision: number }>( `SELECT revision FROM ${target.table} WHERE id = $1${target.active}`, [id], ); if (!current.rows[0]) throw new ApiError(404, 'RESOURCE_NOT_FOUND', `${target.label}不存在`); if (current.rows[0].revision !== expected) { throw new ApiError(409, 'VERSION_CONFLICT', `${target.label}已被更新`, [ { field: 'If-Match', code: 'VERSION_CONFLICT', message: `当前版本为 ${current.rows[0].revision}`, current_revision: current.rows[0].revision, }, ]); } // A conditional write with a matching version affecting no rows is a // resource-state error (for example, a concurrent soft delete), not a // successful retry. throw new ApiError(409, 'VERSION_CONFLICT', `${target.label}状态已变化`); }