Skip to content

Backref resolution

didactic.api.resolve_backrefs

resolve_backrefs(
    target: A,
    candidates: Iterable[B],
    *,
    via: str,
    key: str = "id",
) -> list[B]

Return the subset of candidates whose via field points at target.

Parameters:

Name Type Description Default
target A

The Model instance to find inbound references to.

required
candidates Iterable[B]

An iterable of Model instances that may contain the inverse Ref.

required
via str

The name of the field on each candidate that holds the Ref. Typically this is the field declared as Ref[type(target)].

required
key str

The attribute on target whose value the Ref stores. Defaults to "id", which matches didactic's conventional vertex identifier.

'id'

Returns:

Type Description
list

Every candidate c for which getattr(c, via) == getattr(target, key). The order matches the iteration order of candidates.

Raises:

Type Description
AttributeError

If target has no key attribute, or any candidate has no via attribute.

Examples:

>>> import didactic.api as dx
>>> class Author(dx.Model):
...     id: str
...     name: str
>>> class Book(dx.Model):
...     id: str
...     title: str
...     author: dx.Ref[Author]
>>> ada = Author(id="a1", name="Ada Lovelace")
>>> books = [
...     Book(id="b1", title="Note A", author="a1"),
...     Book(id="b2", title="Note B", author="a2"),
...     Book(id="b3", title="Note C", author="a1"),
... ]
>>> [b.id for b in dx.resolve_backrefs(ada, books, via="author")]
['b1', 'b3']

didactic.api.ModelPool

ModelPool(instances: Iterable[Model] | None = None)

An in-memory pool of Model instances, grouped by class.

Parameters:

Name Type Description Default
instances Iterable[Model] | None

Optional initial collection of Model instances. Each is registered under its concrete class.

None
Notes

The pool is a plain dict-of-lists keyed by class identity. It does not deduplicate, observe mutations, or check that ids are unique; it is a tiny convenience for collecting test fixtures and short-lived application state. For durable storage, use didactic.api.Repository.

Examples:

>>> import didactic.api as dx
>>> class Author(dx.Model):
...     id: str
>>> class Book(dx.Model):
...     id: str
...     author: dx.Ref[Author]
>>>
>>> pool = dx.ModelPool()
>>> ada = Author(id="a1")
>>> _ = pool.add(ada)
>>> _ = pool.add(Book(id="b1", author="a1"))
>>> _ = pool.add(Book(id="b2", author="a2"))
>>>
>>> [b.id for b in pool.backrefs(ada, Book, via="author")]
['b1']

add

add(instance: M) -> M

Register instance under its concrete class.

Parameters:

Name Type Description Default
instance M

A Model instance.

required

Returns:

Type Description
Model

instance itself, for fluent chaining.

all_of

all_of(cls: type[M]) -> list[M]

Return every instance registered under cls.

Parameters:

Name Type Description Default
cls type[M]

The Model class to look up.

required

Returns:

Type Description
list

Instances registered under exactly cls (subclass instances are stored under their own concrete class, not under cls). Order is registration order.

backrefs

backrefs(
    target: A,
    candidate_cls: type[B],
    *,
    via: str,
    key: str = "id",
) -> list[B]

Resolve backrefs to target from instances of candidate_cls.

Parameters:

Name Type Description Default
target A

The Model instance to find inbound references to.

required
candidate_cls type[B]

The Model class to scan for the inverse Ref.

required
via str

The name of the field on candidate_cls that holds the Ref.

required
key str

The attribute on target whose value the Ref stores. Defaults to "id".

'id'

Returns:

Type Description
list

All registered candidate_cls instances whose via field equals getattr(target, key).