DDS, records and containers¶
DataDefinitionSystem defines schema. It has no per-class data until you create
a builder. Properties hold semantic name, Python value type, default and storage
name. Generated record constructors use the storage spelling and validate types.
Generated records are plain slotted Python classes with __dds_record_spec__.
# Definition API: explicit semantic and storage spelling
name = dds.property("FieldName", str, storage_name="field_name")
The tutorial's FieldRow(field_name="x", ...) populates that storage spelling;
matchers and contribution declarations use FieldName. Unknown constructor
keywords and wrong typed values are input errors. Union/family collections accept
concrete variant records; instantiate a concrete variant, not the union itself.
Collection and port contracts¶
| Surface | Contract |
|---|---|
single |
At most one record in the collection |
many |
Multiple records, still subject to declared identity |
| Identity | Scalar property or tuple; strict add rejects duplicates |
| Computed collection | Filtered view of existing source records; no new storage |
view.sequence() |
Collection/view sequence |
view.one() |
One record or None when empty; multiple records reject |
view.by_identity(key) |
Identity-based read; missing key returns None |
contains(...) |
Identity-key existence query, including computed-view filter |
ordered_records(...) |
Declared property order, then collection write order |
| Port cardinality | Number of children at one address, not collection size |
children_at(address) |
Ordered children configured by target/order properties |
The builder supports add and explicit write(..., policy=...). AddIfAbsent
keeps an existing identity; replacement deliberately changes it; strict insertion
rejects accidental duplicates. Confirm exact policy class exports in your SDK
rather than using a string tag. Frozen data views cannot write or lazily derive
new records. A record may participate in several computed views without copying.
Keyed lookup example¶
This canonical fixture demonstrates tuple identities and a data production that
reads one key's TxIndex, rather than enumerating a Cartesian product:
Source authority: tests/data/gold_src/dds_composite_identity_lookup.py.
from __future__ import annotations
from support.golden_case import run_case
from yidl.generation.data_def_sys import AddIfAbsent
from yidl.generation.data_def_sys import DataDefinitionSystem
from yidl.generation.data_def_sys import REQUIRED
from yidl.generation.data_def_sys import emit_container_runtime_source
from yidl.generation.data_def_sys import lookup
from yidl.generation.data_def_sys import read
def _build_dds() -> DataDefinitionSystem:
dds = DataDefinitionSystem()
name = dds.property("Name", str, default=REQUIRED, storage_name="name")
tx_key = dds.property("TxKey", str, default=REQUIRED, storage_name="tx_key")
phase = dds.property("Phase", str, default=REQUIRED, storage_name="phase")
tx_index = dds.property("TxIndex", int, default=REQUIRED, storage_name="tx_index")
order = dds.property("Order", int, default=0, storage_name="order")
tx_key_record = dds.record("TxKeyRecord", tx_key, phase, tx_index)
field = dds.record("Field", name, tx_key, phase, order)
contribution = dds.record("Contribution", tx_index, name, order)
tx_keys = dds.collection(
"TxKeys",
tx_key_record,
cardinality=dds.many,
identity=(tx_key, phase),
)
fields = dds.collection("Fields", field, cardinality=dds.many, identity=name)
contributions = dds.collection(
"Contributions",
contribution,
cardinality=dds.many,
identity=(tx_index, name),
)
production = dds.production(
"FieldProvidesContribution",
source=fields,
target=contributions,
values={
tx_index: lookup(
tx_keys,
key=(read(tx_key), read(phase)),
value=tx_index,
),
name: read(name),
order: read(order),
},
policy=AddIfAbsent,
)
dds.production_group("FieldChildren", production)
return dds
def render_case() -> str:
return emit_container_runtime_source(_build_dds())
def validate_case(source: str) -> None:
namespace = {}
exec(source, namespace)
builder = namespace["new_builder"]()
tx_key_record = namespace["TxKeyRecord"]
field = namespace["Field"]
tx_keys = namespace["TxKeysCollection"]
fields = namespace["FieldsCollection"]
contributions = namespace["ContributionsCollection"]
builder.add(tx_keys, tx_key_record(tx_key="main", phase="commit", tx_index=0))
builder.add(tx_keys, tx_key_record(tx_key="aux", phase="commit", tx_index=1))
builder.add(fields, field(name="owner", tx_key="main", phase="commit", order=2))
builder.add(fields, field(name="memo", tx_key="aux", phase="commit", order=1))
container = namespace["build_container"](builder)
assert container.TxKeys.by_identity(("main", "commit")).tx_index == 0
assert container.TxKeys.by_identity(("aux", "commit")).tx_index == 1
assert container.Contributions.by_identity((0, "owner")).order == 2
assert container.Contributions.by_identity((1, "memo")).order == 1
assert [record.name for record in container.Contributions.sequence()] == [
"owner",
"memo",
]
assert "identity=(_TxKeyProperty, _PhaseProperty)" in source
assert "identity=(_TxIndexProperty, _NameProperty)" in source
assert "lookup_0_key = (source.tx_key, source.phase)" in source
assert "builder.by_identity(TxKeysCollection, lookup_0_key)" in source
assert "dds.collection(" not in source
assert "dds.production(" not in source
if __name__ == "__main__":
raise SystemExit(
run_case("dds_composite_identity_lookup.py", render_case, validate_case)
)
Missing-key behavior can be explicitly supplied by the production lookup
expression's default argument; absent a usable key/default, preserve its lookup
diagnostic. It is not the same as an unmatched rule returning no generated value.
For operation and matcher snapshot timing see fact production.