feat : update
This commit is contained in:
+50
-4
@@ -161,16 +161,36 @@ async function advanceGuideVersion(tx: Parameters<Parameters<ReturnType<typeof g
|
||||
return guide;
|
||||
}
|
||||
|
||||
async function syncConditionIconReferences(
|
||||
tx: Parameters<Parameters<ReturnType<typeof getDb>["transaction"]>[0]>[0],
|
||||
previous: Array<string | null | undefined>,
|
||||
next: Array<string | null | undefined>,
|
||||
) {
|
||||
const nextIds = [...new Set(next.filter((id): id is string => Boolean(id)))];
|
||||
if (nextIds.length) {
|
||||
const ready = await tx.select({ id: media.id }).from(media).where(and(inArray(media.id, nextIds), eq(media.status, "ready")));
|
||||
if (ready.length !== nextIds.length) throw new Error("ไม่พบภาพ Condition ที่อัปโหลดแล้ว");
|
||||
}
|
||||
const changes = new Map<string, number>();
|
||||
for (const id of previous) if (id) changes.set(id, (changes.get(id) ?? 0) - 1);
|
||||
for (const id of next) if (id) changes.set(id, (changes.get(id) ?? 0) + 1);
|
||||
for (const [id, change] of changes) {
|
||||
if (change) await tx.update(media).set({ currentReferenceCount: sql`greatest(${media.currentReferenceCount} + ${change}, 0)` }).where(eq(media.id, id));
|
||||
}
|
||||
}
|
||||
|
||||
export async function saveWeapons(guideId: string, input: unknown, context: GuideMutationContext) {
|
||||
const data = weaponSectionSchema.parse(input);
|
||||
const [guide] = await getDb().select().from(guides).where(eq(guides.id, guideId)).limit(1);
|
||||
if (!guide) throw new Error("ไม่พบ Guide");
|
||||
return getDb().transaction(async (tx) => {
|
||||
const updated = await advanceGuideVersion(tx, guideId, data.expectedVersion, false, "weapon", invalidationDetails(context));
|
||||
const previous = await tx.select({ iconMediaId: weaponConditions.iconMediaId }).from(weaponConditions).where(eq(weaponConditions.guideId, guideId));
|
||||
await syncConditionIconReferences(tx, previous.map((group) => group.iconMediaId), data.groups.map((group) => group.iconMediaId));
|
||||
await tx.update(guideSections).set({ note: data.note }).where(and(eq(guideSections.guideId, guideId), eq(guideSections.slug, "weapon")));
|
||||
await tx.delete(weaponConditions).where(eq(weaponConditions.guideId, guideId));
|
||||
for (const [sortOrder, group] of data.groups.entries()) {
|
||||
const [created] = await tx.insert(weaponConditions).values({ guideId, name: group.name, note: group.note, sortOrder }).returning();
|
||||
const [created] = await tx.insert(weaponConditions).values({ guideId, name: group.name, note: group.note, iconMediaId: group.iconMediaId, sortOrder }).returning();
|
||||
if (group.rows.length) await tx.insert(weaponRecommendations).values(group.rows.map((row, rowOrder) => ({ ...row, refinement: row.refinement, overallPercent: row.overallPercent?.toString() ?? null, personalPercent: row.personalPercent?.toString() ?? null, conditionId: created.id, sortOrder: rowOrder })));
|
||||
}
|
||||
await auditGuide(tx, context, "guide.weapon.saved", updated, "weapon");
|
||||
@@ -259,9 +279,20 @@ export async function saveArtifacts(guideId: string, input: unknown, context: Gu
|
||||
if (!guide) throw new Error("ไม่พบ Guide");
|
||||
return getDb().transaction(async (tx) => {
|
||||
const updated = await advanceGuideVersion(tx, guideId, data.expectedVersion, false, "artifact", invalidationDetails(context));
|
||||
const previousConditions = await tx.select({ iconMediaId: artifactConditions.iconMediaId }).from(artifactConditions).where(eq(artifactConditions.guideId, guideId));
|
||||
const [previousProfile] = await tx.select({ recommendedConditions: artifactProfiles.recommendedConditions, targetConditions: artifactProfiles.targetConditions }).from(artifactProfiles).where(eq(artifactProfiles.guideId, guideId)).limit(1);
|
||||
await syncConditionIconReferences(tx, [
|
||||
...previousConditions.map((group) => group.iconMediaId),
|
||||
...(previousProfile?.recommendedConditions ?? []).map((group) => group.iconMediaId),
|
||||
...(previousProfile?.targetConditions ?? []).map((group) => group.iconMediaId),
|
||||
], [
|
||||
...data.groups.map((group) => group.iconMediaId),
|
||||
...(data.recommendedGroups ?? []).map((group) => group.iconMediaId),
|
||||
...data.targetGroups.map((group) => group.iconMediaId),
|
||||
]);
|
||||
await tx.delete(artifactConditions).where(eq(artifactConditions.guideId, guideId));
|
||||
for (const [conditionOrder, condition] of data.groups.entries()) {
|
||||
const [createdCondition] = await tx.insert(artifactConditions).values({ guideId, name: condition.name, note: condition.note, sortOrder: conditionOrder }).returning();
|
||||
const [createdCondition] = await tx.insert(artifactConditions).values({ guideId, name: condition.name, note: condition.note, iconMediaId: condition.iconMediaId, sortOrder: conditionOrder }).returning();
|
||||
for (const [sortOrder, group] of condition.tiers.entries()) {
|
||||
const [created] = await tx.insert(artifactGroups).values({ conditionId: createdCondition.id, name: group.name, sortOrder }).returning();
|
||||
if (group.rows.length) await tx.insert(artifactRecommendations).values(group.rows.map((row, rowOrder) => ({ ...row, percent: row.percent.toString(), groupId: created.id, sortOrder: rowOrder })));
|
||||
@@ -277,10 +308,12 @@ export async function saveConstellations(guideId: string, input: unknown, contex
|
||||
const data = constellationSectionSchema.parse(input);
|
||||
return getDb().transaction(async (tx) => {
|
||||
const updated = await advanceGuideVersion(tx, guideId, data.expectedVersion, false, "constellations", invalidationDetails(context));
|
||||
const previous = await tx.select({ iconMediaId: constellationConditions.iconMediaId }).from(constellationConditions).where(eq(constellationConditions.guideId, guideId));
|
||||
await syncConditionIconReferences(tx, previous.map((group) => group.iconMediaId), data.groups.map((group) => group.iconMediaId));
|
||||
await tx.update(guideSections).set({ note: data.note }).where(and(eq(guideSections.guideId, guideId), eq(guideSections.slug, "constellations")));
|
||||
await tx.delete(constellationConditions).where(eq(constellationConditions.guideId, guideId));
|
||||
for (const [sortOrder, group] of data.groups.entries()) {
|
||||
const [created] = await tx.insert(constellationConditions).values({ guideId, name: group.name, note: group.note, sortOrder }).returning();
|
||||
const [created] = await tx.insert(constellationConditions).values({ guideId, name: group.name, note: group.note, iconMediaId: group.iconMediaId, sortOrder }).returning();
|
||||
if (group.rows.length) await tx.insert(constellationRecommendations).values(group.rows.map((row) => ({ ...row, cumulativePercent: row.cumulativePercent.toString(), conditionId: created.id })));
|
||||
}
|
||||
await auditGuide(tx, context, "guide.constellations.saved", updated, "constellations");
|
||||
@@ -313,9 +346,11 @@ export async function saveTeams(guideId: string, input: unknown, context: GuideM
|
||||
}
|
||||
return getDb().transaction(async (tx) => {
|
||||
const updated = await advanceGuideVersion(tx, guideId, data.expectedVersion, false, "team", invalidationDetails(context));
|
||||
const previous = await tx.select({ iconMediaId: teamConditions.iconMediaId }).from(teamConditions).where(eq(teamConditions.guideId, guideId));
|
||||
await syncConditionIconReferences(tx, previous.map((group) => group.iconMediaId), data.groups.map((group) => group.iconMediaId));
|
||||
await tx.delete(teamConditions).where(eq(teamConditions.guideId, guideId));
|
||||
for (const [groupOrder, group] of data.groups.entries()) {
|
||||
const [condition] = await tx.insert(teamConditions).values({ guideId, name: group.name, note: group.note, sortOrder: groupOrder }).returning();
|
||||
const [condition] = await tx.insert(teamConditions).values({ guideId, name: group.name, note: group.note, iconMediaId: group.iconMediaId, sortOrder: groupOrder }).returning();
|
||||
for (const [sortOrder, team] of group.teams.entries()) {
|
||||
const [created] = await tx.insert(teamCompositions).values({ guideId, conditionId: condition.id, title: team.title, rotationSeconds: team.rotationSeconds.toString(), combo: team.combo, sortOrder }).returning();
|
||||
await tx.insert(teamMembers).values(team.members.map((member, position) => ({ ...member, teamId: created.id, position, damage: member.damage.toString() })));
|
||||
@@ -583,7 +618,18 @@ export async function permanentlyDeleteGuide(
|
||||
const [guide] = await tx.select().from(guides).where(eq(guides.id, guideId)).limit(1);
|
||||
if (!guide?.trashedAt) throw new Error("Guide ต้องอยู่ในถังขยะก่อนลบถาวร");
|
||||
const bleeding = await tx.select({ mediaId: guidePosterBleeding.mediaId }).from(guidePosterBleeding).where(eq(guidePosterBleeding.guideId, guideId));
|
||||
const weapons = await tx.select({ iconMediaId: weaponConditions.iconMediaId }).from(weaponConditions).where(eq(weaponConditions.guideId, guideId));
|
||||
const artifacts = await tx.select({ iconMediaId: artifactConditions.iconMediaId }).from(artifactConditions).where(eq(artifactConditions.guideId, guideId));
|
||||
const constellations = await tx.select({ iconMediaId: constellationConditions.iconMediaId }).from(constellationConditions).where(eq(constellationConditions.guideId, guideId));
|
||||
const teams = await tx.select({ iconMediaId: teamConditions.iconMediaId }).from(teamConditions).where(eq(teamConditions.guideId, guideId));
|
||||
const profiles = await tx.select({ recommendedConditions: artifactProfiles.recommendedConditions, targetConditions: artifactProfiles.targetConditions }).from(artifactProfiles).where(eq(artifactProfiles.guideId, guideId));
|
||||
const conditionIconIds = [
|
||||
...weapons, ...artifacts, ...constellations, ...teams,
|
||||
...(profiles[0]?.recommendedConditions ?? []),
|
||||
...(profiles[0]?.targetConditions ?? []),
|
||||
].map((condition) => condition.iconMediaId);
|
||||
await tx.delete(guides).where(eq(guides.id, guideId));
|
||||
await syncConditionIconReferences(tx, conditionIconIds, []);
|
||||
await tx.update(media).set({ currentReferenceCount: sql`greatest(${media.currentReferenceCount} - 1, 0)` }).where(eq(media.id, guide.coverMediaId));
|
||||
if (guide.posterArtMediaId) {
|
||||
await tx.update(media).set({ currentReferenceCount: sql`greatest(${media.currentReferenceCount} - 1, 0)` }).where(eq(media.id, guide.posterArtMediaId));
|
||||
|
||||
Reference in New Issue
Block a user