InterfaceType and StructType: Advanced Type Features
Scenario: Multiple entities have "geographic location"
CoomiaPublished on August 10, 202516 min read
Share this articleTwitter / X
InterfaceType and StructType: Advanced Type Features
“Series: S4 Ontology Modeling · Article 6 | Level: Intermediate | Reading Time: 18 min
#TL;DR
- InterfaceType gives the Ontology object-oriented "interface inheritance" — multiple ObjectTypes can implement the same Interface, enabling polymorphic queries ("find all locatable objects" without caring whether they're equipment, warehouses, or vehicles).
- StructType is a lightweight "value object" — unlike ObjectType, which has independent identity and lifecycle, Structs are composite data structures embedded in properties, supporting multi-level nesting for addresses, coordinates, contact info, and similar scenarios.
- Interface inheritance + struct nesting + polymorphic queries work together to elevate the Ontology's expressiveness from simple "table-row-column" to type-safe domain modeling.
#1. Why InterfaceType Is Needed
#1.1 The Problem: How to Express Commonality Across Types?
Code
Scenario: Multiple entities have "geographic location"
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Equipment│ │ Warehouse│ │ Vehicle │ │ Employee │
│ │ │ │ │ │ │ │
│ lat: 31.2│ │ lat: 39.9│ │ lat: 22.3│ │ lat: 30.6│
│ lng: 121 │ │ lng: 116 │ │ lng: 114 │ │ lng: 104 │
│ address │ │ address │ │ address │ │ address │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
Problems:
├── How to query "all locatable objects within 10 km of me"?
├── Traditional: Query 4 tables separately → UNION ALL → client merges
├── If a new ObjectType (e.g., Sensor) is added, query logic must change
└── No way to express "these types share a common capability" at Schema level
Solution: InterfaceType
┌──────────────────────────────────┐
│ InterfaceType: Locatable │
│ │
│ properties: │
│ ├── latitude: DOUBLE │
│ ├── longitude: DOUBLE │
│ └── address: STRING │
│ │
│ implementedBy: │
│ ├── Equipment │
│ ├── Warehouse │
│ ├── Vehicle │
│ └── Employee │
└──────────────────────────────────┘
Now you can:
client.objects.search("Locatable", filters={"nearPoint": ...})
→ Auto-queries across all implementing types, returns mixed results
#1.2 InterfaceType vs Traditional Inheritance
Code
┌────────────────┬───────────────────────┬─────────────────────┐
│ │ Traditional OOP │ InterfaceType │
├────────────────┼───────────────────────┼─────────────────────┤
│ Multiple │ Usually unsupported/ │ ✅ One type can │
│ inheritance │ diamond problem │ implement many │
├────────────────┼───────────────────────┼─────────────────────┤
│ Data storage │ Usually mapped to │ Each ObjectType │
│ │ table inheritance │ stored independently│
│ │ (STI/MTI) │ no shared tables │
├────────────────┼───────────────────────┼─────────────────────┤
│ Query method │ Query parent table │ Polymorphic query │
│ │ │ auto-aggregates │
├────────────────┼───────────────────────┼─────────────────────┤
│ Runtime │ Tight coupling │ Loose coupling │
│ coupling │ │ Interface changes │
│ │ │ don't affect storage│
└────────────────┴───────────────────────┴─────────────────────┘
#2. InterfaceType Data Model
#2.1 Defining an Interface
Python
from ontology_sdk import OntologyClient
client = OntologyClient(base_url="http://localhost:8080")
# Create InterfaceType
interface = client.schema.create_interface_type({
"apiName": "Locatable",
"displayName": "Locatable",
"description": "Represents an entity with geographic location",
# Properties defined by the interface (implementors must have these)
"properties": {
"latitude": {
"type": "DOUBLE",
"required": True,
"description": "Latitude",
"validations": [
{"rule": "min", "value": -90},
{"rule": "max", "value": 90},
],
},
"longitude": {
"type": "DOUBLE",
"required": True,
"description": "Longitude",
"validations": [
{"rule": "min", "value": -180},
{"rule": "max", "value": 180},
],
},
"address": {
"type": "STRING",
"required": False,
"description": "Human-readable address",
},
},
# Actions defined by the interface (optional)
"actions": [
{
"apiName": "updateLocation",
"parameters": {
"newLatitude": {"type": "DOUBLE", "required": True},
"newLongitude": {"type": "DOUBLE", "required": True},
},
},
],
})
#2.2 ObjectType Implementing an Interface
Python
# Make Equipment implement the Locatable interface
client.schema.create_object_type({
"name": "Equipment",
"primaryKey": "equipmentId",
# Declare implemented interfaces
"implements": ["Locatable", "Auditable", "Maintainable"],
"properties": {
"equipmentId": {"type": "STRING", "required": True},
"name": {"type": "STRING", "required": True},
"model": {"type": "STRING"},
# Properties required by Locatable
"latitude": {"type": "DOUBLE", "required": True},
"longitude": {"type": "DOUBLE", "required": True},
"address": {"type": "STRING"},
# Properties required by Auditable
"createdAt": {"type": "TIMESTAMP", "required": True},
"updatedAt": {"type": "TIMESTAMP", "required": True},
"createdBy": {"type": "STRING", "required": True},
# Properties required by Maintainable
"lastMaintenanceDate": {"type": "DATE"},
"nextMaintenanceDate": {"type": "DATE"},
"maintenanceStatus": {"type": "ENUM", "enumValues": ["NORMAL", "DUE", "OVERDUE"]},
# Equipment's own properties
"serialNumber": {"type": "STRING"},
"purchaseDate": {"type": "DATE"},
"warrantyExpiry": {"type": "DATE"},
},
})
#2.3 Interface Compliance Checking
Python
# System automatically validates whether ObjectType satisfies Interface requirements
try:
client.schema.create_object_type({
"name": "Sensor",
"primaryKey": "sensorId",
"implements": ["Locatable"],
"properties": {
"sensorId": {"type": "STRING", "required": True},
"latitude": {"type": "DOUBLE", "required": True},
# Missing longitude!
},
})
except InterfaceComplianceError as e:
print(f"Interface compliance check failed: {e}")
# "ObjectType 'Sensor' does not satisfy interface 'Locatable':
# Missing required property: longitude (DOUBLE)"
print(f"Missing properties: {e.missing_properties}")
print(f"Type mismatches: {e.type_mismatches}")
#3. Polymorphic Queries
#3.1 Cross-Type Queries via Interface
Python
# Query all objects implementing the Locatable interface
# No need to know which specific ObjectTypes exist
results = client.objects.search_by_interface("Locatable", {
"filters": {
"nearPoint": {
"latitude": 31.23,
"longitude": 121.47,
"radiusKm": 10,
},
},
"orderBy": "distance",
"maxResults": 50,
})
for obj in results:
print(f"[{obj.object_type}] {obj.display_name}")
print(f" Location: ({obj.latitude}, {obj.longitude})")
print(f" Distance: {obj.distance_km:.1f} km")
# Example output:
# [Equipment] CNC-001 CNC Machine
# Location: (31.24, 121.48)
# Distance: 1.2 km
# [Warehouse] Pudong Warehouse
# Location: (31.22, 121.50)
# Distance: 2.8 km
# [Vehicle] Transport Truck SH-12345
# Location: (31.20, 121.45)
# Distance: 3.5 km
#3.2 How Polymorphic Query Execution Works
Code
Polymorphic query execution flow:
1. Resolve Interface
┌─────────────────┐
│ Locatable │
│ ├── Equipment │
│ ├── Warehouse │
│ ├── Vehicle │
│ └── Employee │
└─────────────────┘
2. Parallel query each implementing type (Fan-out)
┌─────────────┐
│ Equipment │──── Query with filters ──── Results[0..n]
│ Warehouse │──── Query with filters ──── Results[0..m]
│ Vehicle │──── Query with filters ──── Results[0..k]
│ Employee │──── Query with filters ──── Results[0..j]
└─────────────┘
3. Merge sort (Fan-in)
Results[0..n] ─┐
Results[0..m] ─┼── Merge Sort by distance ── Final Results
Results[0..k] ─┤
Results[0..j] ─┘
Performance characteristics:
├── Parallelism = number of implementing types (typically 3-10)
├── Response time ≈ slowest implementing type's query time
├── Result count = sum of all implementations (capped by maxResults)
└── Auto-optimization: skip query if an implementation can't possibly match filters
#3.3 Interface Inheritance
Python
# InterfaceType can also extend other InterfaceTypes
client.schema.create_interface_type({
"apiName": "TrackableAsset",
"displayName": "Trackable Asset",
# Extends Locatable (inherits location properties)
"extends": ["Locatable"],
# Additional properties
"properties": {
"assetTag": {
"type": "STRING",
"required": True,
"description": "Asset tag number",
},
"assetValue": {
"type": "DOUBLE",
"required": True,
"description": "Asset value",
},
"depreciationRate": {
"type": "DOUBLE",
"description": "Annual depreciation rate",
},
},
})
# Equipment satisfies both Locatable and TrackableAsset
# Querying TrackableAsset also finds Equipment
#4. StructType: Value Object Modeling
#4.1 Why StructType Is Needed
Code
Scenario: Modeling address information
Option A: Flat properties (Bad)
┌─────────────────────────────────┐
│ Employee │
│ ├── homeCountry: STRING │
│ ├── homeProvince: STRING │
│ ├── homeCity: STRING │
│ ├── homeStreet: STRING │
│ ├── homePostcode: STRING │
│ ├── workCountry: STRING │ ← Property explosion!
│ ├── workProvince: STRING │
│ ├── workCity: STRING │
│ ├── workStreet: STRING │
│ └── workPostcode: STRING │
└─────────────────────────────────┘
Option B: Independent ObjectType (Overkill)
┌──────────┐ 1:N ┌──────────┐
│ Employee │──────►│ Address │
└──────────┘ └──────────┘
├── Does address need its own ID? No
├── Does address need an independent lifecycle? No
├── Does address need to be referenced by other objects? No
└── Unnecessary relation management overhead
Option C: StructType (Just Right)
┌─────────────────────────────────┐
│ Employee │
│ ├── homeAddress: Address │ ← Embedded composite structure
│ └── workAddress: Address │
└─────────────────────────────────┘
┌─────────────────────────────────┐
│ StructType: Address │
│ ├── country: STRING │
│ ├── province: STRING │
│ ├── city: STRING │
│ ├── street: STRING │
│ └── postcode: STRING │
└─────────────────────────────────┘
#4.2 Defining StructType
Python
# Create StructType
client.schema.create_struct_type({
"apiName": "Address",
"displayName": "Address",
"description": "Represents a mailing address",
"properties": {
"country": {
"type": "STRING",
"required": True,
"defaultValue": "China",
},
"province": {"type": "STRING", "required": True},
"city": {"type": "STRING", "required": True},
"district": {"type": "STRING"},
"street": {"type": "STRING", "required": True},
"postcode": {
"type": "STRING",
"validations": [
{"rule": "pattern", "value": "^[0-9]{5,6}$", "message": "Invalid postal code format"},
],
},
"isDefault": {"type": "BOOLEAN", "defaultValue": "false"},
},
})
# Create GeoPoint StructType
client.schema.create_struct_type({
"apiName": "GeoPoint",
"displayName": "Geographic Point",
"properties": {
"latitude": {
"type": "DOUBLE",
"required": True,
"validations": [
{"rule": "min", "value": -90},
{"rule": "max", "value": 90},
],
},
"longitude": {
"type": "DOUBLE",
"required": True,
"validations": [
{"rule": "min", "value": -180},
{"rule": "max", "value": 180},
],
},
"altitude": {"type": "DOUBLE", "description": "Altitude (meters)"},
"accuracy": {"type": "DOUBLE", "description": "Accuracy (meters)"},
},
})
#4.3 Using StructType in ObjectType
Python
# Reference StructType in ObjectType properties
client.schema.create_object_type({
"name": "Employee",
"primaryKey": "employeeId",
"properties": {
"employeeId": {"type": "STRING", "required": True},
"name": {"type": "STRING", "required": True},
# Using StructType as property type
"homeAddress": {
"type": "STRUCT",
"structType": "Address",
"required": True,
},
"workAddress": {
"type": "STRUCT",
"structType": "Address",
},
# StructType array
"emergencyContacts": {
"type": "ARRAY",
"itemType": "STRUCT",
"structType": "ContactInfo",
"maxItems": 3,
},
},
})
# Create objects with embedded Struct values
employee = client.objects.create("Employee", {
"employeeId": "emp-001",
"name": "John Smith",
"homeAddress": {
"country": "USA",
"province": "California",
"city": "San Francisco",
"district": "SOMA",
"street": "123 Main St",
"postcode": "94105",
"isDefault": True,
},
"workAddress": {
"country": "USA",
"province": "California",
"city": "San Francisco",
"street": "456 Market St",
"postcode": "94107",
},
"emergencyContacts": [
{"name": "Jane Smith", "phone": "+1-555-0101", "relationship": "Spouse"},
{"name": "Bob Smith", "phone": "+1-555-0102", "relationship": "Parent"},
],
})
#4.4 Nested Queries
Python
# Query nested Struct fields
results = client.objects.search("Employee", {
"filters": {
"homeAddress.city": {"eq": "San Francisco"},
"homeAddress.district": {"eq": "SOMA"},
},
})
# Query fields within Struct arrays
results = client.objects.search("Employee", {
"filters": {
"emergencyContacts.relationship": {"eq": "Spouse"},
},
})
#5. Struct Nesting: Multi-Level Composite Structures
#5.1 Multi-Level Nesting Definition
Python
# Three-level nesting example: Order → Line Items → Price Breakdown
# Level 1: PriceBreakdown
client.schema.create_struct_type({
"apiName": "PriceBreakdown",
"properties": {
"basePrice": {"type": "DOUBLE", "required": True},
"discount": {"type": "DOUBLE", "defaultValue": "0"},
"discountReason": {"type": "STRING"},
"tax": {"type": "DOUBLE", "required": True},
"taxRate": {"type": "DOUBLE", "required": True},
"finalPrice": {"type": "DOUBLE", "required": True},
},
})
# Level 2: OrderLineItem (contains PriceBreakdown)
client.schema.create_struct_type({
"apiName": "OrderLineItem",
"properties": {
"productId": {"type": "STRING", "required": True},
"productName": {"type": "STRING", "required": True},
"quantity": {"type": "INTEGER", "required": True, "validations": [{"rule": "min", "value": 1}]},
"unit": {"type": "STRING", "defaultValue": "pcs"},
"pricing": {
"type": "STRUCT",
"structType": "PriceBreakdown", # Nested reference
"required": True,
},
"notes": {"type": "STRING"},
},
})
# Level 3: Used in Order ObjectType
client.schema.create_object_type({
"name": "Order",
"primaryKey": "orderId",
"properties": {
"orderId": {"type": "STRING", "required": True},
"customerId": {"type": "STRING", "required": True},
"lineItems": {
"type": "ARRAY",
"itemType": "STRUCT",
"structType": "OrderLineItem",
"minItems": 1,
"maxItems": 100,
},
"shippingAddress": {
"type": "STRUCT",
"structType": "Address",
},
"totalAmount": {"type": "DOUBLE"},
},
})
#5.2 Nesting Limits and Best Practices
Code
Nesting depth limits:
coomia-dip supports up to 5 levels of nesting:
ObjectType
└── Struct Level 1
└── Struct Level 2
└── Struct Level 3
└── Struct Level 4
└── Struct Level 5 (maximum depth)
Alternatives when exceeding 5 levels:
├── Split into independent ObjectType + RelationType
├── Re-evaluate whether the data model is overly complex
└── Consider using JSON type for semi-structured data
Best practices:
├── Keep nesting depth to 2-3 levels
├── Struct properties should not exceed 15 fields
├── Struct arrays should not exceed 50 elements
├── Create indexes for frequently queried nested fields
└── Avoid placing large text fields in Structs (impacts storage efficiency)
#6. InterfaceType + StructType Combined Usage
Python
# Combined example: Monitorable equipment
# StructType: Sensor Reading
client.schema.create_struct_type({
"apiName": "SensorReading",
"properties": {
"sensorId": {"type": "STRING", "required": True},
"value": {"type": "DOUBLE", "required": True},
"unit": {"type": "STRING", "required": True},
"timestamp": {"type": "TIMESTAMP", "required": True},
"quality": {"type": "ENUM", "enumValues": ["GOOD", "UNCERTAIN", "BAD"]},
},
})
# InterfaceType: Monitorable
client.schema.create_interface_type({
"apiName": "Monitorable",
"displayName": "Monitorable",
"properties": {
"healthStatus": {
"type": "ENUM",
"enumValues": ["HEALTHY", "WARNING", "CRITICAL", "UNKNOWN"],
"required": True,
},
"lastHeartbeat": {"type": "TIMESTAMP", "required": True},
"currentReadings": {
"type": "ARRAY",
"itemType": "STRUCT",
"structType": "SensorReading",
},
},
"actions": [
{"apiName": "resetHealth", "parameters": {}},
{"apiName": "acknowledgeAlert", "parameters": {
"alertId": {"type": "STRING", "required": True},
}},
],
})
# ObjectType using both InterfaceType and StructType
client.schema.create_object_type({
"name": "IndustrialRobot",
"primaryKey": "robotId",
"implements": ["Locatable", "Monitorable", "TrackableAsset"],
"properties": {
"robotId": {"type": "STRING", "required": True},
"name": {"type": "STRING", "required": True},
"model": {"type": "STRING"},
"manufacturer": {"type": "STRING"},
# From Locatable
"latitude": {"type": "DOUBLE", "required": True},
"longitude": {"type": "DOUBLE", "required": True},
"address": {"type": "STRING"},
# From Monitorable
"healthStatus": {"type": "ENUM", "enumValues": ["HEALTHY", "WARNING", "CRITICAL", "UNKNOWN"], "required": True},
"lastHeartbeat": {"type": "TIMESTAMP", "required": True},
"currentReadings": {
"type": "ARRAY",
"itemType": "STRUCT",
"structType": "SensorReading",
},
# From TrackableAsset
"assetTag": {"type": "STRING", "required": True},
"assetValue": {"type": "DOUBLE", "required": True},
"depreciationRate": {"type": "DOUBLE"},
# Own properties
"operatingHours": {"type": "DOUBLE"},
"jointConfiguration": {
"type": "STRUCT",
"structType": "RobotJointConfig",
},
},
})
#7. Type System Comparison: When to Use What
Code
┌─────────────────┬────────────────┬────────────────┬───────────────┐
│ Feature │ ObjectType │ InterfaceType │ StructType │
├─────────────────┼────────────────┼────────────────┼───────────────┤
│ Has identity(PK)│ ✅ Yes │ ❌ No │ ❌ No │
│ Exists alone │ ✅ Yes │ ❌ No │ ❌ No │
│ Can be ref'd │ ✅ Yes │ ❌ No │ ❌ No │
│ Has lifecycle │ ✅ DRAFT→... │ ✅ DRAFT→... │ ✅ DRAFT→... │
│ Independently │ ✅ Yes │ ✅ Polymorphic│ ❌ No │
│ queryable │ │ queries │ │
│ Can be nested │ ❌ No │ ❌ No │ ✅ Yes │
│ Storage │ Dedicated │ No storage │ Embedded in │
│ │ table/part │ │ host object │
│ Typical use │ Business │ Common │ Value │
│ │ entities │ abstractions │ objects │
└─────────────────┴────────────────┴────────────────┴───────────────┘
Decision tree:
Need to model a concept?
│
├── Does it have independent identity and lifecycle?
│ ├── Yes → ObjectType
│ └── No → Does it represent commonality across multiple types?
│ ├── Yes → InterfaceType
│ └── No → Is it a composite value?
│ ├── Yes → StructType
│ └── No → Simple property (STRING/DOUBLE/...)
#8. Protobuf Definitions
PROTOBUF
message InterfaceType {
string api_name = 1;
string display_name = 2;
string description = 3;
// Parent interfaces extended
repeated string extends = 4;
// Properties defined by the interface
map<string, PropertyDef> properties = 5;
// Actions defined by the interface
repeated ActionSignature actions = 6;
// ObjectTypes implementing this interface (auto-maintained)
repeated string implemented_by = 7;
LifecycleState lifecycle = 8;
}
message StructType {
string api_name = 1;
string display_name = 2;
string description = 3;
// Struct fields
map<string, PropertyDef> properties = 4;
// Types referencing this struct (auto-maintained)
repeated StructUsage usages = 5;
LifecycleState lifecycle = 6;
}
message StructUsage {
string object_type = 1;
string property_name = 2;
bool is_array = 3;
}
#9. Real-World Case: Smart Factory Type System
Python
# Complete smart factory type system design
# === StructTypes ===
# Maintenance Record
client.schema.create_struct_type({
"apiName": "MaintenanceRecord",
"properties": {
"date": {"type": "DATE", "required": True},
"technician": {"type": "STRING", "required": True},
"type": {"type": "ENUM", "enumValues": ["PREVENTIVE", "CORRECTIVE", "PREDICTIVE"]},
"description": {"type": "STRING", "required": True},
"duration_hours": {"type": "DOUBLE"},
"cost": {"type": "DOUBLE"},
"parts_replaced": {"type": "ARRAY", "itemType": "STRING"},
},
})
# Alert Rule
client.schema.create_struct_type({
"apiName": "AlertRule",
"properties": {
"metric": {"type": "STRING", "required": True},
"operator": {"type": "ENUM", "enumValues": ["GT", "LT", "EQ", "GTE", "LTE"]},
"threshold": {"type": "DOUBLE", "required": True},
"severity": {"type": "ENUM", "enumValues": ["INFO", "WARNING", "CRITICAL"]},
"cooldownMinutes": {"type": "INTEGER", "defaultValue": "15"},
},
})
# === InterfaceTypes ===
# Auditable
client.schema.create_interface_type({
"apiName": "Auditable",
"properties": {
"createdAt": {"type": "TIMESTAMP", "required": True},
"updatedAt": {"type": "TIMESTAMP", "required": True},
"createdBy": {"type": "STRING", "required": True},
"updatedBy": {"type": "STRING"},
},
})
# Maintainable
client.schema.create_interface_type({
"apiName": "Maintainable",
"extends": ["Auditable"],
"properties": {
"lastMaintenanceDate": {"type": "DATE"},
"nextMaintenanceDate": {"type": "DATE"},
"maintenanceHistory": {
"type": "ARRAY",
"itemType": "STRUCT",
"structType": "MaintenanceRecord",
},
"alertRules": {
"type": "ARRAY",
"itemType": "STRUCT",
"structType": "AlertRule",
},
},
"actions": [
{"apiName": "scheduleMaintenance", "parameters": {
"date": {"type": "DATE", "required": True},
"type": {"type": "STRING", "required": True},
}},
],
})
# === ObjectTypes ===
# CNC Machine
client.schema.create_object_type({
"name": "CNCMachine",
"primaryKey": "machineId",
"implements": ["Locatable", "Monitorable", "Maintainable", "TrackableAsset"],
"properties": {
"machineId": {"type": "STRING", "required": True},
"name": {"type": "STRING", "required": True},
# ... Locatable properties
"latitude": {"type": "DOUBLE", "required": True},
"longitude": {"type": "DOUBLE", "required": True},
"address": {"type": "STRING"},
# ... Monitorable properties
"healthStatus": {"type": "ENUM", "enumValues": ["HEALTHY", "WARNING", "CRITICAL", "UNKNOWN"], "required": True},
"lastHeartbeat": {"type": "TIMESTAMP", "required": True},
"currentReadings": {"type": "ARRAY", "itemType": "STRUCT", "structType": "SensorReading"},
# ... Maintainable properties (includes Auditable)
"createdAt": {"type": "TIMESTAMP", "required": True},
"updatedAt": {"type": "TIMESTAMP", "required": True},
"createdBy": {"type": "STRING", "required": True},
"updatedBy": {"type": "STRING"},
"lastMaintenanceDate": {"type": "DATE"},
"nextMaintenanceDate": {"type": "DATE"},
"maintenanceHistory": {"type": "ARRAY", "itemType": "STRUCT", "structType": "MaintenanceRecord"},
"alertRules": {"type": "ARRAY", "itemType": "STRUCT", "structType": "AlertRule"},
# ... TrackableAsset properties
"assetTag": {"type": "STRING", "required": True},
"assetValue": {"type": "DOUBLE", "required": True},
"depreciationRate": {"type": "DOUBLE"},
# CNC-specific properties
"spindleSpeed": {"type": "INTEGER", "description": "Spindle speed RPM"},
"axisCount": {"type": "INTEGER", "description": "Number of axes (3/4/5)"},
"maxWorkpieceSize": {"type": "STRUCT", "structType": "Dimensions3D"},
},
})
# Polymorphic query example
print("=== All Equipment Due for Maintenance ===")
overdue = client.objects.search_by_interface("Maintainable", {
"filters": {
"nextMaintenanceDate": {"lt": "2026-03-24"},
"healthStatus": {"in": ["WARNING", "CRITICAL"]},
},
"orderBy": "nextMaintenanceDate",
})
for item in overdue:
print(f"[{item.object_type}] {item.name}")
print(f" Next maintenance: {item.nextMaintenanceDate}")
print(f" Health status: {item.healthStatus}")
print(f" Maintenance history: {len(item.maintenanceHistory)} records")
#10. Version Evolution and Compatibility
Python
# InterfaceType version evolution
# Safe changes (backward compatible):
# ✅ Add optional properties
# ✅ Add new Actions
# ✅ Relax validation rules (e.g., increase max value)
# Breaking changes (require Schema Change process):
# ❌ Remove existing properties
# ❌ Add required properties (existing implementors may not satisfy)
# ❌ Change property types
# ❌ Tighten validation rules
# StructType version evolution follows the same principles
# Additional note: when StructType is referenced by multiple ObjectTypes,
# changes have a larger blast radius
#Key Takeaways
- InterfaceType enables Ontology-level polymorphism — a single query spans multiple ObjectTypes without hardcoding type lists, and new implementing types are automatically included in query scope.
- StructType is a property-level composite type — it avoids property explosion (flattening) and over-modeling (independent ObjectType), supporting up to 5 levels of nesting.
- An ObjectType can implement multiple Interfaces — similar to multiple inheritance but without the diamond problem, with each Interface's properties independent and conflict-free.
- The three type system elements work together: ObjectType (business entities) + InterfaceType (common abstractions) + StructType (value objects) = complete domain modeling capability.
- Interface compliance is automatically checked — when creating or modifying an ObjectType, the system validates whether all declared Interface requirements are satisfied.
#Next Article
The next article, S4-07 Derived Properties, will introduce how to let data "compute itself" — through 9 reducers, expression evaluation, and SQL-backed derived property mechanisms, achieving "define once, auto-update."
#ontology #interface-type #struct-type #polymorphic-query #type-system #inheritance #value-object