Build your own knowledge graph database
Index-free adjacency·10 min

O(1) neighbor lookup

0 / 1
# grade this stage (from your course directory)
npx theinference test --stage neighbors --watch

Now the payoff API: hop to neighbors, optionally filtered by relationship type and direction — without ever scanning the global relationship list. Read outgoing/incoming per dir, filter by type (or all if null), map each relationship to its other endpoint, dedupe, and sort.

Your task

Implement runNeighbors

This is your first adapter step — the harness calls runNeighbors directly and compares the returned number[] to a fixture. Implement store.neighbors(nodeId, type, dir) returning sorted, deduped neighbor node ids, and wire the adapter to it. The fixture asks for Kevin Bacon's ACTED_IN OUT neighbors — the movie ids he acted in.

tests/adapters.ts
import type { Dir } from "./src/types.ts";

export function runNeighbors(nodeId: number, type: string | null, dir: Dir): number[] {
  return store().neighbors(nodeId, type, dir);
}

// in src/store.ts:
neighbors(nodeId: number, type: string | null, dir: Dir): number[] {
  const out = new Set<number>();
  const a = this.adj.get(nodeId);
  if (!a) return [];
  if (dir === "OUT" || dir === "BOTH")
    for (const rid of a.outgoing) {
      const r = this.relById.get(rid)!;
      if (type === null || r.type === type) out.add(r.endNode);
    }
  if (dir === "IN" || dir === "BOTH")
    for (const rid of a.incoming) {
      const r = this.relById.get(rid)!;
      if (type === null || r.type === type) out.add(r.startNode);
    }
  return [...out].sort((x, y) => x - y);
}
How it's graded

Adapter mode: the harness loads the graph (from THEINFERENCE_KGDB_GRAPH), calls runNeighbors(0, 'ACTED_IN', 'OUT'), and compares your number[] to the fixture by exact match. Kevin Bacon (id 0) acted in three movies, so the answer is a length-3 sorted id array.