update
CI / Verify (push) Successful in 1m7s
CI / Build immutable images and deploy (push) Successful in 2m23s

This commit is contained in:
2026-09-07 16:57:10 +07:00 Unverified
parent c3c2aa0862
commit 05826eda82
11 changed files with 90 additions and 33 deletions
+12 -10
View File
@@ -55,9 +55,11 @@ export class GuideVersionConflictError extends Error {
}
}
async function emitGuideEvents(tx: Parameters<Parameters<ReturnType<typeof getDb>["transaction"]>[0]>[0], guideId: string, version: number) {
async function emitGuideEvents(tx: Parameters<Parameters<ReturnType<typeof getDb>["transaction"]>[0]>[0], guideId: string, version: number, directoryChanged = false) {
await tx.insert(outboxEvents).values([
{ topic: "directory", aggregateId: guideId, eventType: "directory.updated", payload: { id: guideId, version } },
...(directoryChanged
? [{ topic: "directory", aggregateId: guideId, eventType: "directory.updated", payload: { id: guideId, version } }]
: []),
{ topic: `page:${guideId}`, aggregateId: guideId, eventType: "page.updated", payload: { id: guideId, version } },
{ topic: "admin", aggregateId: guideId, eventType: "admin.updated", payload: { id: guideId, version } },
]);
@@ -89,19 +91,19 @@ export async function createGuide(input: unknown) {
]);
await tx.insert(artifactProfiles).values({ guideId: guide.id });
await tx.update(media).set({ currentReferenceCount: sql`${media.currentReferenceCount} + 1` }).where(eq(media.id, parsed.coverMediaId));
await emitGuideEvents(tx, guide.id, guide.version);
await emitGuideEvents(tx, guide.id, guide.version, true);
return guide;
});
}
async function advanceGuideVersion(tx: Parameters<Parameters<ReturnType<typeof getDb>["transaction"]>[0]>[0], guideId: string, expectedVersion: number) {
async function advanceGuideVersion(tx: Parameters<Parameters<ReturnType<typeof getDb>["transaction"]>[0]>[0], guideId: string, expectedVersion: number, directoryChanged = false) {
const [guide] = await tx.update(guides).set({ version: expectedVersion + 1 }).where(and(eq(guides.id, guideId), eq(guides.version, expectedVersion), sql`${guides.trashedAt} is null`)).returning();
if (!guide) {
const [current] = await tx.select({ version: guides.version }).from(guides).where(eq(guides.id, guideId)).limit(1);
if (current) throw new GuideVersionConflictError(current.version);
throw new Error("ไม่พบ Guide");
}
await emitGuideEvents(tx, guide.id, guide.version);
await emitGuideEvents(tx, guide.id, guide.version, directoryChanged);
return guide;
}
@@ -146,7 +148,7 @@ export async function updateGuideBasics(guideId: string, input: unknown) {
: [];
if (bleedingMedia.length !== bleedingMediaIds.length) throw new Error("ไม่พบภาพ Bleeding ที่อัปโหลดแล้ว");
}
const updated = await advanceGuideVersion(tx, guideId, data.expectedVersion);
const updated = await advanceGuideVersion(tx, guideId, data.expectedVersion, true);
await tx.update(guides).set({
overview: data.overview,
coverMediaId: data.coverMediaId,
@@ -414,7 +416,7 @@ export async function trashGuide(guideId: string) {
return getDb().transaction(async (tx) => {
const [guide] = await tx.update(guides).set({ trashedAt: new Date(), version: sql`${guides.version} + 1` }).where(eq(guides.id, guideId)).returning();
if (!guide) throw new Error("ไม่พบ Guide");
await emitGuideEvents(tx, guide.id, guide.version);
await emitGuideEvents(tx, guide.id, guide.version, true);
return guide;
});
}
@@ -423,7 +425,7 @@ export async function restoreGuide(guideId: string) {
return getDb().transaction(async (tx) => {
const [guide] = await tx.update(guides).set({ trashedAt: null, version: sql`${guides.version} + 1` }).where(eq(guides.id, guideId)).returning();
if (!guide) throw new Error("ไม่พบ Guide");
await emitGuideEvents(tx, guide.id, guide.version);
await emitGuideEvents(tx, guide.id, guide.version, true);
return guide;
});
}
@@ -436,7 +438,7 @@ export async function setGuideVisibility(guideId: string, isPublic: boolean) {
.where(and(eq(guides.id, guideId), sql`${guides.trashedAt} is null`))
.returning();
if (!guide) throw new Error("ไม่พบ Guide");
await emitGuideEvents(tx, guide.id, guide.version);
await emitGuideEvents(tx, guide.id, guide.version, true);
return guide;
});
}
@@ -454,7 +456,7 @@ export async function permanentlyDeleteGuide(guideId: string) {
for (const layer of bleeding) {
await tx.update(media).set({ currentReferenceCount: sql`greatest(${media.currentReferenceCount} - 1, 0)` }).where(eq(media.id, layer.mediaId));
}
await emitGuideEvents(tx, guide.id, guide.version + 1);
await emitGuideEvents(tx, guide.id, guide.version + 1, true);
return { version: guide.version + 1 };
});
}