loom.core.repository.abc¶
- class loom.core.repository.abc.Cursor(backend, keys, tie_breaker)[source]¶
Bases:
LoomFrozenStructDecoded cursor position.
- class loom.core.repository.abc.CursorResult(*, items, next_cursor, has_next)[source]¶
Bases:
LoomFrozenStruct,Generic[OutputT]Result of a cursor-paginated query.
- class loom.core.repository.abc.FilterGroup(filters, op='AND')[source]¶
Bases:
LoomFrozenStructA group of filter conditions combined with AND or OR logic.
- Parameters:
filters (tuple[FilterSpec, ...]) – Filter conditions to combine.
op (Literal['AND', 'OR']) – Logical operator:
"AND"(default) or"OR".
Example:
FilterGroup( filters=( FilterSpec("price", FilterOp.GTE, 10.0), FilterSpec("price", FilterOp.LTE, 100.0), ), op="AND", )
- class loom.core.repository.abc.FilterOp(value)[source]¶
Bases:
StrEnumFilter operator applied to a single field.
- EQ¶
Exact equality.
- NE¶
Inequality.
- GT¶
Greater than.
- GTE¶
Greater than or equal.
- LT¶
Less than.
- LTE¶
Less than or equal.
- IN¶
Value is in a collection.
- LIKE¶
Text pattern match (case-sensitive).
- ILIKE¶
Text pattern match (case-insensitive).
- IS_NULL¶
Field has no value.
- EXISTS¶
Related collection is non-empty.
- NOT_EXISTS¶
Related collection is empty.
- class loom.core.repository.abc.FilterParams(*, filters=<factory>)[source]¶
Bases:
LoomFrozenStructGeneric filter container for list queries.
- class loom.core.repository.abc.FilterSpec(field, op, value=None)[source]¶
Bases:
LoomFrozenStructA single field filter condition.
- Parameters:
Example:
FilterSpec(field="price", op=FilterOp.GTE, value=10.0)
- class loom.core.repository.abc.PageParams(*, page=1, limit=50)[source]¶
Bases:
LoomFrozenStructPagination parameters for list queries.
- class loom.core.repository.abc.PageResult(*, items, total_count, page, limit, has_next)[source]¶
Bases:
LoomFrozenStruct,Generic[OutputT]Paginated result set returned by list queries.
- class loom.core.repository.abc.PaginationMode(value)[source]¶
Bases:
StrEnumPagination strategy for list and query operations.
- OFFSET¶
Classic page+limit pagination with a total count. Convenient but optional: computing
total_countand skipping to arbitrary offsets is not efficiently supported by every backend, so a backend may decline this mode.
- CURSOR¶
Keyset (cursor) pagination. The portable mode — supported by every backend and performant at scale; requires a stable sort order with a tie-breaker.
- class loom.core.repository.abc.QueryCompiler(*args, **kwargs)[source]¶
Bases:
Protocol[FilterT_co,SortT_co]Compiles query parts into a backend’s native expressions.
FilterT_cois the native filter expression type (a SQLAlchemy clause, a Mongo filter document, …) andSortT_cothe native sort expression type.- compile_filter(group)[source]¶
Compile a filter group into a native filter expression.
- Parameters:
group (FilterGroup) – Flat AND/OR group of field conditions.
- Returns:
The backend’s filter expression.
- Raises:
UnsupportedQuery – If a field or a
FilterOpcannot be served by the backend; the reason names both the operator and the backend.- Return type:
FilterT_co
- compile_sort(sort)[source]¶
Compile sort directives into a native sort expression.
- Parameters:
- Returns:
The backend’s sort expression.
- Raises:
UnsupportedQuery – If a sort field cannot be served by the backend.
- Return type:
SortT_co
- class loom.core.repository.abc.QuerySpec(filters=None, sort=(), pagination=PaginationMode.OFFSET, limit=50, page=1, cursor=None)[source]¶
Bases:
LoomFrozenStructStructured query contract for list operations.
Replaces the flat
FilterParamsdict with an explicit, type-safe representation. The repository implementation compiles this into backend-specific clauses at query time.- Parameters:
filters (FilterGroup | None) – Optional filter group applied to the query.
sort (tuple[SortSpec, ...]) – Ordered tuple of sort directives.
pagination (PaginationMode) – Pagination strategy. Defaults to
OFFSET.limit (int) – Maximum number of items per page (1-1000).
page (int) – 1-based page number (only for
OFFSETmode).cursor (str | None) – Opaque cursor token (only for
CURSORmode).
Example:
QuerySpec( filters=FilterGroup( filters=(FilterSpec("price", FilterOp.GTE, 10.0),), ), sort=(SortSpec("name"),), pagination=PaginationMode.OFFSET, limit=20, page=1, )
- class loom.core.repository.abc.BulkCreatable(*args, **kwargs)[source]¶
Bases:
Protocol[ModelT]Repository capability: persist several new entities in one round trip.
- class loom.core.repository.abc.Countable(*args, **kwargs)[source]¶
Bases:
Protocol[ModelT]Repository capability: existence checks and counting.
- class loom.core.repository.abc.Creatable(*args, **kwargs)[source]¶
Bases:
Protocol[ModelT]Repository capability: persist new entities.
Example:
class CreateOrderUseCase(UseCase[Order, Order, Creatable[Order]]): async def execute(self, cmd: CreateOrderCommand = Input()) -> Order: return await self.main_repo.create(cmd)
- class loom.core.repository.abc.Deletable(*args, **kwargs)[source]¶
Bases:
Protocol[ModelT]Repository capability: remove entities.
- class loom.core.repository.abc.Listable(*args, **kwargs)[source]¶
Bases:
Protocol[ModelT]Repository capability: paginated and structured listing.
- async list_paginated(page_params, filter_params=None, profile='default')[source]¶
Fetch entities with offset pagination.
- Parameters:
page_params (PageParams)
filter_params (FilterParams | None)
profile (str)
- Return type:
PageResult[ModelT]
- async list_with_query(query, profile='default')[source]¶
Fetch entities using a structured query (offset or cursor mode).
- Parameters:
- Return type:
PageResult[ModelT] | CursorResult[ModelT]
- class loom.core.repository.abc.Readable(*args, **kwargs)[source]¶
Bases:
Protocol[ModelT]Repository capability: fetch individual entities.
Implement this to expose single-entity read operations.
Example:
class IProductRepository(Readable[Product], Protocol): async def find_by_sku(self, sku: str) -> Product | None: ...
- class loom.core.repository.abc.RepoFor(*args, **kwargs)[source]¶
Bases:
Readable[ModelT],Creatable[ModelT],Updatable[ModelT],Deletable[ModelT],Listable[ModelT],Countable[ModelT],Protocol[ModelT]Full-surface repository protocol for standard CRUD use cases.
Composes all capability protocols. Use this as the default
RepoTwhen a use case needs the complete CRUD surface. For use cases that only need a subset of operations, prefer the specific capability protocol (Readable,Creatable, etc.) to respect the Interface Segregation Principle.Example:
# Full surface — no third param needed, RepoFor[Any] is the default class CreateProductUseCase(UseCase[Product, Product]): async def execute(self, cmd: CreateProductCommand = Input()) -> Product: return await self.main_repo.create(cmd) # Specific capability — only what the use case needs class GetProductUseCase(UseCase[Product, Product | None, Readable[Product]]): async def execute(self, product_id: int) -> Product | None: return await self.main_repo.get_by_id(product_id)
- class loom.core.repository.abc.Updatable(*args, **kwargs)[source]¶
Bases:
Protocol[ModelT]Repository capability: mutate existing entities.
- class loom.core.repository.abc.Repository(*args, **kwargs)[source]¶
Bases:
RepositoryRead[OutputT,IdT],RepositoryWrite[OutputT,CreateT,UpdateT,IdT],Protocol[OutputT,CreateT,UpdateT,IdT]Combined read-write repository protocol.
- class loom.core.repository.abc.RepositoryRead(*args, **kwargs)[source]¶
Bases:
Protocol[OutputT,IdT]Protocol for read-only repository operations (get by id and paginated listing).
- async get_by_id(obj_id, profile='default')[source]¶
Fetch a single entity by its primary key.
- Parameters:
obj_id (IdT) – Primary key of the entity.
profile (str) – Loading profile name for eager-load options.
- Returns:
The entity output struct, or
Noneif not found.- Return type:
OutputT | None
- async count()[source]¶
Return the total number of entities in the repository.
- Returns:
Total row count as an integer.
- Return type:
- async list_paginated(page_params, filter_params=None, profile='default')[source]¶
Fetch a paginated list of entities.
- Parameters:
page_params (PageParams) – Pagination parameters (page and limit).
filter_params (FilterParams | None) – Optional filter criteria.
profile (str) – Loading profile name for eager-load options.
- Returns:
A
PageResultwith the matching items and pagination metadata.- Return type:
PageResult[OutputT]
- async list_with_query(query, profile='default')[source]¶
Fetch entities using a structured
QuerySpec.Supports both offset and cursor pagination, structured filters, and explicit sort directives. The concrete return type depends on
query.pagination:PaginationMode.OFFSET→PageResultPaginationMode.CURSOR→CursorResult
- Parameters:
- Returns:
A
PageResultfor offset queries or aCursorResultfor cursor queries.- Return type:
PageResult[OutputT] | CursorResult[OutputT]
- class loom.core.repository.abc.RepositoryWrite(*args, **kwargs)[source]¶
Bases:
Protocol[OutputT,CreateT,UpdateT,IdT]Protocol for write repository operations (create, update, delete).
- async create(data)[source]¶
Persist a new entity.
- Parameters:
data (CreateT) – Creation payload struct.
- Returns:
The newly created entity output struct.
- Return type:
OutputT
- class loom.core.repository.abc.SortSpec(field, direction='ASC')[source]¶
Bases:
LoomFrozenStructA single sort directive applied to a query.
- Parameters:
Example:
SortSpec(field="created_at", direction="DESC")
- class loom.core.repository.abc.SupportsCallerScopedSession(*args, **kwargs)[source]¶
Bases:
ProtocolOptional capability: report whether the caller owns the current session.
A repository that resolves its session from the calling context — a
@transactionalscope, a unit of work — runs its reads inside a session that is closed when that caller unwinds, and whose uncommitted writes are visible only to it. A wrapper that would otherwise detach a read from its caller must ask first: the cache layer skips its in-process coalescing while this returnsTrue, because a coalesced load outlives the caller that started it and would be shared with another one.A repository that does not implement this protocol is taken to own the scope of its own reads, which is what a repository opening and closing a session per call does.
This capability is provisional: it exists because each backend publishes its transaction through its own
ContextVar. It is expected to be replaced by the neutral transaction scope, and is not a stable extension point to build on.
- exception loom.core.repository.abc.UnsupportedQuery(backend, model, reason)[source]¶
Bases:
DomainErrorRaised when a backend cannot serve a query because of its arguments.
A capability the repository class does not declare is absent from DI and from the generated routes; this error covers the gaps that depend on a run-time argument instead, such as a lookup on a field the backend can only reach through a scan.
- loom.core.repository.abc.build_page_result(items, total_count, page_params)[source]¶
Construct a
PageResultfrom a list of items and pagination metadata.- Parameters:
items (list[OutputT]) – Entity output structs for the current page.
total_count (int) – Total number of matching entities across all pages.
page_params (PageParams) – The pagination parameters used for this query.
- Returns:
A populated
PageResultinstance.- Return type:
PageResult[OutputT]
- loom.core.repository.abc.decode_cursor(token, backend, model, *, key_count=None)[source]¶
Decode a token issued by
encode_cursor()forbackend.- Parameters:
- Returns:
The decoded
Cursor.- Raises:
UnsupportedQuery – If the token is undecodable, in a legacy format, was issued by another backend or does not match the sort.
- Return type:
- loom.core.repository.abc.encode_cursor(backend, keys, tie_breaker)[source]¶
Encode a cursor position into an opaque URL-safe token.
- Parameters:
- Returns:
base64url token that
decode_cursor()accepts forbackend.- Raises:
TypeError – If a key has a type the token format cannot carry.
- Return type: