Lab
Lazy initialization
type Sheet = { id: number; species: string };
// Checker plumbing, you don't need to edit this: which centers' exports are
// still syncing, and how many times each center's
// lookup was built. The checker changes them between steps.
const plumbing = {
syncing: new Set<string>(),
builds: new Map<string, number>(),
};
// The recipe: one center's species lookup, each word of a species name → the
// ids of its sheets. It fails while that center's export is still syncing.
function buildIndex(center: string, sheets: Sheet[]): Map<string, number[]> {
plumbing.builds.set(center, (plumbing.builds.get(center) ?? 0) + 1);
if (plumbing.syncing.has(center)) throw new Error(`${center}: export still syncing`);
const index = new Map<string, number[]>();
for (const sheet of sheets) {
for (const word of sheet.species.toLowerCase().split(' ')) {
index.set(word, [...(index.get(word) ?? []), sheet.id]);
}
}
return index;
}
// One center's care sheets and its species lookup.
class Center {
readonly name: string;
readonly sheets: Sheet[];
private index: Map<string, number[]>;
constructor(name: string, sheets: Sheet[]) {
this.name = name;
this.sheets = sheets;
this.index = buildIndex(name, sheets);
}
lookup(word: string): number[] {
return this.index.get(word) ?? [];
}
// The dashboard polls this every few seconds.
status(): string {
return `${this.name}: ${this.sheets.length} sheets, lookup ready (${this.index.size} words)`;
}
}
// The intake server: every center in the network, by name.
class IntakeServer {
private centers = new Map<string, Center>();
constructor(network: [string, Sheet[]][]) {
for (const [name, sheets] of network) {
this.centers.set(name, new Center(name, sheets));
}
}
center(name: string): Center {
const center = this.centers.get(name);
if (!center) throw new Error(`unknown center: ${name}`);
return center;
}
}