mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 22:02:16 +00:00
chore(release): v1.4.27
v1.4.27 — Mobile capability and maintainer-finding cleanup. ResponsiveSheet primitive (bottom-sheet on narrow viewports, centred dialog on desktop) applied to BD, Weight, Glucose, Mood, Activity forms. Maintainer-finding cleanups across Coach, Insights, Reports, Privacy. GeoLite2 offline geocoding with resilience layer (graceful fallback when EULA not yet propagated). E2E gap-fill coverage. 450-line release notes attached to the GitHub Release.
This commit is contained in:
1 parent
d98e85cd03
commit
4f09c3f862
314 files changed
+26801
-4419
No files matched your search
@@ -356,21 +356,51 @@ async function postBatch(request: NextRequest): Promise<Response> {
|
||||
// is NULL-distinct, so two manual entries on the same instant
|
||||
// would both insert. We look these up by the deterministic
|
||||
// (userId, source, startedAt, sportType) tuple for each row.
|
||||
const manualMatches = await Promise.all(
|
||||
withoutExternal.map((p) =>
|
||||
tx.workout.findFirst({
|
||||
where: {
|
||||
userId: user.id,
|
||||
//
|
||||
// v1.4.27 B7 / BL-code-M3 — single batched findMany with one
|
||||
// OR-row per entry instead of N serial findFirst probes. For
|
||||
// a 100-row batch this cuts the per-batch round-trip count
|
||||
// from 1 + N to 2; the per-entry "most-recent createdAt"
|
||||
// tie-break is preserved by sorting the returned rows in
|
||||
// memory and keying on the deterministic tuple.
|
||||
type ManualMatch = { id: string; createdAt: Date };
|
||||
const manualMatchesById = new Map<string, ManualMatch>();
|
||||
if (withoutExternal.length > 0) {
|
||||
const manualRows = await tx.workout.findMany({
|
||||
where: {
|
||||
userId: user.id,
|
||||
route: null,
|
||||
OR: withoutExternal.map((p) => ({
|
||||
source: p.row.source,
|
||||
startedAt: p.row.startedAt as Date,
|
||||
sportType: p.row.sportType,
|
||||
route: null,
|
||||
},
|
||||
select: { id: true },
|
||||
orderBy: { createdAt: "desc" },
|
||||
}),
|
||||
),
|
||||
);
|
||||
})),
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
source: true,
|
||||
startedAt: true,
|
||||
sportType: true,
|
||||
createdAt: true,
|
||||
},
|
||||
orderBy: { createdAt: "desc" },
|
||||
});
|
||||
for (const row of manualRows) {
|
||||
const key = `${row.source}::${row.startedAt.getTime()}::${row.sportType}`;
|
||||
const existing = manualMatchesById.get(key);
|
||||
if (!existing || existing.createdAt < row.createdAt) {
|
||||
manualMatchesById.set(key, {
|
||||
id: row.id,
|
||||
createdAt: row.createdAt,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
const manualMatches = withoutExternal.map((p) => {
|
||||
const key = `${p.row.source}::${(p.row.startedAt as Date).getTime()}::${p.row.sportType}`;
|
||||
const match = manualMatchesById.get(key);
|
||||
return match ? { id: match.id } : null;
|
||||
});
|
||||
|
||||
const routesToInsert: Prisma.WorkoutRouteCreateManyInput[] = [];
|
||||
for (let i = 0; i < withExternal.length; i++) {
|
||||
|
||||
Reference in new issue
Block a user