spb/datacenterindex
Public
HTML 53.9%
TypeScript 44.5%
JavaScript 0.6%
SQL 0.5%
1/** Side-by-side operator comparison (2–5 operators): summary, pipeline, velocity, new markets, recent projects. */2import type { OperatorComparison } from "@dci/core";3import { pg, projectLive } from "../lib/sql.js";4import { reqStr, type Row } from "../lib/rows.js";5import { notFound } from "../lib/http.js";6import { expansionVelocity, pipelineBreakdown, scopeFor } from "../lib/pipeline.js";7import { newMarkets, operatorSummaryById } from "./operators.js";8import { projectsWhere } from "./projects.js";910export const COMPARE_METHODOLOGY = "Each column is computed the same way as the operator page: containment-aware facility counts, known MW = published operational figures only (coverage given per operator), pipeline from facility statuses and live project records (hidden / merged projects excluded), velocity windows from opened_on (else first_seen) and announced_on (else first indexed).";1112export async function compareOperators(slugs: string[]): Promise<OperatorComparison> {13 const sql = pg();14 const ids: string[] = [];15 for (const slug of slugs) {16 const r = (await sql<Row[]>`select id from operators where slug = ${slug} or id = ${slug} limit 1`)[0];17 if (!r) throw notFound(`operator ${slug}`);18 ids.push(reqStr(r.id));19 }20 const operators = await Promise.all(ids.map(async (id) => {21 const scope = scopeFor(sql, { operatorId: id });22 const [summary, pipeline, velocity, markets, recentProjects, countries] = await Promise.all([23 operatorSummaryById(id),24 pipelineBreakdown(scope),25 expansionVelocity(scope),26 newMarkets(id, 12),27 projectsWhere(sql`${projectLive(sql)} and p.operator_id = ${id}`, 5),28 sql<Row[]>`select distinct country_iso2 from facilities where operator_id = ${id} and merged_into is null and country_iso2 is not null order by 1`,29 ]);30 if (!summary) throw notFound(`operator ${id}`);31 return { ...summary, pipeline, velocity, aiCount: summary.aiCount ?? 0, newMarkets12m: markets, recentProjects, countriesList: countries.map((c) => reqStr(c.country_iso2)), coverage: summary.mwCoverage ?? 0 };32 }));33 return { operators, generatedAt: new Date().toISOString() };34}35