mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 13:01:00 +00:00
fix(backup): carry the mood tags an account made, so its own file can be restored
The restore resolves a mood entry's rated factors by key and asks only for the seeded catalogue. A tag the user created is not in it, so the lookup came up short and the whole restore threw 'Unknown mood factor keys'. The file was complete; it simply could not be read back. That is the same cause as the cycle symptoms two commits ago, with the opposite ending. There, an unresolvable key was filtered out and the loss was silent. Here it stopped everything. One shape of missing definition, two answers, neither of them the right one. The account's own tag definitions travel now, get written before the factors resolve, and the lookup accepts the seeded catalogue or the owner's own. The seeded rows stay out of the file for the same reason as before: a restore must not rewrite another instance's reference data. Four more test mocks needed the new delegate, which is again the compiler and the suite naming the call sites rather than me hunting for them.
This commit is contained in:
1 parent
d9afb23067
commit
cd30cb3a52
7 files changed
+70
-1
No files matched your search
@@ -605,6 +605,28 @@ const handler = apiHandler(
|
||||
),
|
||||
),
|
||||
];
|
||||
// Re-create the account's own tag definitions first. The lookup
|
||||
// below used to ask only for the seeded catalogue (`userId: null`),
|
||||
// so a single custom rated tag made the whole restore throw
|
||||
// "Unknown mood factor keys" — the file was complete and unusable.
|
||||
for (const tag of payload.customMoodTags) {
|
||||
await tx.moodTag.upsert({
|
||||
where: { key: tag.key },
|
||||
create: {
|
||||
...(tag.id ? { id: tag.id } : {}),
|
||||
userId: ownerId,
|
||||
key: tag.key,
|
||||
labelKey: tag.labelKey,
|
||||
categoryId: tag.categoryId,
|
||||
kind: tag.kind,
|
||||
isActive: tag.isActive,
|
||||
},
|
||||
// `key` is globally unique, so a seeded key would collide.
|
||||
// Leave the catalogue row alone; the links resolve either way.
|
||||
update: {},
|
||||
});
|
||||
}
|
||||
|
||||
const factorRows =
|
||||
factorKeys.length === 0
|
||||
? []
|
||||
@@ -612,7 +634,8 @@ const handler = apiHandler(
|
||||
where: {
|
||||
key: { in: factorKeys },
|
||||
kind: "RATED",
|
||||
userId: null,
|
||||
// The seeded catalogue OR this account's own tags.
|
||||
OR: [{ userId: null }, { userId: ownerId }],
|
||||
},
|
||||
select: { id: true, key: true },
|
||||
});
|
||||
|
||||
@@ -16,6 +16,7 @@ vi.mock("@/lib/db", () => ({
|
||||
medication: { findMany: vi.fn() },
|
||||
medicationIntakeEvent: { findMany: vi.fn() },
|
||||
moodEntry: { findMany: vi.fn() },
|
||||
moodTag: { findMany: vi.fn() },
|
||||
nutrientIntakeDay: { findMany: vi.fn().mockResolvedValue([]) },
|
||||
// v1.15.0 — cycle tables read by the full-backup helper.
|
||||
cycleProfile: { findUnique: vi.fn() },
|
||||
@@ -361,6 +362,7 @@ describe("GET /api/export/mood", () => {
|
||||
remaining: 9,
|
||||
resetAt: Date.now() + 3600_000,
|
||||
});
|
||||
vi.mocked(prisma.moodTag.findMany).mockResolvedValue([] as never);
|
||||
vi.mocked(prisma.moodEntry.findMany).mockResolvedValue([
|
||||
{
|
||||
date: "2026-05-01",
|
||||
@@ -406,6 +408,7 @@ describe("GET /api/export/full-backup", () => {
|
||||
[] as never,
|
||||
);
|
||||
vi.mocked(prisma.moodEntry.findMany).mockResolvedValue([] as never);
|
||||
vi.mocked(prisma.moodTag.findMany).mockResolvedValue([] as never);
|
||||
vi.mocked(prisma.cycleProfile.findUnique).mockResolvedValue(null as never);
|
||||
vi.mocked(prisma.menstrualCycle.findMany).mockResolvedValue([] as never);
|
||||
vi.mocked(prisma.cycleDayLog.findMany).mockResolvedValue([] as never);
|
||||
@@ -475,6 +478,7 @@ describe("GET /api/export/full-backup", () => {
|
||||
[] as never,
|
||||
);
|
||||
vi.mocked(prisma.moodEntry.findMany).mockResolvedValue([] as never);
|
||||
vi.mocked(prisma.moodTag.findMany).mockResolvedValue([] as never);
|
||||
vi.mocked(prisma.cycleProfile.findUnique).mockResolvedValue(null as never);
|
||||
vi.mocked(prisma.menstrualCycle.findMany).mockResolvedValue([] as never);
|
||||
vi.mocked(prisma.cycleDayLog.findMany).mockResolvedValue([] as never);
|
||||
|
||||
@@ -24,6 +24,7 @@ vi.mock("@/lib/db", () => ({
|
||||
medication: { findMany: vi.fn() },
|
||||
medicationIntakeEvent: { findMany: vi.fn(), count: vi.fn() },
|
||||
moodEntry: { findMany: vi.fn(), count: vi.fn() },
|
||||
moodTag: { findMany: vi.fn() },
|
||||
nutrientIntakeDay: { findMany: vi.fn().mockResolvedValue([]) },
|
||||
user: { findUnique: vi.fn() },
|
||||
passkey: { findMany: vi.fn() },
|
||||
|
||||
@@ -14,6 +14,7 @@ vi.mock("@/lib/db", () => ({
|
||||
medication: { findMany: vi.fn().mockResolvedValue([]) },
|
||||
medicationIntakeEvent: { findMany: vi.fn().mockResolvedValue([]) },
|
||||
moodEntry: { findMany: vi.fn().mockResolvedValue([]) },
|
||||
moodTag: { findMany: vi.fn().mockResolvedValue([]) },
|
||||
nutrientIntakeDay: { findMany: vi.fn().mockResolvedValue([]) },
|
||||
cycleProfile: { findUnique: vi.fn().mockResolvedValue(null) },
|
||||
menstrualCycle: { findMany: vi.fn().mockResolvedValue([]) },
|
||||
|
||||
Reference in new issue
Block a user