Domain Rules¶
Domain rules describe expected OMOP concept domains for specific fields on OMOP tables or views.
They are represented explicitly using the DomainRule model.
These expectations are not enforced by the database and are often not enforced by ETL pipelines — which is precisely why they need to be documented and validated explicitly.
Declaring expected domains¶
DomainRule
Immutable specification of an expected OMOP domain constraint.
A DomainRule describes the semantic expectation that a given concept ID field on a table or view should reference concepts from one or more OMOP domains.
Domain rules are derived from model declarations and are intended for inspection, documentation, and validation workflows. They do not enforce behavior or mutate data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
table
|
str
|
Name of the OMOP table or view the rule applies to. |
required |
field
|
str
|
Name of the concept ID field being constrained. |
required |
allowed_domains
|
FrozenSet[str]
|
Set of OMOP domains that are considered valid. |
required |
allowed_classes
|
Optional[set[str]]
|
Optional restriction to specific concept classes. |
None
|
Why rules are generated, not authored¶
OMOP Alchemy does not encourage manually writing domain rules.
Instead, rules are derived from model declarations to ensure:
- rules stay co-located with semantic intent
- documentation cannot drift from code
- tooling can introspect expectations automatically
Domain rules are collected from View classes that declare their expectations explicitly.
The ExpectedDomain Model¶
ExpectedDomain
Declares one or more expected OMOP domains for a concept field.
ExpectedDomain is used on View classes to express semantic intent.
Examples:
>>> ExpectedDomain("Gender").domains
frozenset({'Gender'})
>>> ExpectedDomain("Race", "Ethnicity").domains
frozenset({'Race', 'Ethnicity'})
Use on View Classes¶
Expected domains are declared on View classes using
__expected_domains__.
DomainValidationMixin
Adds lightweight runtime domain validation to OMOP View classes.
This mixin enables best-effort semantic checks that verify whether referenced concept IDs belong to expected OMOP domains.
Validation is advisory:
- no exceptions are raised
- no data is mutated
- detached objects are handled safely
Intended for View classes only.
Examples:
Specification on a View:
>>> class PersonView(Person, DomainValidationMixin):
>>> __expected_domains__ = {
>>> "gender_concept_id": ExpectedDomain("Gender"),
>>> "race_concept_id": ExpectedDomain("Race"),
>>> "ethnicity_concept_id": ExpectedDomain("Ethnicity"),
>>> }
Runtime usage:
>>> p = session.get(PersonView, 123)
>>> p.is_domain_valid
True
Violations can be inspected without raising exceptions:
>>> p.domain_violations
["gender_concept_id not in domain(s): ['Gender']"]
domain_violations
property
¶
domain_violations: list[str]
Human-readable descriptions of domain violations on this object.
is_domain_valid
property
¶
is_domain_valid: bool
Whether this object satisfies all declared domain expectations.
collect_domain_rules
classmethod
¶
collect_domain_rules() -> list[DomainRule]
Collect declared domain expectations as canonical DomainRule objects.
Returns:
| Type | Description |
|---|---|
list[DomainRule]
|
Domain rules derived from |
Collecting rules programmatically¶
Declared rules can be collected into canonical DomainRule objects:
PersonView.collect_domain_rules()
Which yields:
[
DomainRule(
table="person",
field="gender_concept_id",
allowed_domains={"Gender"},
),
DomainRule(
table="person",
field="race_concept_id",
allowed_domains={"Race"},
),
]
This allows domain rules to be:
- documented
- audited
- exported
- validated across the model layer
What domain rules are not¶
Domain rules intentionally do not:
- enforce ETL behavior
- mutate data
- raise hard exceptions
- assume any execution environment
They exist to make semantic expectations visible and checkable — not to constrain ingestion workflows.