normalize data

This commit is contained in:
2026-03-02 11:05:57 +01:00
parent 22067c4904
commit dbfb29703c
7 changed files with 197 additions and 167 deletions

View File

@@ -5,6 +5,40 @@ import { createServerFn } from "@tanstack/react-start";
import { queryOptions } from "@tanstack/react-query";
import { z } from "zod";
// ---------------------------------------------------------------------------
// Normalized timeline shape stored in the TanStack Query cache.
// Groups and items are keyed by ID for O(1) lookups; groupOrder preserves
// the display ordering returned by the DB.
// ---------------------------------------------------------------------------
export type NormalizedGroup = {
id: string;
title: string;
sortOrder: number;
};
export type NormalizedItem = {
id: string;
groupId: string;
title: string;
description: string;
start: Date;
end: Date | null;
lane: number;
};
export type NormalizedTimeline = {
id: string;
title: string;
groups: Record<string, NormalizedGroup>;
items: Record<string, NormalizedItem>;
groupOrder: Array<string>;
};
// ---------------------------------------------------------------------------
// Server function — returns the raw nested Drizzle result (efficient query).
// ---------------------------------------------------------------------------
export const getTimeline = createServerFn({ method: "GET" })
.inputValidator(z.object({ id: z.string().uuid() }))
.handler(async ({ data }) => {
@@ -29,8 +63,52 @@ export const getTimeline = createServerFn({ method: "GET" })
return result;
});
// ---------------------------------------------------------------------------
// Normalization — flattens the nested DB result into the cache shape.
// ---------------------------------------------------------------------------
type NestedTimeline = Awaited<ReturnType<typeof getTimeline>>;
function normalizeTimeline(nested: NestedTimeline): NormalizedTimeline {
const groups: Record<string, NormalizedGroup> = {};
const items: Record<string, NormalizedItem> = {};
const groupOrder: Array<string> = [];
for (const g of nested.groups) {
groupOrder.push(g.id);
groups[g.id] = { id: g.id, title: g.title, sortOrder: g.sortOrder };
for (const item of g.items) {
items[item.id] = {
id: item.id,
groupId: g.id,
title: item.title,
description: item.description,
start: item.start,
end: item.end,
lane: item.lane,
};
}
}
return {
id: nested.id,
title: nested.title,
groups,
items,
groupOrder,
};
}
// ---------------------------------------------------------------------------
// Query options — cache stores normalized data.
// ---------------------------------------------------------------------------
export const timelineQueryOptions = (timelineId: string) =>
queryOptions({
queryKey: ["timeline", timelineId],
queryFn: () => getTimeline({ data: { id: timelineId } }),
queryFn: async () => {
const nested = await getTimeline({ data: { id: timelineId } });
return normalizeTimeline(nested);
},
});