synology_apm_repo.sdk.units.saas.object_name_index module¶
Resolves a per-version, connector-recorded index from
copy_target_version.version_spec, plus the shared lookup helpers
(resolve_service_db, read_indexed_table, read_id_to_name_map,
read_grouped_names) every SaaS provider’s own secondary-table
lookups build on.
The connector records, at backup-completion time, exactly which object
holds each named service DB and exactly which physical location
(<stream_uuid>_<offset>_<length>, the shape parse_object_db_id
parses) holds all of them — a lookup into fixed, connector-written
bookkeeping, never a schema-scanning guess: a schema-only scan could
never safely replace this anyway, since some tables are byte-for-byte
identical in schema across workload variants (Archive Mail’s
mail_table vs. regular Mail’s) and only the index’s own naming, not
the schema, can tell them apart.
version_spec may be vault-key encrypted — see
catalog.version.parse_version_spec, the shared decrypt-then-parse
entry point for this column. Every function here resolves to None
rather than raising when the index simply isn’t recorded; a resolved
index whose own content later fails to validate is a distinct case,
surfaced by provider.py’s own _open_table_via_index, not here.
- class synology_apm_repo.sdk.units.saas.object_name_index.ObjectNameIndex(stream_uuid, offset, length, object_ids)¶
Bases:
objectOne version’s connector-recorded map of indexed db name -> object_id (
object_ids), plus exactly whichObjectDbCandidate(offset/length) holds all of them — parsed straight fromobject_db_id, the authoritative physical location; nothing downstream of this ever needs to scan for it.
- async synology_apm_repo.sdk.units.saas.object_name_index.resolve_object_name_index(repo, version)¶
Noneon any failure to locate the index — nocopy_target_versiontable, no row for this version, unparseable/undecryptableversion_spec, or a missing/malformedadditional_meta: all shapes of “no index recorded here” (an old repository, or a connector version predating this bookkeeping), never corruption. Never raises for those; a resolved index whose content later fails to validate is a distinct case, handled by this module’s callers, not here.
- async synology_apm_repo.sdk.units.saas.object_name_index.resolve_service_db(dedup_file, object_db, object_name_index, object_names, table_name)¶
The shared “no-scan” resolution loop behind both
SaasWorkloadProvider._open_table_via_index(which keeps the returnedSqliteSourceopen long-term) andread_indexed_table(which reads it once and closes it immediately) — only how each caller disposes of a successful result differs, not how one is found. Tries everyobject_namesalias againstobject_db(already loaded atobject_name_index’s own location) in order, opening and returning the first whose resolved object both exists and actually definestable_name. ReturnsNone, closing nothing, when no alias resolves.
- async synology_apm_repo.sdk.units.saas.object_name_index.read_indexed_table(dedup_file, object_name_index, object_names, table_name, reader)¶
Best-effort secondary-table lookup behind the object-name index (M365’s
mail_folder_table/contact_folder_table, GWS’s own label/group name tables — seemail.py/contact.py), as opposed toSaasWorkloadProvider.create’s own primary-table resolution, which this doesn’t replace. Handsreaderthe live connectionresolve_service_dbresolves.Noneonobject_name_indexbeingNone, every name missing, or any read/decompress/validate failure — this is enrichment (a nicer display name, an extra attrs field), never required content, so a caller degrades to showing less rather than failing.By design, no schema-only scan: the same table name can legitimately mean two different real tables depending on which db holds it (see
mail.py’s own_gws_mail_labels), so only the index’s own naming can tell them apart.
- async synology_apm_repo.sdk.units.saas.object_name_index.read_id_to_name_map(dedup_file, object_name_index, object_names, table_name, *, id_column, name_column)¶
read_indexed_tablespecialized for the “id -> display name” shape every folder/label/group definitions table in this project shares (mail_folder_table,contact_folder_table,mail_label_table’s definitions half,group_table, …) —table_name’s ownid_column/name_columnvalues, keyed bystr(id_column value).
- async synology_apm_repo.sdk.units.saas.object_name_index.read_grouped_names(dedup_file, object_name_index, *, definition_names, definition_table, id_column, name_column, membership_names, membership_table, item_column, group_column)¶
Best-effort
item_id -> [real group/label names]map, built from a definitions table (id_column -> name_column) plus a membership table (item_column,group_column) — the shape GWS’s own many-to-many label/group mechanisms share (mail.py’s labels,contact.py’s groups).Noneif either half is unavailable — a caller degrades to showing no labels/groups at all, never a wrong or incomplete join.