spb/datacenterindex
Public
HTML 53.9%
TypeScript 44.5%
JavaScript 0.6%
SQL 0.5%
1/** Slug-or-id resolution and entity reference lookups shared across repositories. */2import { pg } from "./sql.js";3import { reqStr, str, type Row } from "./rows.js";45const TABLES: Record<string, { table: string; idCol: string; slugCol: string; nameCol: string; extraSlugCol?: string }> = {6 facility: { table: "facilities", idCol: "id", slugCol: "slug", nameCol: "name" },7 campus: { table: "campuses", idCol: "id", slugCol: "slug", nameCol: "name" },8 operator: { table: "operators", idCol: "id", slugCol: "slug", nameCol: "name" },9 company: { table: "operators", idCol: "id", slugCol: "slug", nameCol: "name" },10 carrier: { table: "operators", idCol: "id", slugCol: "slug", nameCol: "name" },11 cloud_region: { table: "cloud_regions", idCol: "id", slugCol: "slug", nameCol: "name" },12 metro: { table: "metros", idCol: "id", slugCol: "slug", nameCol: "name" },13 country: { table: "countries", idCol: "iso2", slugCol: "slug", nameCol: "name" },14 ixp: { table: "ixps", idCol: "id", slugCol: "slug", nameCol: "name" },15 project: { table: "projects", idCol: "id", slugCol: "slug", nameCol: "name" },16 expansion: { table: "projects", idCol: "id", slugCol: "slug", nameCol: "name" },17 construction_phase: { table: "projects", idCol: "id", slugCol: "slug", nameCol: "name" },18 source: { table: "sources", idCol: "id", slugCol: "id", nameCol: "name" },19};2021/** Whole row for an entity by slug or id (`null` when unknown). Only whitelisted tables. */22export async function findBySlugOrId(table: "facilities" | "operators" | "metros" | "projects" | "cloud_regions" | "ixps" | "campuses", idOrSlug: string): Promise<Row | null> {23 const sql = pg();24 const rows = await sql<Row[]>`select * from ${sql(table)} where slug = ${idOrSlug} or id = ${idOrSlug} order by (id = ${idOrSlug}) desc limit 1`;25 return rows[0] ?? null;26}2728export async function findCountry(slugOrIso2: string): Promise<Row | null> {29 const sql = pg();30 const up = slugOrIso2.toUpperCase();31 const rows = await sql<Row[]>`select * from countries where slug = ${slugOrIso2.toLowerCase()} or iso2 = ${up} or iso3 = ${up} limit 1`;32 return rows[0] ?? null;33}3435/** Resolve {slug, name} for (entityType, entityId) pairs in one query per entity type. */36export async function resolveEntityRefs(pairs: Array<{ type: string; id: string | null }>): Promise<Map<string, { slug: string; name: string }>> {37 const sql = pg();38 const out = new Map<string, { slug: string; name: string }>();39 const byTable = new Map<string, { def: (typeof TABLES)[string]; ids: Set<string> }>();40 for (const p of pairs) {41 if (!p.id) continue;42 const def = TABLES[p.type];43 if (!def) continue;44 let g = byTable.get(def.table);45 if (!g) { g = { def, ids: new Set() }; byTable.set(def.table, g); }46 g.ids.add(p.id);47 }48 await Promise.all(49 [...byTable.values()].map(async ({ def, ids }) => {50 const list = [...ids];51 const rows = await sql<Row[]>`select ${sql(def.idCol)} as id, ${sql(def.slugCol)} as slug, ${sql(def.nameCol)} as name from ${sql(def.table)} where ${sql(def.idCol)} = any(${list})`;52 for (const r of rows) out.set(`${def.table}:${reqStr(r.id)}`, { slug: reqStr(r.slug), name: reqStr(r.name) });53 }),54 );55 // re-key by (type,id) so callers can look up with their own entity type56 const keyed = new Map<string, { slug: string; name: string }>();57 for (const p of pairs) {58 if (!p.id) continue;59 const def = TABLES[p.type];60 if (!def) continue;61 const v = out.get(`${def.table}:${p.id}`);62 if (v) keyed.set(`${p.type}:${p.id}`, v);63 }64 return keyed;65}6667export function entityKey(type: unknown, id: unknown): string {68 return `${str(type) ?? ""}:${str(id) ?? ""}`;69}7071/** href for a resolved entity on the web app. */72export function hrefFor(type: string, slug: string): string {73 switch (type) {74 case "facility": case "campus": return `/datacenters/${slug}`;75 case "operator": case "company": case "carrier": return `/operators/${slug}`;76 case "country": return `/countries/${slug}`;77 case "metro": return `/datacenters/markets/${slug}`;78 case "cloud_region": return `/cloud-regions/${slug}`;79 case "project": case "expansion": case "construction_phase": return `/projects/${slug}`;80 case "ixp": return `/ixps/${slug}`;81 default: return `/search?q=${encodeURIComponent(slug)}`;82 }83}84