Type Enum Usage Guide
Version: 1.0
Date: 2025-11-14
Phase: 3.5 - Documentation and Benchmarks
Overview
This guide explains how to use dynamically generated type enums for entity and relation types. Type enums provide type safety, IDE autocomplete, and compile-time validation while maintaining backward compatibility with string literals.
Generating Type Enums
Basic Usage
Generate enums from your schema:
from aiecs.domain.knowledge_graph.schema.schema_manager import SchemaManager
# Load schema
schema_manager = SchemaManager.load_from_file("schema.json")
# Generate enums
enums = schema_manager.generate_enums()
# Access entity type enums
PersonEnum = enums["entity_types"]["Person"]
PaperEnum = enums["entity_types"]["Paper"]
CompanyEnum = enums["entity_types"]["Company"]
# Access relation type enums
WorksForEnum = enums["relation_types"]["WORKS_FOR"]
AuthoredByEnum = enums["relation_types"]["AUTHORED_BY"]
Enum Structure
Generated enums have the following structure:
# Entity type enum
PersonEnum.PERSON # "Person"
PersonEnum.PERSON.value # "Person"
PersonEnum.PERSON.name # "PERSON"
# Relation type enum
WorksForEnum.WORKS_FOR # "WORKS_FOR"
WorksForEnum.WORKS_FOR.value # "WORKS_FOR"
WorksForEnum.WORKS_FOR.name # "WORKS_FOR"
Using Type Enums
In Queries
Use enums in query construction:
from aiecs.domain.knowledge_graph.models.query import GraphQuery
# Generate enums
enums = schema_manager.generate_enums()
PersonEnum = enums["entity_types"]["Person"]
# Use enum in query
query = GraphQuery(
entity_type=PersonEnum.PERSON, # Type-safe!
max_results=100
)
# Backward compatible - still works as string
assert str(PersonEnum.PERSON) == "Person"
assert PersonEnum.PERSON == "Person"
In Function Signatures
Use enums for type hints:
from typing import Union
from aiecs.domain.knowledge_graph.schema.type_enums import EntityTypeEnum
def get_entities(
entity_type: Union[str, EntityTypeEnum],
max_results: int = 100
) -> List[Entity]:
"""
Get entities by type
Args:
entity_type: Entity type (string or enum)
max_results: Maximum number of results
Returns:
List of entities
"""
# Convert to string (works for both)
type_str = str(entity_type)
return graph_store.get_entities_by_type(type_str, max_results)
# Use with enum
PersonEnum = enums["entity_types"]["Person"]
entities = get_entities(PersonEnum.PERSON)
# Still works with string
entities = get_entities("Person")
In Validation
Use enums for validation:
def validate_entity_type(entity_type: str) -> bool:
"""Validate entity type exists in schema"""
enums = schema_manager.generate_enums()
valid_types = enums["entity_types"].keys()
return entity_type in valid_types
# Validate
if validate_entity_type("Person"):
print("Valid entity type")
else:
print("Invalid entity type")
In Pattern Matching
Use enums in pattern matching:
from aiecs.domain.knowledge_graph.models.path_pattern import PathPattern
# Generate enums
enums = schema_manager.generate_enums()
PersonEnum = enums["entity_types"]["Person"]
WorksForEnum = enums["relation_types"]["WORKS_FOR"]
# Use in pattern
pattern = PathPattern(
entity_types=[PersonEnum.PERSON], # Type-safe
relation_types=[WorksForEnum.WORKS_FOR],
max_depth=2
)
Backward Compatibility
String Compatibility
Enums are fully backward compatible with strings:
PersonEnum = enums["entity_types"]["Person"]
# String conversion
assert str(PersonEnum.PERSON) == "Person"
# String comparison
assert PersonEnum.PERSON == "Person"
# String formatting
print(f"Entity type: {PersonEnum.PERSON}") # "Entity type: Person"
# In dictionaries
type_map = {"person": PersonEnum.PERSON}
assert type_map["person"] == "Person"
Existing Code
Existing code using strings continues to work:
# Old code (still works)
query = GraphQuery(
entity_type="Person", # String literal
max_results=100
)
# New code (type-safe)
PersonEnum = enums["entity_types"]["Person"]
query = GraphQuery(
entity_type=PersonEnum.PERSON, # Enum
max_results=100
)
# Both produce the same result
Benefits of Type Enums
1. Type Safety
Catch errors at compile time:
# With enum - IDE catches typo
PersonEnum.PERSN # AttributeError at compile time
# With string - error at runtime
entity_type = "Persn" # Typo not caught until runtime
2. IDE Autocomplete
Get autocomplete suggestions:
# Type "PersonEnum." and IDE shows:
# - PERSON
# - value
# - name
# Type "enums['entity_types'][" and IDE shows all entity types
3. Refactoring Support
Rename types safely:
# If you rename "Person" to "Individual" in schema:
# - Enum automatically updates
# - IDE finds all usages
# - Refactoring is safe
# With strings:
# - Must find/replace manually
# - Easy to miss occurrences
# - Risky refactoring
4. Documentation
Self-documenting code:
# Clear what types are expected
def process_person(person_type: PersonEnum):
"""Process person (type is clear from signature)"""
pass
# Less clear with strings
def process_person(person_type: str):
"""Process person (what strings are valid?)"""
pass
Advanced Usage
Iterating Over Enums
Iterate over all enum members:
PersonEnum = enums["entity_types"]["Person"]
# Iterate over members
for member in PersonEnum:
print(f"{member.name} = {member.value}")
# Output:
# PERSON = Person
Enum Comparison
Compare enums:
PersonEnum = enums["entity_types"]["Person"]
PaperEnum = enums["entity_types"]["Paper"]
# Compare enum members
assert PersonEnum.PERSON != PaperEnum.PAPER
# Compare with strings
assert PersonEnum.PERSON == "Person"
assert PaperEnum.PAPER == "Paper"
Dynamic Enum Access
Access enums dynamically:
# Get enum by name
entity_type_name = "Person"
EntityEnum = enums["entity_types"][entity_type_name]
# Get enum member
enum_member = EntityEnum.PERSON
# Or use getattr
enum_member = getattr(EntityEnum, "PERSON")
Best Practices
1. Generate Enums Once
Generate enums once at startup:
# At application startup
schema_manager = SchemaManager.load_from_file("schema.json")
TYPE_ENUMS = schema_manager.generate_enums()
# Use throughout application
def get_person_entities():
PersonEnum = TYPE_ENUMS["entity_types"]["Person"]
return get_entities(PersonEnum.PERSON)
2. Use Type Hints
Add type hints for better IDE support:
from typing import Union
from aiecs.domain.knowledge_graph.schema.type_enums import EntityTypeEnum
def get_entities(
entity_type: Union[str, EntityTypeEnum]
) -> List[Entity]:
"""Get entities (accepts string or enum)"""
return graph_store.get_entities_by_type(str(entity_type))
3. Prefer Enums in New Code
Use enums in new code for type safety:
# New code - use enums
PersonEnum = TYPE_ENUMS["entity_types"]["Person"]
query = GraphQuery(entity_type=PersonEnum.PERSON)
# Old code - keep strings for backward compatibility
query = GraphQuery(entity_type="Person")
4. Document Enum Usage
Document when enums are expected:
def create_entity(
entity_type: Union[str, EntityTypeEnum],
properties: Dict[str, Any]
) -> Entity:
"""
Create entity
Args:
entity_type: Entity type (string or enum)
Use TYPE_ENUMS["entity_types"]["Person"].PERSON for type safety
properties: Entity properties
Returns:
Created entity
"""
pass
Migration Guide
Migrating Existing Code
Gradually migrate to enums:
# Step 1: Generate enums
TYPE_ENUMS = schema_manager.generate_enums()
# Step 2: Update function signatures (optional)
def get_entities(
entity_type: Union[str, EntityTypeEnum] # Accept both
) -> List[Entity]:
return graph_store.get_entities_by_type(str(entity_type))
# Step 3: Update call sites (gradually)
# Old
entities = get_entities("Person")
# New
PersonEnum = TYPE_ENUMS["entity_types"]["Person"]
entities = get_entities(PersonEnum.PERSON)
No Breaking Changes
Migration is optional - strings still work:
# All of these work:
query1 = GraphQuery(entity_type="Person") # String
query2 = GraphQuery(entity_type=PersonEnum.PERSON) # Enum
query3 = GraphQuery(entity_type=str(PersonEnum.PERSON)) # Explicit conversion
# All produce the same result
Conclusion
Type enums provide type safety and better developer experience while maintaining full backward compatibility. Use them in new code for better IDE support and compile-time validation.