Adding Walkers
=begin rakudoc
Overview
Walkers define how a Qwiratry query is executed against a data model.
Use this extension point when the new thing changes how data is traversed: trees, tables, graphs, logic databases, document stores, or any structure whose query execution rules need a custom traversal model.
If the data is still an ordinary tree for query purposes and only the node object shape is new, add a Tree Navigator instead. A navigator teaches the generic tree walker how to find children, parents, and attributes. A walker changes traversal or query execution semantics.
To add support for a new walker:
1. Setup: choose the data model, supported query shapes, and advertised capabilities.
2. Walker: implement
Qwiratry::Walkerfor the data model.3. Plan: implement
Qwiratry::Walker::Planfor reusable execution state.4. Iterator: return a
QueryIteratorthat outputs matching elements lazily.5. Discovery/Handover: add metadata and capabilities if the walker should be selected automatically.
6. Testing: test planning, iteration, unsupported queries, and strategy integration.
Setup
Decide what data model the walker supports and which query operators it can interpret. Define the capability metadata that tells Qwiratry and extenders what the walker can do.
Before adding a walker for a tree-shaped model, check whether a
Qwiratry::Tree::Navigator::Base is enough. Custom XML nodes, compiler
AST nodes, or other document-like objects usually need a navigator unless they
also need non-standard traversal or query planning.
If the walker should be discovered automatically, decide what domain metadata
callers will attach through Qwiratry::Walker::Providing.
Walker
Required Walker Shape
A concrete walker does Qwiratry::Walker and implements at least plan and
iterator.
use Qwiratry::Walker;
use Qwiratry::QueryIterator;
class MyWalker does Qwiratry::Walker {
method plan(Mu $query, Mu:D $root --> Qwiratry::Walker::Plan) {
MyPlan.new(:$query, :$root)
}
method iterator(Qwiratry::Walker::Plan $plan --> QueryIterator) {
$plan.iterator
}
}
Plan
Required Plan Shape
A plan does Qwiratry::Walker::Plan and provides an iterator, the original
query, and a human-readable description.
class MyPlan does Qwiratry::Walker::Plan {
has Mu $.query;
has Mu $.root;
method iterator(--> QueryIterator) {
MyIterator.new(:plan(self))
}
method query(--> Mu) {
$!query
}
method describe(--> Str) {
"MyPlan"
}
}
Iterator
The plan's iterator method should return a QueryIterator. The iterator is
responsible for outputting results lazily and keeping traversal state isolated
from other iterators created from the same plan.
Use a context object that does Qwiratry::Context::Context when traversal needs
mutable state or strategy integration.
Discovery/Handover
Use Qwiratry::Walker::Providing and capabilities when a walker should be
selected automatically or when a master walker should hand part of a query to
another domain.
Qwiratry::Walker::Providing.instance.bind-domains($data, <tree>);
Testing
Add tests that prove:
The walker creates a plan for supported query shapes.
The plan returns an independent iterator each time.
The iterator outputs expected matches lazily.
Unsupported query elements throw
X::Qwiratry::UnknownQueryElement.Discovery metadata selects the walker when expected.
Strategies receive hook calls during traversal.
Reference Material
Main Types
Qwiratry::Walker
Role implemented by concrete walkers. A walker turns a query and a root value into a reusable plan, then turns that plan into an iterator.
Qwiratry::Walker::Plan
Role implemented by execution plans. Plans store the query, root, and any precomputed strategy needed to produce iterators.
Qwiratry::QueryIterator::QueryIterator
Role for lazy result streams produced by walker plans.
Qwiratry::Context::Context
Role for per-traversal mutable state shared by walkers, iterators, and strategies.
Qwiratry::QueryMatch::QueryMatch
Match object used when a strategy is told that an element matched a query.
Qwiratry::Walker::Capabilities
Shared capability metadata for walkers and plans.
Qwiratry::Walker::Factory
Discovery service for choosing a walker for data.
Qwiratry::Walker::Providing
Registry for domain and schema metadata used by walker discovery and handover.
Errors
X::Qwiratry::Walker
Base exception for walker-related failures.
X::Qwiratry::UnknownQueryElement
Throw when the walker cannot interpret a query element.
X::Qwiratry::NoWalkerFound
Thrown when discovery cannot find a suitable walker.
=end rakudoc