Expand description
Persistence helpers for the admin engine — basic CREATE + UPDATE.
Deliberately small. No ORM integration, no schema discovery, no
migration framework. The caller hands in a (table, column → value)
map and these helpers build a parameterised INSERT / UPDATE
against the existing Db pool. Column names are sorted so the
emitted SQL is deterministic across runs.
Functions§
- bulk_
delete DELETE FROM table WHERE "id" IN (?, ?, …). Same parameter-only guarantees asbulk_update. Emptyids→ no-op.- bulk_
update UPDATE table SET "<field>" = ? WHERE "id" IN (?, ?, …).- count_
filtered_ records SELECT COUNT(*)counterpart offilter_records. SameWHEREshape, noORDER BY/LIMIT/OFFSET. Feeds the page-count math.- count_
records SELECT COUNT(*) FROM "<table>". Used by the table footer to render the “Showing N of M” label and by the page header to produce the records-count subtitle.- count_
search_ records SELECT COUNT(*)counterpart ofsearch_records— sameWHEREclause, noORDER BY/LIMIT. Feeds the “Showing N of M” label when the table is in search mode.- ensure_
table - Run an arbitrary
CREATE TABLE IF NOT EXISTS …(or any other idempotent DDL) supplied by anAdminUiModel. Generic — every model brings its own schema string. - filter_
records - Run a windowed
SELECTagainsttablecombining metadata-driven filters and free-text search: - form_
to_ column_ map - Project a
FormConfig’s field values into acolumn → valuemap suitable forinsert_record/update_record. The primary-key column is always skipped — the id is auto-generated on INSERT and bound separately on UPDATE. - get_
record_ by_ id - Fetch a single row by id and return its columns as a flat
column → stringmap. NULL becomes an empty string. Returns an empty map when no row matches — the GET handler treats that case as “fall back to the create-mode demo form” rather than surfacing an error. - insert_
record - Run an
INSERT INTO <table> (<cols>) VALUES (<placeholders>)againstdb. Returns the newly-allocated row id (last_insert_rowid()). - list_
records - List rows from
table, newest first, with a hardLIMIT/OFFSETwindow. Both bounds are bound positionally — caller values never enter the SQL text. Each row is flattened to the samecolumn → stringshape asget_record_by_id. - search_
records - Case-insensitive partial match across an arbitrary list of
searchable_fields. The query is lower-cased once, wrapped in%…%, and bound once per searchable field — no interpolation into the SQL text. Results are ordered newest-first and windowed byLIMIT/OFFSET, matchinglist_records. An emptysearchable_fieldsslice (model declared no search columns) degrades to a normalSELECT * … ORDER BY id DESC LIMIT…. - update_
record - Run an
UPDATE <table> SET <col = ?>... WHERE id = ?againstdb. The primary-key column is fixed toidfor now (matches the demo table); broaden when a model needs a custom PK column.