How Apache Ossie Supports Composite Primary Keys with Multiple Columns
Apache Ossie treats primary keys as ordered arrays of column names, allowing datasets to define composite keys consisting of multiple columns while preserving order across relationships and conversions.
Apache Ossie is an open-source semantic modeling framework that enables data teams to define portable dataset schemas. Unlike systems that restrict primary keys to single columns, Ossie natively supports composite primary keys with multiple columns by representing them as ordered arrays in the core specification, Python runtime models, and vendor-specific converters.
Core Specification: Arrays Enable Composite Keys
In core-spec/spec.md, the primary_key field is defined as an optional array rather than a scalar string (lines 28-34). This architectural decision explicitly allows datasets to declare keys spanning multiple columns. The specification demonstrates this flexibility with concrete examples showing both a simple single-column key (primary_key: [customer_id]) and a composite key spanning multiple columns (primary_key: [order_id, line_number]) (lines 35-43).
Python Runtime Model
The Python implementation stores composite keys using the exact array structure defined in the specification. In python/src/ossie/models.py, the Dataset class declares primary_key as Optional[list[str]] (lines 153-158). This type annotation ensures that the runtime preserves the exact sequence of column names, maintaining the integrity of composite keys throughout the model's lifecycle.
Order Enforcement in Relationships
When datasets with composite keys participate in relationships, column order becomes critical. The Relationships definition in core-spec/spec.md mandates that the from_columns and to_columns arrays must follow matching order (lines 95-99). This constraint prevents ambiguity when joining tables on multiple columns, ensuring that the first column in the source composite key maps to the first column in the target composite key.
Converter Architecture
Ossie's converter layer propagates composite key structures across vendor-specific formats without losing the multi-column definition.
Omni Converter
The Omni converter explicitly preserves composite keys through dedicated metadata fields. In converters/omni/src/osi_omni/osi_to_omni.py, the converter extracts the primary key array and records it as custom_compound_primary_key_sql (lines 300-307). The reverse converter in omni_to_osi.py restores the composite key from this metadata (lines 313-371), ensuring round-trip fidelity even when translating between Ossie and Omni view definitions.
Orionbelt Converter
For legacy system migrations, converters/orionbelt/src/ossie_orionbelt/osi_to_obml.py promotes primary key information from older OBML representations into the first-class primary_key array (lines 65-73). This promotion supports both simple and composite key definitions during format translation.
Honeydew Converter
The Honeydew converter handles composite keys by emitting them as unique keys in the target format, ensuring that multi-column uniqueness constraints survive the conversion process in converters/honeydew/src/honeydew_osi/converter.py.
Practical Implementation Examples
Define a dataset with a composite primary key in your semantic model YAML:
datasets:
- name: order_lines
source: sales.public.order_lines
primary_key: [order_id, line_number] # ← composite key
fields: []
Inspect the primary key structure in Python:
from ossie.models import Dataset
# Assume `ds` is a Dataset loaded from a semantic model
print(ds.name) # → "order_lines"
print(ds.primary_key) # → ["order_id", "line_number"]
Create a relationship that correctly references the composite key:
relationships:
- name: order_lines_to_orders
from: order_lines
to: orders
from_columns: [order_id, line_number] # matches the composite PK order
to_columns: [order_id, line_number] # target also has a composite PK
Summary
- Ossie defines primary keys as ordered arrays in
core-spec/spec.md, enabling multi-column composite keys without artificial constraints. - The Python model stores keys as
Optional[list[str]]inpython/src/ossie/models.pyto preserve column sequences. - Relationship definitions enforce matching column order between
from_columnsandto_columnsarrays to prevent ambiguous joins. - Omni and Orionbelt converters maintain composite key integrity during format translations using explicit metadata preservation and promotion logic.
Frequently Asked Questions
How many columns can an Ossie composite primary key contain?
There is no artificial limit imposed by the specification. The array-based design in core-spec/spec.md allows you to define primary keys with two, three, or more columns as required by your data model, provided each column name exists within the dataset's field definitions.
Does the order of columns matter in composite primary keys?
Yes. Ossie treats the primary_key array as ordered. When referencing composite keys in relationships, the from_columns and to_columns arrays must list columns in the exact same sequence as defined in the respective primary keys, as mandated by the Relationships section of the core specification.
How do converters handle composite keys when the target platform uses a different representation?
Converters like the Omni implementation explicitly preserve composite key metadata using vendor-specific extensions such as custom_compound_primary_key_sql. This ensures the composite structure survives round-trip conversions even when the target format uses different native representations for multi-column keys.
What validation errors occur if column order is mismatched in a relationship?
The Ossie validator will reject the relationship definition because the specification requires that from_columns and to_columns arrays match in order and length. This prevents runtime join errors that would occur if the system attempted to join tables on mismatched composite key columns.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →