← Lazy initialization lesson
Lab

Lazy initialization

Sign in to run your code

Read the brief and the starter here. With a free account you can edit it, run the sample, step through it and check your work, and your progress is kept.

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;
  }
}