mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 22:26:13 +00:00
chore: format data integrity fixes
This commit is contained in:
1 parent
a846bbc90d
commit
d966355f83
5 files changed
+67
-87
No files matched your search
@@ -367,8 +367,7 @@ const handler = apiHandler(
|
||||
adminCodexConnectedAt: settings.adminCodexConnectedAt
|
||||
? new Date(settings.adminCodexConnectedAt)
|
||||
: null,
|
||||
adminCodexConnectionStatus:
|
||||
settings.adminCodexConnectionStatus,
|
||||
adminCodexConnectionStatus: settings.adminCodexConnectionStatus,
|
||||
adminAiInsightsFeedbackSummary:
|
||||
settings.adminAiInsightsFeedbackSummary as never,
|
||||
defaultUserTimezone: settings.defaultUserTimezone,
|
||||
@@ -381,8 +380,7 @@ const handler = apiHandler(
|
||||
settings.assistantCorrelationsEnabled,
|
||||
assistantHealthScoreExplainerEnabled:
|
||||
settings.assistantHealthScoreExplainerEnabled,
|
||||
moduleAvailabilityJson:
|
||||
settings.moduleAvailabilityJson as never,
|
||||
moduleAvailabilityJson: settings.moduleAvailabilityJson as never,
|
||||
documentMaxFileBytes: settings.documentMaxFileBytes,
|
||||
documentQuotaBytes: BigInt(settings.documentQuotaBytes),
|
||||
};
|
||||
@@ -492,9 +490,7 @@ const handler = apiHandler(
|
||||
active: m.active ?? true,
|
||||
notificationsEnabled: m.notificationsEnabled ?? true,
|
||||
pausedAt: m.pausedAt ? new Date(m.pausedAt) : null,
|
||||
snoozedUntil: m.snoozedUntil
|
||||
? new Date(m.snoozedUntil)
|
||||
: null,
|
||||
snoozedUntil: m.snoozedUntil ? new Date(m.snoozedUntil) : null,
|
||||
startsOn: m.startsOn ? new Date(m.startsOn) : null,
|
||||
endsOn: m.endsOn ? new Date(m.endsOn) : null,
|
||||
oneShot: m.oneShot ?? false,
|
||||
|
||||
@@ -126,10 +126,8 @@ function stableFallbackMoodInstant(
|
||||
const digest = createHash("sha256")
|
||||
.update(`${fallbackMoodIdentity(entry)}:${occurrence}`)
|
||||
.digest();
|
||||
const initialOffset =
|
||||
digest.readUInt32BE(0) % ENTRY_INSTANT_CLOCK_SKEW_MS;
|
||||
const offset =
|
||||
(initialOffset + probe) % ENTRY_INSTANT_CLOCK_SKEW_MS;
|
||||
const initialOffset = digest.readUInt32BE(0) % ENTRY_INSTANT_CLOCK_SKEW_MS;
|
||||
const offset = (initialOffset + probe) % ENTRY_INSTANT_CLOCK_SKEW_MS;
|
||||
const dateStart = fallbackMoodDateStart(entry.date);
|
||||
if (!dateStart) throw new Error("Invalid mood date");
|
||||
return new Date(dateStart.getTime() + offset);
|
||||
@@ -308,17 +306,10 @@ export const POST = apiHandler(async (request: NextRequest) => {
|
||||
fallbackOccurrences.set(identity, occurrence + 1);
|
||||
}
|
||||
|
||||
for (
|
||||
let probe = 0;
|
||||
probe < ENTRY_INSTANT_CLOCK_SKEW_MS;
|
||||
probe++
|
||||
) {
|
||||
for (let probe = 0; probe < ENTRY_INSTANT_CLOCK_SKEW_MS; probe++) {
|
||||
const loggedAt =
|
||||
e.loggedAt ?? stableFallbackMoodInstant(e, occurrence, probe);
|
||||
if (
|
||||
!e.loggedAt &&
|
||||
reservedFallbackInstants.has(loggedAt.getTime())
|
||||
) {
|
||||
if (!e.loggedAt && reservedFallbackInstants.has(loggedAt.getTime())) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -80,11 +80,9 @@ describe("buildCycleBackupSection disaster-recovery mode", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const section = await buildCycleBackupSection(
|
||||
prisma as never,
|
||||
"user-1",
|
||||
{ purpose: "disaster-recovery" },
|
||||
);
|
||||
const section = await buildCycleBackupSection(prisma as never, "user-1", {
|
||||
purpose: "disaster-recovery",
|
||||
});
|
||||
|
||||
expect(prisma.menstrualCycle.findMany).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ where: { userId: "user-1" } }),
|
||||
|
||||
+32
-30
@@ -367,37 +367,39 @@ export async function upsertWhoopMeasurements(
|
||||
chunkStart + WHOOP_MEASUREMENT_TRANSACTION_CHUNK_SIZE,
|
||||
readings.length,
|
||||
);
|
||||
const verdicts = await prisma.$transaction(
|
||||
async (tx) => {
|
||||
const outcomes = [];
|
||||
for (let index = chunkStart; index < chunkEnd; index++) {
|
||||
const reading = readings[index]!;
|
||||
const verdict = await reconcileExternalMeasurement(
|
||||
tx,
|
||||
{
|
||||
userId,
|
||||
type: reading.type as MeasurementType,
|
||||
source: "WHOOP",
|
||||
value: reading.value,
|
||||
unit: reading.unit,
|
||||
measuredAt: reading.measuredAt,
|
||||
externalId: reading.externalId,
|
||||
sleepStage: reading.sleepStage ?? null,
|
||||
},
|
||||
{ exactExternalMatch: "update" },
|
||||
);
|
||||
if (verdict.status === "failed") {
|
||||
throw new MeasurementReconciliationError(verdict);
|
||||
const verdicts = await prisma
|
||||
.$transaction(
|
||||
async (tx) => {
|
||||
const outcomes = [];
|
||||
for (let index = chunkStart; index < chunkEnd; index++) {
|
||||
const reading = readings[index]!;
|
||||
const verdict = await reconcileExternalMeasurement(
|
||||
tx,
|
||||
{
|
||||
userId,
|
||||
type: reading.type as MeasurementType,
|
||||
source: "WHOOP",
|
||||
value: reading.value,
|
||||
unit: reading.unit,
|
||||
measuredAt: reading.measuredAt,
|
||||
externalId: reading.externalId,
|
||||
sleepStage: reading.sleepStage ?? null,
|
||||
},
|
||||
{ exactExternalMatch: "update" },
|
||||
);
|
||||
if (verdict.status === "failed") {
|
||||
throw new MeasurementReconciliationError(verdict);
|
||||
}
|
||||
outcomes.push(verdict);
|
||||
}
|
||||
outcomes.push(verdict);
|
||||
}
|
||||
return outcomes;
|
||||
},
|
||||
{ maxWait: 10_000, timeout: 60_000 },
|
||||
).catch((err) => {
|
||||
invalidateTouchedTypes();
|
||||
throw err;
|
||||
});
|
||||
return outcomes;
|
||||
},
|
||||
{ maxWait: 10_000, timeout: 60_000 },
|
||||
)
|
||||
.catch((err) => {
|
||||
invalidateTouchedTypes();
|
||||
throw err;
|
||||
});
|
||||
|
||||
const touched: Array<{ type: MeasurementType; measuredAt: Date }> = [];
|
||||
const insertedRows: Array<
|
||||
|
||||
@@ -280,9 +280,7 @@ describe("canonical disaster-recovery backup round-trip", () => {
|
||||
scheduleType: "CYCLIC",
|
||||
cyclicOnWeeks: 3,
|
||||
cyclicOffWeeks: 1,
|
||||
doseWindows: [
|
||||
{ timeOfDay: "08:00", start: "07:30", end: "09:00" },
|
||||
],
|
||||
doseWindows: [{ timeOfDay: "08:00", start: "07:30", end: "09:00" }],
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -340,8 +338,7 @@ describe("canonical disaster-recovery backup round-trip", () => {
|
||||
deletedAt: tombstoneDeletedAt,
|
||||
},
|
||||
});
|
||||
const cycleCategory =
|
||||
await prisma.cycleSymptomCategory.findFirstOrThrow();
|
||||
const cycleCategory = await prisma.cycleSymptomCategory.findFirstOrThrow();
|
||||
const cycleSymptom = await prisma.cycleSymptom.create({
|
||||
data: {
|
||||
id: "cycle-symptom-dr",
|
||||
@@ -542,7 +539,9 @@ describe("canonical disaster-recovery backup round-trip", () => {
|
||||
);
|
||||
|
||||
await prisma.appSettings.deleteMany();
|
||||
await prisma.medicationIntakeEvent.deleteMany({ where: { userId: ownerId } });
|
||||
await prisma.medicationIntakeEvent.deleteMany({
|
||||
where: { userId: ownerId },
|
||||
});
|
||||
await prisma.medication.deleteMany({ where: { userId: ownerId } });
|
||||
await prisma.cycleDayLog.deleteMany({ where: { userId: ownerId } });
|
||||
await prisma.menstrualCycle.deleteMany({ where: { userId: ownerId } });
|
||||
@@ -880,9 +879,7 @@ describe("canonical disaster-recovery backup round-trip", () => {
|
||||
type: "PULSE" as const,
|
||||
value: 60 + (index % 20),
|
||||
unit: "bpm",
|
||||
measuredAt: new Date(
|
||||
Date.UTC(2026, 6, 10, 0, 0, 0, index),
|
||||
).toISOString(),
|
||||
measuredAt: new Date(Date.UTC(2026, 6, 10, 0, 0, 0, index)).toISOString(),
|
||||
source: "IMPORT" as const,
|
||||
externalId: `external-${index}`,
|
||||
syncVersion: 3,
|
||||
@@ -907,29 +904,25 @@ describe("canonical disaster-recovery backup round-trip", () => {
|
||||
options?: { maxWait?: number; timeout?: number },
|
||||
) => Promise<unknown>;
|
||||
const transactionSpy = vi.spyOn(prisma, "$transaction");
|
||||
transactionSpy.mockImplementation(
|
||||
(async (
|
||||
callback: (tx: Prisma.TransactionClient) => Promise<unknown>,
|
||||
options?: { maxWait?: number; timeout?: number },
|
||||
) =>
|
||||
originalTransaction(async (tx) => {
|
||||
const originalUpsert = tx.measurement.upsert.bind(tx.measurement);
|
||||
const originalCreateMany = tx.measurement.createMany.bind(
|
||||
tx.measurement,
|
||||
);
|
||||
vi.spyOn(tx.measurement, "upsert").mockImplementation((args) => {
|
||||
stableWriteQueries += 1;
|
||||
return originalUpsert(args);
|
||||
});
|
||||
vi.spyOn(tx.measurement, "createMany").mockImplementation(
|
||||
(args) => {
|
||||
stableWriteQueries += 1;
|
||||
return originalCreateMany(args);
|
||||
},
|
||||
);
|
||||
return callback(tx);
|
||||
}, options)) as never,
|
||||
);
|
||||
transactionSpy.mockImplementation((async (
|
||||
callback: (tx: Prisma.TransactionClient) => Promise<unknown>,
|
||||
options?: { maxWait?: number; timeout?: number },
|
||||
) =>
|
||||
originalTransaction(async (tx) => {
|
||||
const originalUpsert = tx.measurement.upsert.bind(tx.measurement);
|
||||
const originalCreateMany = tx.measurement.createMany.bind(
|
||||
tx.measurement,
|
||||
);
|
||||
vi.spyOn(tx.measurement, "upsert").mockImplementation((args) => {
|
||||
stableWriteQueries += 1;
|
||||
return originalUpsert(args);
|
||||
});
|
||||
vi.spyOn(tx.measurement, "createMany").mockImplementation((args) => {
|
||||
stableWriteQueries += 1;
|
||||
return originalCreateMany(args);
|
||||
});
|
||||
return callback(tx);
|
||||
}, options)) as never);
|
||||
|
||||
const response = await POST(
|
||||
makeRequest(backup.id) as unknown as Parameters<typeof POST>[0],
|
||||
|
||||
Reference in new issue
Block a user