Archived
M5(3/3): trigger —— 三类触发器与起单幂等
- matchesEvent:事件触发的命中判定(S-FEEL 规则;规则写坏按不命中处置,不让事件流停摆) - assembleInput:字段映射装配;缺必填即起单失败入死信,不静默丢弃 - 幂等:同一事件对同一触发器至多起一单;数据日历型同一行同一日期只触发一次 - 周期两型:日历表达式到点扫描 + 数据日历型(日期字段 + 偏移 + 过滤)逐行起单 - 登记触发:人工起单的统一形态,登记人即来源 - 触发器与流程包平级:配置独立存放,增删启停不改流程包版本 340 个测试通过,门禁五道全绿 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
co-authored by
Claude Opus 5
parent
a8f6eef610
commit
4ad901c452
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* trigger 存储 adapter —— Drizzle 只准出现在 adapter(编码规范 §5.3)。
|
||||
*/
|
||||
import { eq } from 'drizzle-orm';
|
||||
import type { TriggerConfig } from '@contracts';
|
||||
import { triggerConfigSchema } from '@contracts';
|
||||
import type { Db } from '@shared/db.ts';
|
||||
import type { TriggerStore } from '../../port.ts';
|
||||
import { triggerClaimTable, triggerTable } from './trigger-schema.ts';
|
||||
|
||||
type Row = typeof triggerTable.$inferSelect;
|
||||
|
||||
function toConfig(row: Row): TriggerConfig {
|
||||
return triggerConfigSchema.parse({
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
enabled: row.enabled,
|
||||
processPackageId: row.processPackageId,
|
||||
mapping: row.mapping,
|
||||
spec: row.spec,
|
||||
});
|
||||
}
|
||||
|
||||
export function createTriggerStore(db: Db): TriggerStore {
|
||||
return {
|
||||
async list() {
|
||||
const rows = await db.select().from(triggerTable).orderBy(triggerTable.name);
|
||||
return rows.map(toConfig);
|
||||
},
|
||||
async get(id) {
|
||||
const rows = await db.select().from(triggerTable).where(eq(triggerTable.id, id)).limit(1);
|
||||
return rows[0] === undefined ? undefined : toConfig(rows[0]);
|
||||
},
|
||||
async upsert(config) {
|
||||
const values = {
|
||||
id: config.id,
|
||||
name: config.name,
|
||||
enabled: config.enabled,
|
||||
processPackageId: config.processPackageId,
|
||||
mapping: config.mapping,
|
||||
spec: config.spec,
|
||||
};
|
||||
const [row] = await db
|
||||
.insert(triggerTable)
|
||||
.values(values)
|
||||
.onConflictDoUpdate({ target: triggerTable.id, set: values })
|
||||
.returning();
|
||||
if (row === undefined) throw new Error('触发器写入未返回行');
|
||||
return toConfig(row);
|
||||
},
|
||||
async setEnabled(id, enabled) {
|
||||
await db.update(triggerTable).set({ enabled }).where(eq(triggerTable.id, id));
|
||||
},
|
||||
async remove(id) {
|
||||
await db.delete(triggerTable).where(eq(triggerTable.id, id));
|
||||
},
|
||||
async claim(key) {
|
||||
const inserted = await db
|
||||
.insert(triggerClaimTable)
|
||||
.values({ key })
|
||||
.onConflictDoNothing()
|
||||
.returning({ key: triggerClaimTable.key });
|
||||
return inserted.length > 0;
|
||||
},
|
||||
async lastFiredAt(id) {
|
||||
const rows = await db.select({ at: triggerTable.lastFiredAt }).from(triggerTable).where(eq(triggerTable.id, id)).limit(1);
|
||||
return rows[0]?.at ?? undefined;
|
||||
},
|
||||
async markFired(id, at) {
|
||||
await db.update(triggerTable).set({ lastFiredAt: at }).where(eq(triggerTable.id, id));
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user