CINXE.COM
IPLD ♦ Specs: Selectors
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="/css/layout.css?1741648188062"> <link rel="stylesheet" href="/css/nav.css?1741648188062"> <link rel="stylesheet" href="/css/style.css?1741648188062"> <link rel="stylesheet" href="/css/prismjs@1.24-themes-prism.css"> <title>IPLD ♦ Specs: Selectors</title> </head> <body> <header> <div class="sidebar-button" onclick="document.getElementById('sidebar').classList.toggle('sidebar-open')"> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"> <path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path> </svg> </div> <a href="/" class="logo">IPLD</a> <aside id=breadcrumbs> <ul> <li><a href="/specs">specs</a></li> <li><a href="/specs/selectors/">selectors</a></li> </ul> </aside> </header> <aside id=sidebar> <nav> <ul> <li> <a href="/docs/">Docs</a><ul> <li> <a href="/docs/intro/">Intro</a><ul> <li> <a href="/docs/intro/hello-world/">Hello, World</a></li> <li> <a href="/docs/intro/primer/">The Brief Primer</a></li> <li> <a href="/docs/intro/ecosystem/">InterPlanetary Ecosystem Overview</a></li> <li> <a href="/docs/intro/community/">Finding Community</a></li></ul></li> <li> <a href="/docs/motivation/">Motivation</a><ul> <li> <a href="/docs/motivation/benefits-of-content-addressing/">Benefits of Content Addressing</a></li> <li> <a href="/docs/motivation/data-to-data-structures/">From Data to Data Structures</a></li></ul></li> <li> <a href="/docs/codecs/">Codecs</a><ul> <li> <a href="/docs/codecs/known/">Known Codecs</a><ul> <li> <a href="/docs/codecs/known/dag-cbor/">DAG-CBOR</a></li> <li> <a href="/docs/codecs/known/dag-json/">DAG-JSON</a></li> <li> <a href="/docs/codecs/known/dag-pb/">DAG-PB</a></li></ul></li></ul></li> <li> <a href="/docs/data-model/">Data Model</a><ul> <li> <a href="/docs/data-model/node/">Nodes</a></li> <li> <a href="/docs/data-model/kinds/">Kinds</a></li> <li> <a href="/docs/data-model/pathing/">Pathing</a></li> <li> <a href="/docs/data-model/traversal/">Traversal</a></li></ul></li> <li> <a href="/docs/advanced-data-layouts/">Advanced Data Layouts</a><ul> <li> <a href="/docs/advanced-data-layouts/intro/">Intro to ADLs</a></li> <li> <a href="/docs/advanced-data-layouts/naming/">ADL Naming</a></li> <li> <a href="/docs/advanced-data-layouts/signalling/">Signalling ADLs</a></li> <li> <a href="/docs/advanced-data-layouts/dynamic-loading/">Dynamic Loading</a></li> <li> <a href="/docs/advanced-data-layouts/known/">Known ADLs</a></li></ul></li> <li> <a href="/docs/schemas/">Schemas</a><ul> <li> <a href="/docs/schemas/intro/">Introduction</a><ul> <li> <a href="/docs/schemas/intro/compare/">compare</a></li> <li> <a href="/docs/schemas/intro/goals/">Goals</a></li> <li> <a href="/docs/schemas/intro/feature-summary/">Feature Summary</a></li></ul></li> <li> <a href="/docs/schemas/features/">Features</a><ul> <li> <a href="/docs/schemas/features/typekinds/">Type Kinds</a></li> <li> <a href="/docs/schemas/features/representation-strategies/">Representation Strategies</a></li> <li> <a href="/docs/schemas/features/links/">Links</a></li> <li> <a href="/docs/schemas/features/indicating-adls/">Using ADLs in Schemas</a></li></ul></li> <li> <a href="/docs/schemas/using/">Using Wisely</a><ul> <li> <a href="/docs/schemas/using/authoring-guide/">Authoring Guide</a></li> <li> <a href="/docs/schemas/using/migrations/">Migrations</a></li></ul></li></ul></li> <li> <a href="/docs/synthesis/">Synthesis</a><ul> <li> <a href="/docs/synthesis/gtd/">Getting Things Done</a></li> <li> <a href="/docs/synthesis/building-in-alignment/">Building in Alignment</a></li> <li> <a href="/docs/synthesis/how-ipfs-web-gateways-work/">How IPFS Web Gateways Work</a></li> <li> <a href="/docs/synthesis/encryption/">Working With Encryption</a></li></ul></li></ul></li> <li> <a href="/specs/">Specs</a><ul> <li> <a href="/specs/about/">About the Specifications</a></li> <li> <a href="/specs/codecs/">Codecs</a><ul> <li> <a href="/specs/codecs/dag-cbor/">DAG-CBOR</a><ul> <li> <a href="/specs/codecs/dag-cbor/spec/">Spec</a></li> <li> <a href="/specs/codecs/dag-cbor/fixtures/">DAG-CBOR Test Fixtures</a><ul> <li> <a href="/specs/codecs/dag-cbor/fixtures/cross-codec/">cross-codec</a></li></ul></li></ul></li> <li> <a href="/specs/codecs/dag-cosmos/">DAG-COSMOS</a><ul> <li> <a href="/specs/codecs/dag-cosmos/basic_types/">basic_types</a></li> <li> <a href="/specs/codecs/dag-cosmos/cosmos_state/">cosmos_state</a></li> <li> <a href="/specs/codecs/dag-cosmos/crypto_types/">crypto_types</a></li> <li> <a href="/specs/codecs/dag-cosmos/tendermint_chain/">tendermint_chain</a></li> <li> <a href="/specs/codecs/dag-cosmos/typed_protobuf/">typed_protobuf</a></li></ul></li> <li> <a href="/specs/codecs/dag-eth/">DAG-ETH</a><ul> <li> <a href="/specs/codecs/dag-eth/basic_types/">basic_types</a></li> <li> <a href="/specs/codecs/dag-eth/chain/">chain</a></li> <li> <a href="/specs/codecs/dag-eth/convenience_types/">convenience_types</a></li> <li> <a href="/specs/codecs/dag-eth/state/">state</a></li></ul></li> <li> <a href="/specs/codecs/dag-jose/">DAG-JOSE</a><ul> <li> <a href="/specs/codecs/dag-jose/spec/">Spec</a></li> <li> <a href="/specs/codecs/dag-jose/fixtures/">fixtures</a></li></ul></li> <li> <a href="/specs/codecs/dag-json/">DAG-JSON</a><ul> <li> <a href="/specs/codecs/dag-json/spec/">Spec</a></li> <li> <a href="/specs/codecs/dag-json/fixtures/">DAG-JSON Test Fixtures</a><ul> <li> <a href="/specs/codecs/dag-json/fixtures/cross-codec/">cross-codec</a></li></ul></li></ul></li> <li> <a href="/specs/codecs/dag-pb/">DAG-PB</a><ul> <li> <a href="/specs/codecs/dag-pb/spec/">Spec</a></li> <li> <a href="/specs/codecs/dag-pb/fixtures/">DAG-PB Test Fixtures</a><ul> <li> <a href="/specs/codecs/dag-pb/fixtures/cross-codec/">cross-codec</a></li></ul></li></ul></li></ul></li> <li> <a href="/specs/advanced-data-layouts/">Advanced Data Layouts</a><ul> <li> <a href="/specs/advanced-data-layouts/fbl/">FBL ADL</a><ul> <li> <a href="/specs/advanced-data-layouts/fbl/spec/">spec</a></li></ul></li> <li> <a href="/specs/advanced-data-layouts/hamt/">HAMT ADL</a><ul> <li> <a href="/specs/advanced-data-layouts/hamt/spec/">spec</a></li> <li> <a href="/specs/advanced-data-layouts/hamt/fixture/">HashMap (HAMT) Test Fixtures</a><ul> <li> <a href="/specs/advanced-data-layouts/hamt/fixture/alice-words/">alice-words</a></li></ul></li></ul></li></ul></li> <li> <a href="/specs/schemas/">Schemas</a><ul> <li> <a href="/specs/schemas/prelude/">prelude</a></li></ul></li> <li> <a href="/specs/transport/">Transports</a><ul> <li> <a href="/specs/transport/car/">CAR</a><ul> <li> <a href="/specs/transport/car/carv1/">CARv1 Specification</a></li> <li> <a href="/specs/transport/car/carv2/">CARv2 Specification</a></li> <li> <a href="/specs/transport/car/fixture/">CAR Test Fixtures</a><ul> <li> <a href="/specs/transport/car/fixture/carv1-basic/">carv1-basic</a></li> <li> <a href="/specs/transport/car/fixture/carv2-basic/">carv2-basic</a></li></ul></li></ul></li> <li> <a href="/specs/transport/graphsync/">Graphsync</a><ul> <li> <a href="/specs/transport/graphsync/known_extensions/">known_extensions</a></li></ul></li> <li> <a href="/specs/transport/trustless-pathing/">Trustless Pathing</a><ul> <li> <a href="/specs/transport/trustless-pathing/fixtures/">Trustless Pathing Fixtures</a><ul> <li> <a href="/specs/transport/trustless-pathing/fixtures/unixfs_20m_variety/">unixfs_20m_variety</a></li></ul></li></ul></li></ul></li> <li class="active-page"> <a href="/specs/selectors/">Selectors</a><ul> <li> <a href="/specs/selectors/fixtures/">fixtures</a><ul> <li> <a href="/specs/selectors/fixtures/selector-fixtures-1/">selector-fixtures-1</a></li> <li> <a href="/specs/selectors/fixtures/selector-fixtures-adl/">selector-fixtures-adl</a></li> <li> <a href="/specs/selectors/fixtures/selector-fixtures-recursion/">selector-fixtures-recursion</a></li></ul></li></ul></li> <li> <a href="/specs/patch/">Patch</a><ul> <li> <a href="/specs/patch/fixtures/">IPLD Patch Test Fixtures</a><ul> <li> <a href="/specs/patch/fixtures/fixtures-1/">fixtures-1</a></li></ul></li></ul></li></ul></li> <li> <a href="/libraries/">Libraries</a><ul> <li> <a href="/libraries/golang/">Golang</a></li> <li> <a href="/libraries/java/">Java</a></li> <li> <a href="/libraries/javascript/">JavaScript</a></li> <li> <a href="/libraries/python/">Python</a></li> <li> <a href="/libraries/rust/">Rust</a></li></ul></li> <li> <a href="/design/">Design</a><ul> <li> <a href="/design/objectives/">Objectives</a></li> <li> <a href="/design/concepts/">Concepts</a><ul> <li> <a href="/design/concepts/type-theory-glossary/">type-theory-glossary</a></li></ul></li> <li> <a href="/design/libraries/">Libraries</a><ul> <li> <a href="/design/libraries/nodes-and-kinds/">nodes-and-kinds</a></li></ul></li> <li> <a href="/design/tricky-choices/">Tricky Choices</a><ul> <li> <a href="/design/tricky-choices/dag-pb-forms-impl-and-use/">dag-pb-forms-impl-and-use</a></li> <li> <a href="/design/tricky-choices/map-key-domain/">map-key-domain</a></li> <li> <a href="/design/tricky-choices/numeric-domain/">numeric-domain</a></li> <li> <a href="/design/tricky-choices/ordering/">ordering</a></li> <li> <a href="/design/tricky-choices/string-domain/">string-domain</a></li></ul></li> <li> <a href="/design/open-research/">Open Research</a><ul> <li> <a href="/design/open-research/ADL-autoexecution/">ADL autoexecution</a></li></ul></li></ul></li> <li> <a href="/tools/">Tools</a></li> <li> <a href="/glossary/">Glossary</a></li> <li> <a href="/media/">Media</a></li> <li> <a href="/FAQ/">FAQ</a></li></ul> </nav> </aside> <main> <div class=content> <h1>Selectors</h1> <h2 id="introduction" tabindex="-1"><a class="header-anchor" href="#introduction">Introduction</a></h2> <h3 id="what-are-selectors" tabindex="-1"><a class="header-anchor" href="#what-are-selectors">What are Selectors?</a></h3> <div class="callout callout-info"> <p>You'll want to read up on the <a href="/docs/data-model/">IPLD Data Model</a> first, before learning about Selectors.</p> </div> <p>IPLD Selectors are expressions that describe a traversal over an IPLD dag, and mark ("select") a subset of nodes during that walk.</p> <p>You can think of Selectors as roughly like regexps for textual data, but made for IPLD graphs.</p> <p>This is a useful primitive to use along with: (a) systems that require distributing or pinning dags (IPFS, Filecoin, bitswap, graphsync, ipfs-cluster) (b) applications that require fetching subsets of data in specific orders or at specific times (video players, dataset viewers, file systems), (c) programs that transform graphs into other graphs (data transformations, ETL, etc).</p> <h2 id="specification" tabindex="-1"><a class="header-anchor" href="#specification">Specification</a></h2> <p>Selectors are defined by an "DMT" (Data Model Tree -- similar to the concept of Abstract Syntax Tree, but syntax-agnostic) which is itself specified in IPLD, and uses IPLD Schemas for clarity.</p> <p>Implementations of Selectors read this "DMT" and evaluate its instructions to traverse a graph, and select nodes in it.</p> <h3 id="schema" tabindex="-1"><a class="header-anchor" href="#schema">Schema</a></h3> <p>This code block describes Selectors using <a href="../schemas/">IPLD Schemas</a> syntax.</p> <p>Descriptions of how each node should be evaluated can be found in comments inline in the schema.</p> <pre class="language-ipldsch"><code class="language-ipldsch"><span class="token comment">## SelectorEnvelope is the recommended top-level value for serialized messages</span> <span class="token comment">## that don't have established existing context with marks the start of a selector:</span> <span class="token comment">## it's a single-member union used to kick us towards "nominative typing".</span> <span class="token comment">##</span> <span class="token comment">## See https://ipld.io/docs/schemas/using/migrations/</span> <span class="token comment">## for a background on the theory behind this gentle-nominative concept.</span> <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">SelectorEnvelope</span></span> <span class="token builtin">union</span> <span class="token punctuation">{</span> <span class="token punctuation">|</span> Selector <span class="token string">"selector"</span> <span class="token representation">} <span class="token builtin">representation</span></span> keyed <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">Selector</span></span> <span class="token builtin">union</span> <span class="token punctuation">{</span> <span class="token punctuation">|</span> Matcher <span class="token string">"."</span> <span class="token punctuation">|</span> ExploreAll <span class="token string">"a"</span> <span class="token punctuation">|</span> ExploreFields <span class="token string">"f"</span> <span class="token punctuation">|</span> ExploreIndex <span class="token string">"i"</span> <span class="token punctuation">|</span> ExploreRange <span class="token string">"r"</span> <span class="token punctuation">|</span> ExploreRecursive <span class="token string">"R"</span> <span class="token punctuation">|</span> ExploreUnion <span class="token string">"|"</span> <span class="token punctuation">|</span> ExploreConditional <span class="token string">"&"</span> <span class="token punctuation">|</span> ExploreRecursiveEdge <span class="token string">"@"</span> <span class="token comment"># sentinel value; only valid in some positions.</span> <span class="token punctuation">|</span> InterpretAs <span class="token string">"~"</span> <span class="token representation">} <span class="token builtin">representation</span></span> keyed <span class="token comment">## ExploreAll is similar to a `*` -- it traverses all elements of an array,</span> <span class="token comment">## or all entries in a map, and applies a next selector to the reached nodes.</span> <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">ExploreAll</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span> next Selector <span class="token punctuation">(</span>rename <span class="token string">">"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token comment">## ExploreFields traverses named fields in a map (or equivalently, struct, if</span> <span class="token comment">## traversing on typed/schema nodes) and applies a next selector to the</span> <span class="token comment">## reached nodes.</span> <span class="token comment">##</span> <span class="token comment">## Note that a concept of exploring a whole path (e.g. "foo/bar/baz") can be</span> <span class="token comment">## represented as a set of three nexted ExploreFields selectors, each</span> <span class="token comment">## specifying one field.</span> <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">ExploreFields</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span> fields <span class="token punctuation">{</span>String<span class="token punctuation">:</span>Selector<span class="token punctuation">}</span> <span class="token punctuation">(</span>rename <span class="token string">"f>"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token comment">## ExploreIndex traverses a specific index in a list, and applies a next</span> <span class="token comment">## selector to the reached node.</span> <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">ExploreIndex</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span> index Int <span class="token punctuation">(</span>rename <span class="token string">"i"</span><span class="token punctuation">)</span> next Selector <span class="token punctuation">(</span>rename <span class="token string">">"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token comment">## ExploreRange traverses a list, and for each element in the range specified,</span> <span class="token comment">## will apply a next selector to those reached nodes.</span> <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">ExploreRange</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span> start Int <span class="token punctuation">(</span>rename <span class="token string">"^"</span><span class="token punctuation">)</span> end Int <span class="token punctuation">(</span>rename <span class="token string">"$"</span><span class="token punctuation">)</span> next Selector <span class="token punctuation">(</span>rename <span class="token string">">"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token comment">## ExploreRecursive traverses some structure recursively.</span> <span class="token comment">## To guide this exploration, it uses a "sequence", which is another Selector</span> <span class="token comment">## tree; some leaf node in this sequence should contain an ExploreRecursiveEdge</span> <span class="token comment">## selector, which denotes the place recursion should occur.</span> <span class="token comment">##</span> <span class="token comment">## In implementation, whenever evaluation reaches an ExploreRecursiveEdge marker</span> <span class="token comment">## in the recursion sequence's Selector tree, the implementation logically</span> <span class="token comment">## produces another new Selector which is a copy of the original</span> <span class="token comment">## ExploreRecursive selector, but with a decremented depth parameter for limit</span> <span class="token comment">## (if limit is of type depth), and continues evaluation thusly.</span> <span class="token comment">##</span> <span class="token comment">## It is not valid for an ExploreRecursive selector's sequence to contain</span> <span class="token comment">## no instances of ExploreRecursiveEdge; it *is* valid for it to contain</span> <span class="token comment">## more than one ExploreRecursiveEdge.</span> <span class="token comment">##</span> <span class="token comment">## ExploreRecursive can contain a nested ExploreRecursive!</span> <span class="token comment">## This is comparable to a nested for-loop.</span> <span class="token comment">## In these cases, any ExploreRecursiveEdge instance always refers to the</span> <span class="token comment">## nearest parent ExploreRecursive (in other words, ExploreRecursiveEdge can</span> <span class="token comment">## be thought of like the 'continue' statement, or end of a for-loop body;</span> <span class="token comment">## it is *not* a 'goto' statement).</span> <span class="token comment">##</span> <span class="token comment">## Be careful when using ExploreRecursive with a large depth limit parameter;</span> <span class="token comment">## it can easily cause very large traversals (especially if used in combination</span> <span class="token comment">## with selectors like ExploreAll inside the sequence).</span> <span class="token comment">##</span> <span class="token comment">## limit is a union type -- it can have an integer depth value (key "depth") or</span> <span class="token comment">## no value (key "none"). If limit has no value it is up to the</span> <span class="token comment">## implementation library using selectors to identify an appropriate max depth</span> <span class="token comment">## as necessary so that recursion is not infinite.</span> <span class="token comment">##</span> <span class="token comment">## stopAt specifies a Condition that stops the traversal when it is fulfilled.</span> <span class="token comment">## If throughout the traversal the selector encounters a node that matches</span> <span class="token comment">## Condition it will finish exploring the current node and it won't recurse more,</span> <span class="token comment">## stopping the traversal immediately.</span> <span class="token comment">## If Condition is never matched, the selector performs the traversal seamlessly</span> <span class="token comment">## until the end. This feature is of particular interest for applications that need to</span> <span class="token comment">## recurse a large linked structure up to a specific point. stopAt can be used to</span> <span class="token comment">## let the selector know where to stop recursing preventing from having to traverse</span> <span class="token comment">## the full structure.</span> <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">ExploreRecursive</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span> sequence Selector <span class="token punctuation">(</span>rename <span class="token string">":>"</span><span class="token punctuation">)</span> limit RecursionLimit <span class="token punctuation">(</span>rename <span class="token string">"l"</span><span class="token punctuation">)</span> stopAt <span class="token keyword">optional</span> Condition <span class="token punctuation">(</span>rename <span class="token string">"!"</span><span class="token punctuation">)</span> <span class="token comment"># if a node matches, we won't match it nor explore its children.</span> <span class="token punctuation">}</span> <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">RecursionLimit</span></span> <span class="token builtin">union</span> <span class="token punctuation">{</span> <span class="token punctuation">|</span> RecursionLimit_None <span class="token string">"none"</span> <span class="token punctuation">|</span> RecursionLimit_Depth <span class="token string">"depth"</span> <span class="token representation">} <span class="token builtin">representation</span></span> keyed <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">RecursionLimit_None</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">RecursionLimit_Depth</span></span> <span class="token keyword">int</span> <span class="token comment">## ExploreRecursiveEdge is a special sentinel value which is used to mark</span> <span class="token comment">## the end of a sequence started by an ExploreRecursive selector: the recursion</span> <span class="token comment">## goes back to the initial state of the earlier ExploreRecursive selector,</span> <span class="token comment">## and proceeds again (with a decremented maxDepth value).</span> <span class="token comment">##</span> <span class="token comment">## An ExploreRecursive selector that doesn't contain an ExploreRecursiveEdge</span> <span class="token comment">## is nonsensical. Containing more than one ExploreRecursiveEdge is valid.</span> <span class="token comment">## An ExploreRecursiveEdge without an enclosing ExploreRecursive is an error.</span> <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">ExploreRecursiveEdge</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token comment">## ExploreUnion allows selection to continue with two or more distinct selectors</span> <span class="token comment">## while exploring the same tree of data.</span> <span class="token comment">##</span> <span class="token comment">## ExploreUnion can be used to apply a Matcher on one node (causing it to</span> <span class="token comment">## be considered part of a (possibly labelled) result set), while simultaneously</span> <span class="token comment">## continuing to explore deeper parts of the tree with another selector,</span> <span class="token comment">## for example.</span> <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">ExploreUnion</span></span> <span class="token punctuation">[</span>Selector<span class="token punctuation">]</span> <span class="token comment">## Note that ExploreConditional versus a Matcher with a Condition are distinct:</span> <span class="token comment">## ExploreConditional progresses deeper into a tree;</span> <span class="token comment">## whereas a Matcher with a Condition may look deeper to make its decision,</span> <span class="token comment">## but returns a match for the node it's on rather any of the deeper values.</span> <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">ExploreConditional</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span> condition Condition <span class="token punctuation">(</span>rename <span class="token string">"&"</span><span class="token punctuation">)</span> next Selector <span class="token punctuation">(</span>rename <span class="token string">">"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token comment">## InterpretAs is a clause that instructs the traversal to attempt to 'reify' the current node</span> <span class="token comment">## using an ADL, which is specified by the 'as' field.</span> <span class="token comment">## ADLs are identified by agreed-upon strings, similar to libp2p protocols.</span> <span class="token comment">## Once reified, the traversal continues upon the newly reified view of the data,</span> <span class="token comment">## rather than the original raw data.</span> <span class="token comment">##</span> <span class="token comment">## If the selection interpreter doesn't have an ADL implementation available</span> <span class="token comment">## by the name requested, the traversal cannot continue.</span> <span class="token comment">##</span> <span class="token comment">## The reification process may consume a data-dependent amount of budget on evaluation,</span> <span class="token comment">## based on the specific traversal and ADL implementation.</span> <span class="token comment">## Similarly, steps across the ADL once reified may also consume data-dependent</span> <span class="token comment">## amounts of any resource budgets.</span> <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">InterpretAs</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span> as String next Selector <span class="token punctuation">(</span>rename <span class="token string">">"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token comment">## Slice is a predicate that selects only a subset of node.</span> <span class="token comment">## This is applicable primarily in the context of reified nodes based on the</span> <span class="token comment">## InterpetAs clause above, where the primitive (bytes or string) node is</span> <span class="token comment">## actually composed from multiple underlying substrate nodes.</span> <span class="token comment">##</span> <span class="token comment">## The slice is specified by a "from" index, which is inclusive, and a "to"</span> <span class="token comment">## index, which is exclusive. That is: [from, to).</span> <span class="token comment">##</span> <span class="token comment">## * Overflow of "to" is allowed, in which case a reified node</span> <span class="token comment">## implementation should interpret the overflow as the end of the slice. This</span> <span class="token comment">## allows for a simple way to specify a slice from a particular index to the</span> <span class="token comment">## end of the slice, without needing to know the length of the slice.</span> <span class="token comment">##</span> <span class="token comment">## * Negative values are allowed for "from" and "to", and are interpreted as</span> <span class="token comment">## offsets from the end of the slice. e.g. -1 is the last element, -2 is the</span> <span class="token comment">## second to last, etc. When a negative "from" value resolves to a negative</span> <span class="token comment">## index once the length of the slice is known (i.e. an underflow), the</span> <span class="token comment">## "from" value will be adjusted to be 0.</span> <span class="token comment">##</span> <span class="token comment">## Reified node implementations may choose to not implement negative ranges</span> <span class="token comment">## due to difficulties in implementing them efficiently. In these cases, the</span> <span class="token comment">## selector will fail to match.</span> <span class="token comment">##</span> <span class="token comment">## * Where the from:to range fails to match within the byte range of the node,</span> <span class="token comment">## (e.g. where they select a range beyond the end of the node), or where they</span> <span class="token comment">## resolve to a negative, or zero-length range (from>=to), the selector will</span> <span class="token comment">## fail to match. However, in the case where from==to, the selector will</span> <span class="token comment">## match, but the node should be empty.</span> <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">Slice</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span> from Int <span class="token punctuation">(</span>rename <span class="token string">"["</span><span class="token punctuation">)</span> to Int <span class="token punctuation">(</span>rename <span class="token string">"]"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token comment">## Matcher marks a node to be included in the "result" set.</span> <span class="token comment">## (All nodes traversed by a selector are in the "covered" set (which is a.k.a.</span> <span class="token comment">## "the merkle proof"); the "result" set is a subset of the "covered" set.)</span> <span class="token comment">##</span> <span class="token comment">## In libraries using selectors, the "result" set is typically provided to</span> <span class="token comment">## some user-specified callback.</span> <span class="token comment">##</span> <span class="token comment">## A selector tree with only "explore*"-type selectors and no Matcher selectors</span> <span class="token comment">## is valid; it will just generate a "covered" set of nodes and no "result" set.</span> <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">Matcher</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span> onlyIf <span class="token keyword">optional</span> Condition <span class="token comment"># match is true based on position alone if this is not set.</span> label <span class="token keyword">optional</span> String <span class="token comment"># labels can be used to match multiple different structures in one selection.</span> subset <span class="token keyword">optional</span> Slice <span class="token comment"># if set, only the subset of the node specified by the slice is matched.</span> <span class="token punctuation">}</span> <span class="token comment">## Condition is expresses a predicate with a boolean result.</span> <span class="token comment">##</span> <span class="token comment">## Condition clauses are used several places:</span> <span class="token comment">## - in Matcher, to determine if a node is selected.</span> <span class="token comment">## - in ExploreRecursive, to halt exploration.</span> <span class="token comment">## - in ExploreConditional,</span> <span class="token comment">##</span> <span class="token comment">##</span> <span class="token comment">## TODO -- Condition is very skeletal and incomplete.</span> <span class="token comment">## The place where Condition appears in other structs is correct;</span> <span class="token comment">## the rest of the details inside it are not final nor even completely drafted.</span> <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">Condition</span></span> <span class="token builtin">union</span> <span class="token punctuation">{</span> <span class="token comment"># We can come back to this and expand it later...</span> <span class="token comment"># TODO: figure out how to make this recurse correctly, so I can say "hasField{hasField{or{hasValue{1}, hasValue{2}}}}".</span> <span class="token punctuation">|</span> Condition_HasField <span class="token string">"hasField"</span> <span class="token punctuation">|</span> Condition_HasValue <span class="token string">"="</span> <span class="token comment"># will need to contain a kinded union, lol. these conditions are gonna get deep.)</span> <span class="token punctuation">|</span> Condition_HasKind <span class="token string">"%"</span> <span class="token comment"># will ideally want to refer to the DataModel ReprKind enum...! will we replicate that here? don't want to block on cross-schema references, but it's interesting that we've finally found a good example wanting it.</span> <span class="token punctuation">|</span> Condition_IsLink <span class="token string">"/"</span> <span class="token comment"># will need this so we can use it in recursions to say "stop at CID QmFoo".</span> <span class="token punctuation">|</span> Condition_GreaterThan <span class="token string">"greaterThan"</span> <span class="token punctuation">|</span> Condition_LessThan <span class="token string">"lessThan"</span> <span class="token punctuation">|</span> Condition_And <span class="token string">"and"</span> <span class="token punctuation">|</span> Condition_Or <span class="token string">"or"</span> <span class="token comment"># REVIEW: since we introduced "and" and "or" here, we're getting into dangertown again. we'll need a "max conditionals limit" (a la 'gas' of some kind) near here.</span> <span class="token representation">} <span class="token builtin">representation</span></span> keyed</code></pre> <h3 id="fixtures" tabindex="-1"><a class="header-anchor" href="#fixtures">fixtures</a></h3> <ul> <li><a href="./fixtures/selector-fixtures-1/">selector-fixtures-1</a></li> </ul> <h2 id="known-issues" tabindex="-1"><a class="header-anchor" href="#known-issues">Known issues</a></h2> <ul> <li>The "Condition" system is not fully specified -- it is a placeholder awaiting further design.</li> <li>The limit systems around recursion are primitive, and more like advisories than any kind of security feature. Subsequent recursions can always start over with new limits.</li> </ul> <h2 id="other-related-work" tabindex="-1"><a class="header-anchor" href="#other-related-work">Other related work</a></h2> <h3 id="implementations" tabindex="-1"><a class="header-anchor" href="#implementations">Implementations</a></h3> <ul> <li><a href="https://github.com/ipld/go-ipld-prime/tree/master/traversal/selector">Selectors package in go-ipld-prime</a> <ul> <li><a href="https://godoc.org/github.com/ipld/go-ipld-prime/traversal#Traverse">Traversal func which uses Selectors</a></li> </ul> </li> </ul> </div> </main> </body> </html>