Skip to content

Type procs, functions, and TVFs as [Args, ReturnType] tuples #22

@damusix

Description

@damusix

Summary

Procs, functions, and TVFs should be typed as tuples: [Args, ReturnType] instead of just Args.

Currently, the generic type maps only capture the input parameters:

type MyProcs = {
    get_users: { department_id: number };
    refresh_cache: void;
};

// Return type must be specified at every call site
const users = await ctx.proc<User>('get_users', { department_id: 1 });

Proposed: each entry becomes a tuple [Args, ReturnType]:

type MyProcs = {
    get_users: [{ department_id: number }, User];
    refresh_cache: void;  // shorthand for [void, void]
};

// Return type is inferred when the tuple provides it
const users = await ctx.proc('get_users', { department_id: 1 }); // → User[]

// But the generic is still available for overriding or ad-hoc calls
const users = await ctx.proc<SpecialUser>('get_users', { department_id: 1 }); // → SpecialUser[]
await ctx.proc('refresh_cache'); // → void

Rules

  • SomeProc: [Args, ReturnType] — full tuple form
  • If Args is empty/unused, use void[void, ReturnType]
  • If ReturnType is empty/unused, use void[Args, void]
  • Plain void (no tuple) is shorthand for [void, void] — no args, no meaningful return
  • proc() and tvf() currently return T[] — with tuples, return becomes ReturnType[]
  • func() currently returns scalar T — with tuples, return becomes ReturnType
  • The T return type generic remains available — it defaults to the tuple's ReturnType but can be explicitly overridden at the call site

Behavior

  1. Tuple provides return type, no generic specified → infer from tuple
  2. Tuple provides return type, generic explicitly specified → generic wins (override)
  3. No tuple / plain void → falls back to unknown (same as today), user specifies T manually
  4. Ad-hoc / untyped calls → user can still call ctx.proc<MyType>(...) for procs not in the type map, or to override the mapped return type

Affected Surfaces

  • Context class generics: Context<DB, Procs, Funcs, Tvfs>
  • ctx.proc(), ctx.func(), ctx.tvf() method signatures
  • createContext<DB, Procs, Funcs, Tvfs>() factory
  • ImpersonatedScope<DB, Procs, Funcs, Tvfs> interface
  • SDK type exports

Benefit

The type map becomes the single source of truth for both input and output shapes, eliminating repetitive annotations at call sites — while preserving full flexibility for ad-hoc calls and explicit overrides.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions