synology_apm_repo.sdk.storage.table module

Schema-tolerant SQLite table access — declare the columns a query needs and whether each is required, and this introspects the real table once (PRAGMA table_info) to work out which optional columns this particular connector version’s schema actually has. A missing optional column reads back as None for every row instead of raising sqlite3.OperationalError: no such column — the failure mode this project hits repeatedly across every workload DB, not just those two.

class synology_apm_repo.sdk.storage.table.Column(name, required=True)

Bases: object

One column a Table expects — required=False for a column only some connector-version schemas have.

name: str
required: bool = True
class synology_apm_repo.sdk.storage.table.Table(name, columns)

Bases: object

A schema-tolerant view of one real SQLite table.

Introspects PRAGMA table_info(name) once at construction time — cheap, and the schema can’t change under a read-only connection mid Table lifetime. Raises DataCorruptError immediately if any required column is absent; missing optional columns are simply left out of the SELECT and backfilled as None in every row.

Constructed via await Table.create(conn, name, columns), never Table(conn, ...) directly: introspecting PRAGMA table_info is a database query, and __init__ cannot be async def — the same async-classmethod-factory idiom aiosqlite.connect() uses.

async classmethod create(conn, name, columns, *, index_hints=())

Introspect name’s real schema and return a Table bound to conn.

index_hints: each entry is a column-name sequence this table’s callers intend to filter/sort by (e.g. [["parent_folder_id"]], or a composite), declared here alongside the schema introspection rather than scattered into query logic later. Each is passed straight to apply_index_hint, which doesn’t need to know or care whether conn allows writing.

async static exists_in(conn, name)

Whether name exists at all (and has at least one column) — a non-raising presence check, for the genuinely different situation from a missing column: some repository shapes don’t have a given table at all (e.g. file_meta may not exist in every repository shape). Callers needing that distinction check this before constructing a Table — the constructor’s own “table must exist” contract stays intact for the normal “table exists but drifted a column” case.

property columns_present: frozenset[str]

The table’s actual full column set, as introspected — independent of which columns this Table was asked to declare. For call sites that must pick a real column name via a heuristic rather than a fixed declaration, because the table’s schema varies across repositories and so there is no fixed name to declare.

async select(where='', params=(), *, order_by=None, limit=None, offset=0)

Run SELECT <present columns> FROM <name> [WHERE <where>] [ORDER BY <order_by>] [LIMIT ? OFFSET ?] and yield each row as {column_name: value}, with every declared-but-absent optional column backfilled as None.

where/order_by are literal SQL fragments written by the caller (not untrusted input) — parameterize actual values via params; this only ever interpolates column/table names this module itself introspected.

limit/offset are the pagination primitives: limit=None (default) means “no cap” but still lets offset apply via SQLite’s own LIMIT -1 idiom, since OFFSET alone isn’t valid syntax without some LIMIT present. Both are parameterized (?), since they’re plain integers from the caller, not schema-derived text.

async select_one(where='', params=())
synology_apm_repo.sdk.storage.table.as_int(value)

Narrow one of Table.select’s object | None values to int — a thin, explicit boundary between a caller’s typed dataclasses and the untyped dict rows SQLite hands back, rather than scattering # type: ignore at every call site. Raises DataCorruptError, the same exception this module’s own Table.create already raises for a schema mismatch, rather than a bare AssertionError a caller’s except (..., DataCorruptError, ...) degrade path wouldn’t catch.

synology_apm_repo.sdk.storage.table.as_str(value)

Narrow one of Table.select’s object | None values to str, the same way as_int narrows to int.

synology_apm_repo.sdk.storage.table.sql_placeholders(n)

A comma-joined n-item "?" placeholder list for a batched WHERE <column> IN (...) query — every caller building one of these still owns its own “nothing to look up” early return (an empty IN () is invalid SQL), just not the placeholder string itself.