Installation
# Python (included in ison-graph)
pip install ison-graph
# TypeScript (included in ison-graph-ts)
npm install ison-graph-ts
# Rust (included in ison-graph-rs)
cargo add ison-graph-rs
Quick Example
from ison_graph.schema import (
GraphSchema, NodeType, EdgeType,
StringField, IntField, Cardinality
)
# Define node types
Person = NodeType('person') \
.id(IntField()) \
.field('name', StringField().required().max(100)) \
.field('age', IntField().min(0).max(150)) \
.field('email', StringField().email())
Company = NodeType('company') \
.id(IntField()) \
.field('name', StringField().required()) \
.field('employees', IntField().min(1))
# Define edge types
Knows = EdgeType('KNOWS') \
.from_node(Person) \
.to_node(Person) \
.field('since', IntField()) \
.no_self_loop() \
.unique()
WorksAt = EdgeType('WORKS_AT') \
.from_node(Person) \
.to_node(Company) \
.field('role', StringField()) \
.cardinality(Cardinality.MANY_TO_ONE)
# Create schema
schema = GraphSchema('social') \
.node_types(Person, Company) \
.edge_types(Knows, WorksAt) \
.no_orphans()
# Validate a graph
result = schema.validate(graph)
if result.valid:
print("Graph is valid!")
else:
for error in result.errors:
print(f"{error.code}: {error.message}")
StringField
Validates string properties.
StringField()
.required() # Must be present
.min(1) # Minimum length
.max(100) # Maximum length
.pattern(r'\w+') # Regex pattern
.email() # Email format
.enum('a', 'b', 'c') # Allowed values
IntField
Validates integer properties.
IntField()
.required() # Must be present
.min(0) # Minimum value
.max(100) # Maximum value
.range(0, 100) # Min and max together
FloatField
Validates floating-point properties.
FloatField()
.required()
.min(0.0)
.max(1.0)
.range(0.0, 100.0)
BoolField
Validates boolean properties.
BoolField()
.required()
.default(True)
RefField
Validates references to other nodes.
RefField('person') # Reference to person nodes
.required()
.to('company') # Alternative syntax
NodeType
Define a node type schema.
Person = NodeType('person')
.id(IntField()) # ID field type
.field('name', StringField().required()) # Add property
.field('age', IntField().min(0))
.constraint(lambda n: n['age'] < 150) # Custom validation
EdgeType
Define an edge type schema with constraints.
Knows = EdgeType('KNOWS')
.from_node(Person) # Source node type
.to_node(Person) # Target node type
.field('since', IntField())
.no_self_loop() # Disallow A -> A
.unique() # No duplicate edges
.acyclic() # Enforce DAG
.bidirectional() # Require symmetric edges
.cardinality(Cardinality.ONE_TO_MANY)
.constraint(lambda e: e['since'] > 1900)
Cardinality
| Cardinality | Description | Example |
|---|---|---|
ONE_TO_ONE | One source to one target | Person HAS_PASSPORT Passport |
ONE_TO_MANY | One source to many targets | Author WROTE Books |
MANY_TO_ONE | Many sources to one target | Employees WORKS_AT Company |
MANY_TO_MANY | Many to many (default) | Users LIKES Products |
GraphSchema
Combine node and edge types with graph-level constraints.
schema = GraphSchema('my_graph')
.node_types(Person, Company, Product)
.edge_types(Knows, WorksAt, Purchased)
.connected() # All nodes reachable
.no_orphans() # All nodes have edges
.max_depth(10) # Maximum path length
.constraint(fn) # Custom graph constraint
Validation Result
result = schema.validate(graph)
# Check if valid
if result.valid:
print("All good!")
else:
# Access errors
for error in result.errors:
print(f"Code: {error.code}")
print(f"Message: {error.message}")
print(f"Path: {error.path}")
print(f"Value: {error.value}")
Error Codes
| Code | Description |
|---|---|
REQUIRED_FIELD | Required field missing |
INVALID_TYPE | Wrong value type |
MIN_VALUE | Value below minimum |
MAX_VALUE | Value above maximum |
MIN_LENGTH | String too short |
MAX_LENGTH | String too long |
PATTERN_MISMATCH | Regex pattern failed |
INVALID_EMAIL | Invalid email format |
INVALID_ENUM | Value not in allowed list |
REF_NOT_FOUND | Referenced node missing |
SELF_LOOP | Self-referential edge |
DUPLICATE_EDGE | Duplicate edge exists |
CARDINALITY_VIOLATION | Cardinality constraint violated |
CYCLE_DETECTED | Cycle in acyclic constraint |
NOT_CONNECTED | Graph not connected |
ORPHAN_NODE | Node has no edges |