graflo.hq.endpoint_resolve¶
Resolve edge endpoints declared by a secondary identity.
An edge-only source references its endpoints by an alternate key. Before the edge can be written, that key has to be mapped back to the vertex's primary identity — which is what every backend's edge write already expects.
Doing the mapping here rather than pushing the predicate into each backend's
edge query keeps one semantic across all of them, and is the only approach that
works for backends addressing endpoints by key (PostgreSQL foreign keys,
NebulaGraph VIDs, TigerGraph PRIMARY_ID).
Attributes¶
logger = logging.getLogger(__name__)
module-attribute
¶
Classes¶
AmbiguousEndpointError
¶
AttachStats
dataclass
¶
What happened while attaching records of one class to existing vertices.
An attached record never creates a vertex, so a record whose key finds none is counted and not written.
Source code in graflo/hq/endpoint_resolve.py
Attributes¶
ambiguous = 0
class-attribute
instance-attribute
¶
Records whose key matched more than one vertex.
attached = 0
class-attribute
instance-attribute
¶
Records written onto at least one vertex.
documents = 0
class-attribute
instance-attribute
¶
unmatched = 0
class-attribute
instance-attribute
¶
Records whose key matched no vertex.
unresolvable = 0
class-attribute
instance-attribute
¶
Records whose key was absent or incomplete, so no lookup was possible.
written = 0
class-attribute
instance-attribute
¶
Rows upserted, one per vertex written onto: above attached when
fanning out, below it when several records land on one vertex.
Methods:¶
__init__(documents=0, attached=0, unmatched=0, unresolvable=0, ambiguous=0, written=0)
¶
has_findings()
¶
merge(other)
¶
Add other's counts to these.
Source code in graflo/hq/endpoint_resolve.py
EndpointResolutionStats
dataclass
¶
What happened while resolving one edge batch.
Unmatched and ambiguous endpoints are ordinary data conditions rather than failures, so they are counted and reported instead of raising.
Source code in graflo/hq/endpoint_resolve.py
Attributes¶
ambiguous = 0
class-attribute
instance-attribute
¶
Documents whose key matched more than one vertex.
documents = 0
class-attribute
instance-attribute
¶
dropped = 0
class-attribute
instance-attribute
¶
Documents that produced no edge.
endpoints = field(default_factory=list)
class-attribute
instance-attribute
¶
unmatched = 0
class-attribute
instance-attribute
¶
Documents whose key matched no vertex.
unresolvable = 0
class-attribute
instance-attribute
¶
Documents whose key was absent or incomplete, so no lookup was possible.
written = 0
class-attribute
instance-attribute
¶
Edge documents produced, which exceeds documents when fanning out.
Methods:¶
__init__(documents=0, unresolvable=0, unmatched=0, ambiguous=0, dropped=0, written=0, endpoints=list())
¶
has_findings()
¶
merge(other)
¶
Add other's counts to these.
Source code in graflo/hq/endpoint_resolve.py
summary()
¶
Source code in graflo/hq/endpoint_resolve.py
WriteStats
dataclass
¶
Resolution counts accumulated by one writer over a run.
Safe to add to from the worker threads concurrent writes run on.
Source code in graflo/hq/endpoint_resolve.py
Attributes¶
attached = field(default_factory=dict)
class-attribute
instance-attribute
¶
By vertex class.
endpoints = field(default_factory=dict)
class-attribute
instance-attribute
¶
By edge, for edges whose endpoints were resolved by a secondary identity.
Methods:¶
__init__(attached=dict(), endpoints=dict(), _lock=threading.Lock())
¶
add_attached(vertex, stats)
¶
add_endpoints(edge_id, stats)
¶
is_empty()
¶
summary()
¶
One line per attached class and per resolved edge.
Source code in graflo/hq/endpoint_resolve.py
Functions:¶
resolve_edge_endpoints(db, docs, *, source_class, target_class, source_match_fields, target_match_fields, source_identity_fields, target_identity_fields, resolve_source, resolve_target, policy, guard=None)
¶
Rewrite endpoint projections from secondary keys to primary identities.
Only the endpoints flagged for resolution are looked up; the other side is passed through untouched, which is what makes asymmetric selection work.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
docs
|
list[Any]
|
|
required |
resolve_source
|
bool
|
True when the source endpoint uses a secondary identity |
required |
resolve_target
|
bool
|
Same, for the target endpoint |
required |
policy
|
EndpointAmbiguityPolicy
|
What to do when a key matches several vertices |
required |
guard
|
FilterExpression | None
|
A trusted read guard every match must pass, so an endpoint is never resolved to a vertex the guard hides; refused by a backend without read guards. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
tuple |
tuple[list[Any], EndpointResolutionStats]
|
rewritten edge documents, and what happened while resolving. |
Raises:
| Type | Description |
|---|---|
AmbiguousEndpointError
|
on multiple matches under the |
Source code in graflo/hq/endpoint_resolve.py
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | |
select_matches(found, *, policy, identity_fields, describe)
¶
The vertices a key's matches resolve to under policy.
Several matches are kept (all), reduced to the lowest primary identity
(first), dropped (skip) or refused (error); a single match is
always kept. Callers check for a partial key before looking it up.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
found
|
list[dict[str, Any]]
|
Every vertex the key matched, carrying identity_fields |
required |
policy
|
EndpointAmbiguityPolicy
|
What to do when there are several matches |
required |
identity_fields
|
Sequence[str]
|
Primary identity fields to project the matches onto |
required |
describe
|
Callable[[int], str]
|
Given the match count, the sentence naming what matched,
for the |
required |
Returns:
| Name | Type | Description |
|---|---|---|
list |
list[dict[str, Any]]
|
The selected matches, projected onto identity_fields. |
Raises:
| Type | Description |
|---|---|
AmbiguousEndpointError
|
on several matches under the |