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

CardinalityDescriptionExample
ONE_TO_ONEOne source to one targetPerson HAS_PASSPORT Passport
ONE_TO_MANYOne source to many targetsAuthor WROTE Books
MANY_TO_ONEMany sources to one targetEmployees WORKS_AT Company
MANY_TO_MANYMany 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

CodeDescription
REQUIRED_FIELDRequired field missing
INVALID_TYPEWrong value type
MIN_VALUEValue below minimum
MAX_VALUEValue above maximum
MIN_LENGTHString too short
MAX_LENGTHString too long
PATTERN_MISMATCHRegex pattern failed
INVALID_EMAILInvalid email format
INVALID_ENUMValue not in allowed list
REF_NOT_FOUNDReferenced node missing
SELF_LOOPSelf-referential edge
DUPLICATE_EDGEDuplicate edge exists
CARDINALITY_VIOLATIONCardinality constraint violated
CYCLE_DETECTEDCycle in acyclic constraint
NOT_CONNECTEDGraph not connected
ORPHAN_NODENode has no edges