Skip to content

Make connection names a compile-time surface, not a string #331

Description

@nstfkc

Follow-up from the review of #329, which added named connections.

Model.on(name: string) and DB.connection(name: string) take any string. An unknown one raises UnknownConnectionError and lists what is configured — but only when that query runs, which for the nightly sweep the feature exists to isolate means 3am rather than the edit.

That is the same gap the PR argues about elsewhere and closes everywhere it can: on("analitycs") silently running on the hot path is the incident the second pool was configured to prevent, and the runtime refusal is the last line of defence rather than the first.

A declaration-merged interface, in the style the framework already uses for generated surfaces, would make it a type error at the call site:

declare module "gemi/database" {
  interface ConnectionNames {
    analytics: true
  }
}

Subscription.on("analitycs")   // ✗ not assignable to "default" | "analytics"

Open questions worth settling before building it:

  • Where the names come from. app/config/database.ts is application code, not a generated artifact, so nothing emits a type from it today. Either the app declares the interface by hand (cheap, and drifts from the config), or gemi check / the generator learns to read the config (accurate, and adds a build step for what is a handful of strings).
  • The fallback has to stay open. A name computed at runtime — a tenant router, a test harness — must still be expressible, so the parameter type wants to be keyof ConnectionNames | (string & {}) or an explicit escape hatch rather than a closed union.
  • Empty by default. With no declarations the interface is empty, and keyof on it must degrade to string rather than to never, or every existing call site becomes an error.

Not a blocker for #329: the runtime refusal is correct, loud and tested. This is about moving the failure from 3am to the keyboard.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions