textselector

package module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 29, 2021 License: Apache-2.0, MIT Imports: 5 Imported by: 17

README

go-ipld-selector-text-lite

A rudimentary (pre-ipld-schema) implementation of IPLD selectors

GoDoc GoReport

This library contains basic utilities for creation of IPLD selector objects from a flat textual representation. For further info see https://github.com/ipld/specs/blob/master/selectors/selectors.md

Lead Maintainer

Peter Rabbitson

License

SPDX-License-Identifier: Apache-2.0 OR MIT

Documentation

Overview

Package textselector provides basic utilities for creation of IPLD selector objects from a flat textual representation. For further info see https://github.com/ipld/specs/blob/master/selectors/selectors.md

Example (SelectorFromPath)
package main

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"log"

	"github.com/ipfs/go-cid"
	mipld "github.com/ipfs/go-ipld-format"
	mdag "github.com/ipfs/go-merkledag"
	mdagtest "github.com/ipfs/go-merkledag/test"

	// .../Raw must be imported to init() Raw-codec support
	// Dag-PB is additionally configured runtime
	dagpb "github.com/ipld/go-codec-dagpb"
	_ "github.com/ipld/go-ipld-prime/codec/raw"

	"github.com/ipld/go-ipld-prime"
	cidlink "github.com/ipld/go-ipld-prime/linking/cid"
	basicnode "github.com/ipld/go-ipld-prime/node/basic"
	"github.com/ipld/go-ipld-prime/traversal"
	"github.com/ipld/go-ipld-prime/traversal/selector"

	textselector "github.com/ipld/go-ipld-selector-text-lite"
)

func main() {

	//
	// we put together a fixture datastore, and also return its root
	ds, rootCid := fixtureDagService()

	//
	// Selector spec from a path, hopefully within that rootCid
	// The 001 is deliberate: making sure index navigation still works
	selectorSpec, err := textselector.SelectorSpecFromPath("Links/1/Hash/Links/001/Hash", false, nil)
	if err != nil {
		log.Fatal(err)
	}

	//
	// this is how we R/O interact with the fixture DS
	linkSystem := cidlink.DefaultLinkSystem()
	linkSystem.StorageReadOpener = func(lctx ipld.LinkContext, lnk ipld.Link) (io.Reader, error) {
		if cl, isCid := lnk.(cidlink.Link); !isCid {
			return nil, fmt.Errorf("unexpected link type %#v", lnk)
		} else {
			node, err := ds.Get(lctx.Ctx, cl.Cid)
			if err != nil {
				return nil, err
			}
			return bytes.NewBuffer(node.RawData()), nil
		}
	}

	//
	// this is what allows us to understand dagpb
	nodePrototypeChooser := dagpb.AddSupportToChooser(
		func(ipld.Link, ipld.LinkContext) (ipld.NodePrototype, error) {
			return basicnode.Prototype.Any, nil
		},
	)

	//
	// compile our selector from spec
	parsedSelector, err := selector.ParseSelector(selectorSpec.Node())
	if err != nil {
		log.Fatal(err)
	}

	//
	// Not sure why this indirection exists TBH...
	// Also trapping it in a struct ( twice ) is ugh
	ctx := context.TODO()
	linkContext := ipld.LinkContext{Ctx: ctx}

	//
	// this is how we pull the root node out of the DS
	startNodePrototype, err := nodePrototypeChooser(cidlink.Link{Cid: rootCid}, linkContext)
	if err != nil {
		log.Fatal(err)
	}
	startNode, err := linkSystem.Load(
		linkContext,
		cidlink.Link{Cid: rootCid},
		startNodePrototype,
	)
	if err != nil {
		log.Fatal(err)
	}

	//
	// this is executing the selector over the entire DS
	err = traversal.Progress{
		Cfg: &traversal.Config{
			Ctx:                            ctx,
			LinkSystem:                     linkSystem,
			LinkTargetNodePrototypeChooser: nodePrototypeChooser,
		},
	}.WalkAdv(
		startNode,
		parsedSelector,
		func(p traversal.Progress, n ipld.Node, r traversal.VisitReason) error {
			if r == traversal.VisitReason_SelectionMatch {
				content, _ := n.AsBytes()
				fmt.Printf("%s\n", content)
			}
			return nil
		},
	)
	if err != nil {
		log.Fatal(err)
	}

}

func fixtureDagService() (mipld.DAGService, cid.Cid) {
	ds := mdagtest.Mock()

	correct := mdag.NewRawNode([]byte("WantedNode"))
	incorrect := mdag.NewRawNode([]byte("UnwantedNode"))

	bothIncorrect := &mdag.ProtoNode{}
	bothIncorrect.AddNodeLink("a", incorrect)
	bothIncorrect.AddNodeLink("b", incorrect)

	bIsCorrect := &mdag.ProtoNode{}
	bIsCorrect.AddNodeLink("b", correct)
	bIsCorrect.AddNodeLink("a", incorrect)

	root := &mdag.ProtoNode{}
	root.AddNodeLink("", bothIncorrect)
	root.AddNodeLink("", bIsCorrect)

	ds.AddMany(context.Background(), []mipld.Node{
		correct, incorrect, bothIncorrect, bIsCorrect, root,
	})

	return ds, root.Cid()
}
Output:

WantedNode

Index

Examples

Constants

View Source
const PathValidCharset = `[- _0-9a-zA-Z\/\.]`

PathValidCharset is the regular expression fully matching a valid textselector

Variables

This section is empty.

Functions

func SelectorSpecFromPath

func SelectorSpecFromPath(path Expression, matchPath bool, optionalSubselectorAtTarget builder.SelectorSpec) (builder.SelectorSpec, error)

SelectorSpecFromPath transforms a textual path specification in the form x/y/10/z into a go-ipld-prime selector-spec object. This is a short-term stop-gap on the road to a more versatile text-based selector description mechanism. Therefore the accepted syntax is relatively inflexible, and restricted to the members of PathValidCharset. The parsing rules are:

  • The character `/` is a path segment separator
  • An empty segment ( `...//...` ) and the unix-like `.` and `..` are illegal
  • Any other valid segment is treated as a key within a map, or (if applicable) as an index within an array

Types

type Expression

type Expression string

Expression is a string-type input to SelectorSpecFromPath

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL