graflo.architecture.schema.edge_direction¶
What each backend can do with edge direction (a capability table, never raises).
Edge.directed and the declared inverses of EdgeConfig are statements
about the model. Backends express them to wildly different degrees, and the
difference matters mostly on the read path: reaching an edge from its target
endpoint is free on some backends, needs an explicit clause on others, and is a
schema-time decision that cannot be retrofitted on TigerGraph.
The table lives beside the schema, below every backend, so that schema-level
reasoning (which realization of a declared inverse suits a target, what an
undirected edge will cost) can consult it without importing a database driver.
:mod:graflo.db.edge_direction_support builds the read-path assertions and the
per-edge diagnostics on top of it.
Attributes¶
REVERSE_TRAVERSAL_COST = {DBType.ARANGO: ReverseTraversalCost.FREE, DBType.NEO4J: ReverseTraversalCost.CHEAP, DBType.MEMGRAPH: ReverseTraversalCost.CHEAP, DBType.FALKORDB: ReverseTraversalCost.CHEAP, DBType.NEBULA: ReverseTraversalCost.CLAUSE_REQUIRED, DBType.TIGERGRAPH: ReverseTraversalCost.SCHEMA_TIME_ONLY, DBType.POSTGRES: ReverseTraversalCost.FREE, DBType.GRAFLO_BACKEND: ReverseTraversalCost.MATERIALIZATION_REQUIRED}
module-attribute
¶
UNDIRECTED_NATIVE_DBS = frozenset({DBType.TIGERGRAPH})
module-attribute
¶
__all__ = ['REVERSE_TRAVERSAL_COST', 'UNDIRECTED_NATIVE_DBS', 'ReverseTraversalCost', 'coerce_db_type', 'db_type_label', 'default_direction_for_edge', 'reverse_traversal_cost', 'reversed_direction', 'supports_native_undirected']
module-attribute
¶
Classes¶
ReverseTraversalCost
¶
Bases: StrEnum
What it costs to reach an edge from its target endpoint.
Source code in graflo/architecture/schema/edge_direction.py
Attributes¶
CHEAP = 'cheap'
class-attribute
instance-attribute
¶
Relationships are stored bidirectionally; the reverse pattern is legal and fast.
CLAUSE_REQUIRED = 'clause_required'
class-attribute
instance-attribute
¶
Cheap once asked for, but only via an explicit reverse/bidirectional clause.
FREE = 'free'
class-attribute
instance-attribute
¶
Both endpoints are indexed; the reverse query is the same price.
INDEX_REQUIRED = 'index_required'
class-attribute
instance-attribute
¶
Needs a secondary index on the target column before it is affordable.
MATERIALIZATION_REQUIRED = 'materialization_required'
class-attribute
instance-attribute
¶
Direction is the storage partition key; the reverse view must be written out.
SCHEMA_TIME_ONLY = 'schema_time_only'
class-attribute
instance-attribute
¶
Decided at DDL time; no query rewrite can recover it afterwards.
Functions:¶
coerce_db_type(db_type)
¶
Accept the bare strings that reach these helpers from validated config.
Source code in graflo/architecture/schema/edge_direction.py
db_type_label(db_type)
¶
Printable backend name, whether db_type is the enum or a bare string.
Source code in graflo/architecture/schema/edge_direction.py
default_direction_for_edge(edge)
¶
The direction a read should follow for edge when none is requested.
This is where Edge.directed stops being an annotation and starts
steering queries: an undirected edge reads as :attr:EdgeDirection.ANY,
because both orientations denote the same relationship and anchoring on
source alone would drop half the neighbourhood.
Source code in graflo/architecture/schema/edge_direction.py
reverse_traversal_cost(db_type)
¶
What it costs to reach an edge from its target endpoint on db_type.
Raises:
| Type | Description |
|---|---|
KeyError
|
if |
Source code in graflo/architecture/schema/edge_direction.py
reversed_direction(direction)
¶
direction as seen from the other end of the edge.
Reading a relation through its declared inverse follows the stored edge from its target, so what the caller called outgoing is incoming in storage.
Source code in graflo/architecture/schema/edge_direction.py
supports_native_undirected(db_type)
¶
Whether the backend has an undirected edge type in its schema language.