synology_apm_repo.sdk.units.saas.tree_strategy.recursive_group_flat module

RecursiveGroupFlatTree: M365 Mail’s real folder hierarchy — groups (folders) recurse via parent-pointer, like RecursiveTree, but each group’s leaves (messages) live in a separate, flat, non-recursive table instead of recursing themselves, combining the two schema shapes every service-level DB in this project expands into (parent-pointer recursion; a flat list optionally grouped by one key).

class synology_apm_repo.sdk.units.saas.tree_strategy.recursive_group_flat.RecursiveGroupFlatTree(provider, *, group_table, group_columns, group_id_column, group_name_column, group_parent_column, group_root_id, leaf_table, leaf_columns, leaf_id_column, leaf_group_column, display_name, order_by, descending=False)

Bases: object

M365 Mail’s real folder hierarchy: mail_folder_table is a real, named, self-referencing table (folder_id/folder_name/ parent_folder_id, rooted at a synthetic anchor id exactly like RecursiveTree’s own root_id convention) whose rows are always folders — unlike RecursiveTree/NamedGroupRecursiveTree’s own mixed tables, no is_folder() check is needed. Its leaves live in a separate, flat, non-recursive table keyed by its own group-fk column — a message never nests and never has children of its own. “Group” here means what it means for NamedGroupFlatTree/ NamedGroupRecursiveTree (a real definitions table with its own display-name column), just recursive rather than flat, and with one id-space serving as both this table’s own recursion key and the leaf table’s own foreign key.

Every key is a growing-prefix chain, one real folder id per level (e.g. ("inbox",), ("inbox", "haha")), not a bare id the way RecursiveTree keys Drive: Mail stays a plain SaasWorkloadProvider (not RecursiveTreeSaasProvider), so units/resolve.py’s generic ref-descent needs every non-leaf child’s key to be a genuine prefix of any deeper target’s key. A leaf’s key extends its own containing folder’s key by one more segment (its own leaf id).

children_of() for one folder lists its real subfolders — always, even with zero backed-up messages, the entire point of this class — before that folder’s own leaves. See children_of() itself for how each half is fetched and windowed.

A genuine leaf’s own key naturally returns [] from children_of() with no explicit key-shape guard (unlike every sibling class in this package): a leaf’s own id never appears as any row’s parent_folder_id in either table. A NULL leaf_group_column value is a documented non-concern the same way: it never matches WHERE ... = ?, and real M365 rows always populate it.

contact_folder_table has this exact same shape and could reuse this class later — out of scope for now, contact.py is untouched.

async children_of(key, *, offset=0, limit=None)

One folder’s real subfolders (always, even with zero backed-up messages) before that folder’s own leaves. A folder’s own subfolder count is small (this mailbox’s own folder fan-out, never its message count), so _list_subfolders fully materializes and paginates it in Python, the same small-bounded-scan precedent _NamedGroupTable.list_top_level already establishes; only the leaf half issues a real WHERE/ORDER BY/LIMIT/OFFSET query, windowed to cover only whatever part of [offset, offset+limit) the subfolders didn’t already satisfy.

row_for(key)