"""Machine and Asset relationship models.""" from shopdb.extensions import db from .base import BaseModel class RelationshipType(BaseModel): """ Types of relationships between assets. ADR-001 seeds three canonical types: partof, controls, connectedto. Sites may add legacy/communication-flavored types (Serial Cable, Direct Ethernet, USB, WiFi, Dualpath) for backward compatibility with pre-1.0 data, but new ADR-001 code paths only reason about the three canonical types via free-text label for nuance. """ __tablename__ = 'relationshiptypes' relationshiptypeid = db.Column(db.Integer, primary_key=True) relationshiptype = db.Column(db.String(50), unique=True, nullable=False) description = db.Column(db.Text) # Sibling propagation (ADR-001): when a relationship of this type is # created/deleted, the framework finds all assets related to the source # via the type at propagatesthroughid and mirrors the change. Null means # no propagation. Seeded values: # partof -> null (propagation rail itself) # controls -> partof (controls propagates across siblings) # connectedto -> null (network paths don't propagate) propagatesthroughid = db.Column( db.Integer, db.ForeignKey('relationshiptypes.relationshiptypeid'), nullable=True, comment='Sibling-propagation rail per ADR-001' ) propagatesthrough = db.relationship( 'RelationshipType', remote_side=[relationshiptypeid], foreign_keys=[propagatesthroughid], ) def __repr__(self): return f"" class AssetRelationship(BaseModel): """ Relationships between assets. Examples: - Computer controls Equipment - Two machines are dualpath partners - Network device connects to equipment """ __tablename__ = 'assetrelationships' relationshipid = db.Column(db.Integer, primary_key=True) sourceassetid = db.Column( db.Integer, db.ForeignKey('assets.assetid'), nullable=False ) targetassetid = db.Column( db.Integer, db.ForeignKey('assets.assetid'), nullable=False ) relationshiptypeid = db.Column( db.Integer, db.ForeignKey('relationshiptypes.relationshiptypeid'), nullable=False ) # Free-text description carrying domain nuance ("DNC feed", # "operator workstation", "ethernet PoE"). Avoids inflating type list. label = db.Column(db.String(200), comment='Free-text relationship description (ADR-001)') # When true, resolve_asset_position walks across this edge (priority 2 # in the resolution chain). Defaults to true for partof + controls when # the relationship is created via the API; nullable for legacy rows. inheritsposition = db.Column( db.Boolean, default=True, nullable=False, server_default='1', comment='If true, resolved-position walk follows this edge (ADR-001)' ) notes = db.Column(db.Text) sourceasset = db.relationship( 'Asset', foreign_keys=[sourceassetid], backref='outgoing_relationships' ) targetasset = db.relationship( 'Asset', foreign_keys=[targetassetid], backref='incoming_relationships' ) relationshiptype = db.relationship('RelationshipType', backref='asset_relationships') __table_args__ = ( db.UniqueConstraint( 'sourceassetid', 'targetassetid', 'relationshiptypeid', name='uq_asset_relationship' ), db.Index('idx_asset_rel_source', 'sourceassetid'), db.Index('idx_asset_rel_target', 'targetassetid'), ) def __repr__(self): return f" {self.targetassetid}>" class MachineRelationship(BaseModel): """ Relationships between machines. Examples: - PC controls CNC machine - Two CNCs are dualpath partners """ __tablename__ = 'machinerelationships' relationshipid = db.Column(db.Integer, primary_key=True) parentmachineid = db.Column( db.Integer, db.ForeignKey('machines.machineid'), nullable=False ) childmachineid = db.Column( db.Integer, db.ForeignKey('machines.machineid'), nullable=False ) relationshiptypeid = db.Column( db.Integer, db.ForeignKey('relationshiptypes.relationshiptypeid'), nullable=False ) notes = db.Column(db.Text) # Relationships parent_machine = db.relationship( 'Machine', foreign_keys=[parentmachineid], backref='child_relationships' ) child_machine = db.relationship( 'Machine', foreign_keys=[childmachineid], backref='parent_relationships' ) relationship_type = db.relationship('RelationshipType', backref='relationships') __table_args__ = ( db.UniqueConstraint( 'parentmachineid', 'childmachineid', 'relationshiptypeid', name='uq_machine_relationship' ), ) def __repr__(self): return f" {self.childmachineid}>"