Skip to content

PgStatement.first() returns undefined instead of null, diverging from the D1 adapter's contract #8361

Description

@JSONbored

Context

src/selfhost/pg-adapter.ts and src/selfhost/d1-adapter.ts both implement a Statement.first(colName)
method with the same documented contract: Promise<T | null>. The D1 adapter honors this correctly:

// src/selfhost/d1-adapter.ts:57-61
return ((colName != null ? row[colName] : row) ?? null) as T | null;

The ?? coalesce guarantees null is returned whenever the row exists but the requested column is
SQL NULL or the key is absent from the row object.

The Postgres adapter has no equivalent coalesce:

// src/selfhost/pg-adapter.ts:38-43
return (colName ? row[colName] : row) as T;

When row[colName] is undefined (column absent) or the driver represents a SQL NULL as
undefined rather than null, this returns undefined cast as T — breaking the documented
T | null contract and diverging from the D1 sibling for callers that treat the two backends
interchangeably (the whole point of the adapter abstraction in backend-contracts.ts).

This is a known bug class in this repo — see the "D1 double .first() = undefined" pattern already
fixed elsewhere — but this specific sibling divergence between pg-adapter.ts and d1-adapter.ts
hasn't been addressed.

Existing test asymmetry confirms the gap: test/unit/selfhost-d1-adapter.test.ts:67 has a test
titled "first(colName) returns null when the row exists but the column value is NULL". The analogous
test in test/unit/selfhost-pg-adapter.test.ts:44 never exercises a NULL/absent-column case at all.

Requirements

  • PgStatement.first(colName) in src/selfhost/pg-adapter.ts must coalesce to null exactly like
    d1-adapter.ts's implementation: return ((colName != null ? row[colName] : row) ?? null) as T | null;
    (or the Postgres-appropriate equivalent — check the actual current signature before writing the
    patch, don't assume this snippet compiles verbatim against pg-adapter.ts's row type).
  • Do not change d1-adapter.ts — it is already correct and is the reference implementation to match.
  • Do not change any other method on PgStatement — this issue is scoped to first() only.

Deliverables

  • PgStatement.first() in src/selfhost/pg-adapter.ts returns null (never undefined) when the
    row exists but the requested column is SQL NULL or absent.
  • test/unit/selfhost-pg-adapter.test.ts gains a test mirroring
    test/unit/selfhost-d1-adapter.test.ts:67 — "first(colName) returns null when the row exists but
    the column value is NULL" — for the Postgres adapter.

Test Coverage Requirements

This repo's Codecov patch gate is 99%+ of changed lines and branches (src/** is covered). The new
?? null branch added to pg-adapter.ts must be exercised by the new test above, covering both the
present-value case (already covered) and the NULL/absent case (the new test).

Expected Outcome

PgStatement.first() and Statement.first() (D1) behave identically for the NULL/absent-column case,
both honoring the Promise<T | null> contract. Any code that branches on === null (rather than
== null/truthiness) behaves the same regardless of which backend is configured.

Links & Resources

  • src/selfhost/pg-adapter.ts:38-43 — the method to fix
  • src/selfhost/d1-adapter.ts:57-61 — the reference implementation to match
  • test/unit/selfhost-d1-adapter.test.ts:67 — the test to mirror
  • test/unit/selfhost-pg-adapter.test.ts:44 — the existing test to extend

Metadata

Metadata

Assignees

No one assigned

    Labels

    gittensor:bugGittensor-scored bug fix — scores a 0.05x multiplier.help wantedExtra attention is needed

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions