db/fact_queries.ts

Raw queries against the fact and fact_ref tables.

Convention: deps: QueryDeps first, no audit side effects, mutations are idempotent (ON CONFLICT DO NOTHING) so the same hash can be written by two callers without the second observing an error.

Higher-level lifecycle (verify-on-read, JSON ref auto-extraction, embedded-vs-referenced selection) lives in db/fact_store.ts. Queries here are deliberately mechanical.

view source

Declarations
#

12 declarations

FactMetaRow
#

db/fact_queries.ts view source

FactMetaRow import type {FactMetaRow} from '@fuzdev/fuz_app/db/fact_queries.js';

Subset returned by metadata-only queries (no bytes payload).

hash

type FactHash

external_url

type string | null

content_type

type string | null

size

type number | string

created_at

type Date

FactRow
#

db/fact_queries.ts view source

FactRow import type {FactRow} from '@fuzdev/fuz_app/db/fact_queries.js';

Row shape for SELECT … FROM fact.

hash

type FactHash

bytes

type Uint8Array | null

external_url

type string | null

content_type

type string | null

size

type number | string

created_at

type Date

OrphanFactsListResult
#

db/fact_queries.ts view source

OrphanFactsListResult import type {OrphanFactsListResult} from '@fuzdev/fuz_app/db/fact_queries.js';

Summary + sample shape returned by query_orphan_facts_list. The sample is a small page (default 20 rows) shown in the admin panel so the operator has *some* visibility into what they're about to delete. Total count and total_size_bytes are over the full orphan set (matching the same predicate the delete handler will run).

count

type number

total_size_bytes

type number

sample

type Array<{ hash: FactHash; size: number; created_at: string; external_url: string | null; }>

query_delete_fact
#

db/fact_queries.ts view source

(deps: QueryDeps, hash: string & $brand<"FactHash">): Promise<{ size: number; external_url: string | null; } | null> import {query_delete_fact} from '@fuzdev/fuz_app/db/fact_queries.js';

Drop a fact row. Cascades fact_ref rows via the ON DELETE CASCADE FK on source_hash. Returns the deleted row's (size, external_url) so the caller can unlink the disk file (if any) and tally freed bytes, or null when no row matched (idempotent: deleting an absent fact is not an error).

NOTE: this is a low-level primitive — callers MUST verify the fact is truly orphan (no referencing cell) before calling. The orphan check lives in query_orphan_facts_* below; the lifecycle wrapper in PgFactStore.delete handles the disk-file unlink.

deps

hash

type string & $brand<"FactHash">

returns

Promise<{ size: number; external_url: string | null; } | null>

query_get_fact
#

db/fact_queries.ts view source

(deps: QueryDeps, hash: string & $brand<"FactHash">): Promise<FactRow | null> import {query_get_fact} from '@fuzdev/fuz_app/db/fact_queries.js';

Fetch a fact's full row (including embedded bytes). Use this from FactStore.get; cheaper accessors live below.

deps

hash

type string & $brand<"FactHash">

returns

Promise<FactRow | null>

query_get_fact_meta
#

db/fact_queries.ts view source

(deps: QueryDeps, hash: string & $brand<"FactHash">): Promise<FactMetaRow | null> import {query_get_fact_meta} from '@fuzdev/fuz_app/db/fact_queries.js';

Fetch metadata only — skips the (potentially large) bytes column.

deps

hash

type string & $brand<"FactHash">

returns

Promise<FactMetaRow | null>

query_get_fact_refs
#

db/fact_queries.ts view source

(deps: QueryDeps, source_hash: string & $brand<"FactHash">): Promise<(string & $brand<"FactHash">)[]> import {query_get_fact_refs} from '@fuzdev/fuz_app/db/fact_queries.js';

List declared targets for a source fact. Order is unspecified; callers that need stable ordering should sort.

deps

source_hash

type string & $brand<"FactHash">

returns

Promise<(string & $brand<"FactHash">)[]>

query_has_fact
#

db/fact_queries.ts view source

(deps: QueryDeps, hash: string & $brand<"FactHash">): Promise<boolean> import {query_has_fact} from '@fuzdev/fuz_app/db/fact_queries.js';

Cheap existence check. Backed by the fact PK index.

deps

hash

type string & $brand<"FactHash">

returns

Promise<boolean>

query_orphan_facts_list
#

db/fact_queries.ts view source

(deps: QueryDeps, older_than: Date | null, sample_limit: number): Promise<OrphanFactsListResult> import {query_orphan_facts_list} from '@fuzdev/fuz_app/db/fact_queries.js';

Compute the "orphan facts" set: rows in fact where no active (non-tombstone) cell.refs array contains the hash.

The cell join is deliberately app-coupled — fact lives in the fuz_facts namespace and cell.refs lives in fuz_cell, but the orphan predicate only makes sense in apps that route content through cells. When a non-cell fact consumer ever appears (signed memo outputs? external fact mirrors?) the predicate moves to a generic fact_consumers registry; today the cell layer is the only consumer.

The older_than filter applies to fact.created_at. Pass null to skip the filter (used by the list-summary preview); the delete handler always passes a non-null cutoff (default 0, meaning "any orphan").

deps

query deps

older_than

filter to facts created before this Date (or null to skip)

type Date | null

sample_limit

row cap for the returned sample

type number

returns

Promise<OrphanFactsListResult>

query_orphan_facts_select_for_delete
#

db/fact_queries.ts view source

(deps: QueryDeps, older_than: Date): Promise<{ hash: string & $brand<"FactHash">; size: number; external_url: string | null; }[]> import {query_orphan_facts_select_for_delete} from '@fuzdev/fuz_app/db/fact_queries.js';

Select the orphan-fact hashes for deletion. Returns the rows directly (no row-count limit) — callers iterate to unlink disk files. The older_than cutoff is required (non-null) here: bulk delete should always be operator-scoped to a time window. A "delete all" sweep passes a far-future cutoff, not null.

deps

older_than

type Date

returns

Promise<{ hash: string & $brand<"FactHash">; size: number; external_url: string | null; }[]>

query_put_fact
#

db/fact_queries.ts view source

(deps: QueryDeps, input: { hash: string & $brand<"FactHash">; bytes: Uint8Array<ArrayBufferLike> | null; external_url: string | null; content_type: string | null; size: number; }): Promise<...> import {query_put_fact} from '@fuzdev/fuz_app/db/fact_queries.js';

Idempotently insert a fact row.

bytes xor external_url per the fact_storage_present CHECK constraint; the caller is responsible for satisfying it (the queries layer does not second-guess). Returns true when a new row was inserted, false when a row already existed (caller can use this to decide whether to also write fact_ref).

deps

input

type { hash: string & $brand<"FactHash">; bytes: Uint8Array<ArrayBufferLike> | null; external_url: string | null; content_type: string | null; size: number; }

returns

Promise<boolean>

query_put_fact_refs
#

db/fact_queries.ts view source

(deps: QueryDeps, source_hash: string & $brand<"FactHash">, target_hashes: (string & $brand<"FactHash">)[]): Promise<void> import {query_put_fact_refs} from '@fuzdev/fuz_app/db/fact_queries.js';

Idempotently insert declared refs for a fact. No-ops on `(source_hash, target_hash)` collisions and skips the round trip entirely when target_hashes is empty.

deps

source_hash

type string & $brand<"FactHash">

target_hashes

type (string & $brand<"FactHash">)[]

returns

Promise<void>

Depends on
#

Imported by
#