Skip to main content

Why Use Model Inheritance?

When your system has related data types—different kinds of alerts, equipment, or events—you often repeat the same fields across multiple models. Model inheritance lets you define common fields once in a base model, then extend it with specialized fields for each variant.
Like a family tree for data. A “TemperatureAlert” is a child of “Alert”—it inherits all the standard alert properties (ID, timestamp, severity) but adds its own temperature-specific fields. Change the parent, and all children get the update.

When to Use Inheritance

ScenarioExample
Alert systemsBase alert + temperature, pressure, maintenance alerts
Equipment monitoringBase equipment + pumps, conveyors, motors
Event trackingBase event + production, quality, safety events
Sensor networksBase sensor + temperature, pressure, flow sensors

In This Page

  • Inheritance Syntax — The FROM keyword and how it works
  • Base Models — Designing reusable parent models
  • Specialized Models — Adding type-specific fields
  • Publishing Inherited Models — Using inherited models in Actions
  • Complete Examples — Real-world inheritance patterns

Inheritance Syntax

The FROM keyword creates a child model that inherits all fields from a parent:
DEFINE MODEL ChildModel FROM ParentModel
    ADD STRING "specialized_field"
    ADD DOUBLE "another_field"
The child model automatically includes every field from the parent, plus any additional fields you define.

How It Works

// Parent model with common fields
DEFINE MODEL BaseAlert COLLAPSED
    ADD STRING "alert_id"
    ADD STRING "timestamp"
    ADD STRING "severity"
    ADD STRING "message"
    ADD BOOL "acknowledged"

// Child model inherits all parent fields + adds specialized ones
DEFINE MODEL TemperatureAlert FROM BaseAlert
    ADD DOUBLE "temperature_value"
    ADD DOUBLE "threshold_exceeded"
    ADD STRING "sensor_location"
Result: TemperatureAlert has 8 fields total:
  • 5 inherited from BaseAlert (alert_id, timestamp, severity, message, acknowledged)
  • 3 specialized fields (temperature_value, threshold_exceeded, sensor_location)
Base models are typically defined with COLLAPSED since they’re meant to be extended, not used directly. The child models inherit this behavior.

Designing Base Models

A good base model contains fields that every variant needs. Put yourself in the position of someone processing alerts, equipment data, or events—what fields do they always expect?

Base Model Best Practices

DEFINE MODEL BaseEquipment COLLAPSED
    // Identification - always needed
    ADD STRING "equipment_id"
    ADD STRING "equipment_name"
    
    // Context - helps locate and categorize
    ADD STRING "location"
    ADD STRING "status"
    
    // Operational data - common across equipment
    ADD INT "runtime_hours"
    ADD STRING "last_maintenance"
    
    // Metadata - for tracking and auditing
    ADD STRING "operator"
    ADD STRING "timestamp"
Don’t include type-specific fields in base models. If only some variants need a field, it belongs in the child model.

What to Include in Base Models

Field CategoryExamplesWhy
Identifiersid, name, codeEvery record needs to be identifiable
Timestampstimestamp, created_atEssential for ordering and debugging
Statusstatus, severity, stateCommon across most data types
Contextlocation, source, operatorHelps downstream processing
Flagsacknowledged, processedCommon workflow states

Creating Specialized Models

Child models add fields specific to their domain. Keep these focused—only add what that particular variant needs.

Alert Family Example

Starting from a common base, create specialized alert types:
DEFINE MODEL BaseAlert COLLAPSED
    ADD STRING "alert_id"
    ADD STRING "source_system"
    ADD STRING "timestamp"
    ADD STRING "severity"
    ADD STRING "message"
    ADD BOOL "acknowledged"
Temperature alerts add measurement data and thresholds:
DEFINE MODEL TemperatureAlert FROM BaseAlert
    ADD DOUBLE "temperature_value"
    ADD DOUBLE "threshold_exceeded"
    ADD STRING "sensor_location"
    ADD STRING "unit"

Publishing Inherited Models

Inherited models work exactly like regular COLLAPSED models—use PUBLISH MODEL from an Action and provide values for all fields (inherited + specialized):
DEFINE ACTION GenerateTemperatureAlert
ON TOPIC "sensors/temperature/+/alert" DO
    SET "sensor_id" WITH TOPIC POSITION 3
    
    PUBLISH MODEL TemperatureAlert TO "alerts/temperature/" + {sensor_id} WITH
        // Inherited fields from BaseAlert
        alert_id = (RANDOM UUID)
        source_system = "TemperatureMonitor"
        timestamp = TIMESTAMP "UTC"
        severity = "HIGH"
        message = "Temperature threshold exceeded"
        acknowledged = FALSE
        
        // Specialized fields for TemperatureAlert
        temperature_value = (GET JSON "value" IN PAYLOAD AS DOUBLE)
        threshold_exceeded = (GET JSON "threshold" IN PAYLOAD AS DOUBLE)
        sensor_location = (GET JSON "location" IN PAYLOAD AS STRING)
        unit = "celsius"

Polymorphic Action Pattern

One Action can handle multiple model types by checking the incoming data and publishing the appropriate variant:
DEFINE ACTION PolymorphicAlertGenerator
ON TOPIC "sensors/+/+/alert" DO
    SET "sensor_type" WITH TOPIC POSITION 2
    SET "sensor_id" WITH TOPIC POSITION 3
    
    IF {sensor_type} EQUALS "temperature" THEN
        PUBLISH MODEL TemperatureAlert TO "alerts/temperature/" + {sensor_id} WITH
            alert_id = (RANDOM UUID)
            source_system = "SensorNetwork"
            timestamp = TIMESTAMP "UTC"
            severity = (GET JSON "severity" IN PAYLOAD AS STRING)
            message = "Temperature alert triggered"
            acknowledged = FALSE
            temperature_value = (GET JSON "value" IN PAYLOAD AS DOUBLE)
            threshold_exceeded = (GET JSON "threshold" IN PAYLOAD AS DOUBLE)
            sensor_location = (GET JSON "location" IN PAYLOAD AS STRING)
            unit = "celsius"
    
    ELSE IF {sensor_type} EQUALS "pressure" THEN
        PUBLISH MODEL PressureAlert TO "alerts/pressure/" + {sensor_id} WITH
            alert_id = (RANDOM UUID)
            source_system = "SensorNetwork"
            timestamp = TIMESTAMP "UTC"
            severity = (GET JSON "severity" IN PAYLOAD AS STRING)
            message = "Pressure alert triggered"
            acknowledged = FALSE
            pressure_value = (GET JSON "value" IN PAYLOAD AS DOUBLE)
            max_safe_pressure = (GET JSON "max_pressure" IN PAYLOAD AS DOUBLE)
            pressure_unit = "PSI"
            system_affected = (GET JSON "system" IN PAYLOAD AS STRING)
All alert types share the same base structure, so downstream systems can process common fields (like severity and acknowledged) without knowing the specific alert type.

Complete Examples

A complete equipment monitoring system with specialized equipment types:
// Base model with common equipment fields
DEFINE MODEL BaseEquipment COLLAPSED
    ADD STRING "equipment_id"
    ADD STRING "equipment_name"
    ADD STRING "location"
    ADD STRING "status"
    ADD INT "runtime_hours"
    ADD STRING "last_maintenance"
    ADD STRING "operator"
    ADD STRING "timestamp"

// Pump-specific model
DEFINE MODEL PumpEquipment FROM BaseEquipment
    ADD DOUBLE "flow_rate"
    ADD DOUBLE "pressure_output"
    ADD INT "rpm"
    ADD DOUBLE "power_consumption"
    ADD STRING "pump_type"

// Conveyor-specific model
DEFINE MODEL ConveyorEquipment FROM BaseEquipment
    ADD DOUBLE "belt_speed"
    ADD INT "items_per_minute"
    ADD DOUBLE "belt_tension"
    ADD BOOL "emergency_stop_active"
    ADD STRING "direction"
Action to publish equipment reports:
DEFINE ACTION EquipmentReporter
ON TOPIC "equipment/+/+/status_update" DO
    SET "equipment_type" WITH TOPIC POSITION 2
    SET "equipment_id" WITH TOPIC POSITION 3
    
    IF {equipment_type} EQUALS "pump" THEN
        PUBLISH MODEL PumpEquipment TO "equipment/reports/pump/" + {equipment_id} WITH
            equipment_id = {equipment_id}
            equipment_name = (GET JSON "name" IN PAYLOAD AS STRING)
            location = (GET JSON "location" IN PAYLOAD AS STRING)
            status = (GET JSON "status" IN PAYLOAD AS STRING)
            runtime_hours = (GET JSON "runtime" IN PAYLOAD AS INT)
            last_maintenance = (GET JSON "last_service" IN PAYLOAD AS STRING)
            operator = (GET JSON "operator" IN PAYLOAD AS STRING)
            timestamp = TIMESTAMP "UTC"
            flow_rate = (GET JSON "flow_rate" IN PAYLOAD AS DOUBLE)
            pressure_output = (GET JSON "pressure" IN PAYLOAD AS DOUBLE)
            rpm = (GET JSON "rpm" IN PAYLOAD AS INT)
            power_consumption = (GET JSON "power" IN PAYLOAD AS DOUBLE)
            pump_type = "Centrifugal"
    
    ELSE IF {equipment_type} EQUALS "conveyor" THEN
        PUBLISH MODEL ConveyorEquipment TO "equipment/reports/conveyor/" + {equipment_id} WITH
            equipment_id = {equipment_id}
            equipment_name = (GET JSON "name" IN PAYLOAD AS STRING)
            location = (GET JSON "location" IN PAYLOAD AS STRING)
            status = (GET JSON "status" IN PAYLOAD AS STRING)
            runtime_hours = (GET JSON "runtime" IN PAYLOAD AS INT)
            last_maintenance = (GET JSON "last_service" IN PAYLOAD AS STRING)
            operator = (GET JSON "operator" IN PAYLOAD AS STRING)
            timestamp = TIMESTAMP "UTC"
            belt_speed = (GET JSON "speed" IN PAYLOAD AS DOUBLE)
            items_per_minute = (GET JSON "throughput" IN PAYLOAD AS INT)
            belt_tension = (GET JSON "tension" IN PAYLOAD AS DOUBLE)
            emergency_stop_active = (GET JSON "estop" IN PAYLOAD AS BOOL)
            direction = (GET JSON "direction" IN PAYLOAD AS STRING)

Best Practices

Only include fields that every child model needs. If only some variants use a field, it belongs in the child model, not the base.
// Good - base has universal fields only
DEFINE MODEL BaseAlert COLLAPSED
    ADD STRING "alert_id"
    ADD STRING "timestamp"
    ADD STRING "severity"

// Bad - 'temperature_unit' doesn't apply to all alerts
DEFINE MODEL BaseAlert COLLAPSED
    ADD STRING "alert_id"
    ADD STRING "timestamp"
    ADD STRING "severity"
    ADD STRING "temperature_unit"  // Too specific!
Name child models to clearly indicate their specialization:
// Good - clear inheritance relationship
DEFINE MODEL TemperatureAlert FROM BaseAlert
DEFINE MODEL PressureAlert FROM BaseAlert

// Bad - unclear relationship
DEFINE MODEL TempData FROM BaseAlert
DEFINE MODEL PressData FROM BaseAlert
When you have multiple inheritance levels, keep the structure clear:
BaseEntity
└── BaseEquipment
    ├── PumpEquipment
    ├── ConveyorEquipment
    └── MotorEquipment
When using PUBLISH MODEL, you must provide values for both inherited and specialized fields:
PUBLISH MODEL TemperatureAlert TO "alerts/temp" WITH
    // Don't forget inherited fields!
    alert_id = (RANDOM UUID)
    timestamp = TIMESTAMP "UTC"
    severity = "HIGH"
    
    // Plus specialized fields
    temperature_value = 85.5
    threshold_exceeded = 80.0

Limitations

Current limitations of model inheritance:
  • Single inheritance only — A model can only inherit from one parent (no multiple inheritance)
  • No field override — Child models cannot redefine fields from the parent with different types
  • COLLAPSED required — Base models should use COLLAPSED since they’re templates, not triggered models

Next Steps