Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

signaling ADLs in selectors #301

Merged
merged 13 commits into from
Jan 10, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions linking/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type LinkSystem struct {
StorageReadOpener BlockReadOpener
TrustedStorage bool
NodeReifier NodeReifier
KnownReifiers map[string]NodeReifier
}

// The following three types are the key functionality we need from a "blockstore".
Expand Down
12 changes: 12 additions & 0 deletions traversal/selector/builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type SelectorSpecBuilder interface {
ExploreIndex(index int64, next SelectorSpec) SelectorSpec
ExploreRange(start, end int64, next SelectorSpec) SelectorSpec
ExploreFields(ExploreFieldsSpecBuildingClosure) SelectorSpec
ExploreInterpretAs(as string, next SelectorSpec) SelectorSpec
Matcher() SelectorSpec
}

Expand Down Expand Up @@ -150,6 +151,17 @@ func (ssb *selectorSpecBuilder) ExploreFields(specBuilder ExploreFieldsSpecBuild
}
}

func (ssb *selectorSpecBuilder) ExploreInterpretAs(as string, next SelectorSpec) SelectorSpec {
return selectorSpec{
fluent.MustBuildMap(ssb.np, 1, func(na fluent.MapAssembler) {
na.AssembleEntry(selector.SelectorKey_ExploreInterpretAs).CreateMap(1, func(na fluent.MapAssembler) {
na.AssembleEntry(selector.SelectorKey_As).AssignString(as)
na.AssembleEntry(selector.SelectorKey_Next).AssignNode(next.Node())
})
}),
}
}

func (ssb *selectorSpecBuilder) Matcher() SelectorSpec {
return selectorSpec{
fluent.MustBuildMap(ssb.np, 1, func(na fluent.MapAssembler) {
Expand Down
65 changes: 65 additions & 0 deletions traversal/selector/exploreInterpretAs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package selector

import (
"fmt"

"github.com/ipld/go-ipld-prime/datamodel"
)

type ExploreInterpretAs struct {
next Selector // selector for element we're interested in
adl string // reifier for the ADL we're interested in
}

// Interests for ExploreIndex is just the index specified by the selector node
func (s ExploreInterpretAs) Interests() []datamodel.PathSegment {
return s.next.Interests()
}

// Explore returns the node's selector if
// the path matches the index for this selector or nil if not
func (s ExploreInterpretAs) Explore(n datamodel.Node, p datamodel.PathSegment) (Selector, error) {
return s.next, nil
}

// Decide always returns false because this is not a matcher
func (s ExploreInterpretAs) Decide(n datamodel.Node) bool {
return false
}

// Transform indicates how this selector expects to transform the current datamodel.Node.
func (s ExploreInterpretAs) Transform() string {
return s.adl
}

// Transformable provides for a feature detection interface on selectors to understand when
// and if Transformation of the datamodel.node should be attempted when performing traversals.
type Transformable interface {
Transform() string
willscott marked this conversation as resolved.
Show resolved Hide resolved
}

// ParseExploreInterpretAs assembles a Selector
// from a ExploreInterpretAs selector node
func (pc ParseContext) ParseExploreInterpretAs(n datamodel.Node) (Selector, error) {
if n.Kind() != datamodel.Kind_Map {
return nil, fmt.Errorf("selector spec parse rejected: selector body must be a map")
}
adlNode, err := n.LookupByString(SelectorKey_As)
if err != nil {
return nil, fmt.Errorf("selector spec parse rejected: fields in ExploreFields selector must be present")
willscott marked this conversation as resolved.
Show resolved Hide resolved
}
next, err := n.LookupByString(SelectorKey_Next)
if err != nil {
return nil, fmt.Errorf("selector spec parse rejected: next field must be present in ExploreAll selector")
willscott marked this conversation as resolved.
Show resolved Hide resolved
}
selector, err := pc.ParseSelector(next)
if err != nil {
return nil, err
}
adl, err := adlNode.AsString()
if err != nil {
return nil, err
}

return ExploreInterpretAs{selector, adl}, nil
}
2 changes: 2 additions & 0 deletions traversal/selector/fieldKeys.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const (
SelectorKey_ExploreUnion = "|"
SelectorKey_ExploreConditional = "&"
SelectorKey_ExploreRecursiveEdge = "@"
SelectorKey_ExploreInterpretAs = "~"
SelectorKey_Next = ">"
SelectorKey_Fields = "f>"
SelectorKey_Index = "i"
Expand All @@ -21,5 +22,6 @@ const (
SelectorKey_LimitNone = "none"
SelectorKey_StopAt = "!"
SelectorKey_Condition = "&"
SelectorKey_As = "c"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realize this would also be a specs change, since we merged that in the ipld/ipld repo already, but since this will be the first implementation actually using it --

I still think we should change this key. There's no way I would either look at the spec and expect it to use the constant "c" here, nor look at the constant "c" in a message and guess remotely correctly what it stands for. (To wit: I just had to look it up again.)

Can we use "as"? I don't think a second byte is going to bother anyone, and my surprise factor would go down drastically.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm very scared to go back to step one given that we're now 2 months in to a very simple change that has now missed 2 shipping deadlines because of the spec then implementation then wait long time for review approach.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// not filling conditional keys since it's not complete
)
2 changes: 2 additions & 0 deletions traversal/selector/selector.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ func (pc ParseContext) ParseSelector(n datamodel.Node) (Selector, error) {
return pc.ParseExploreRecursive(v)
case SelectorKey_ExploreRecursiveEdge:
return pc.ParseExploreRecursiveEdge(v)
case SelectorKey_ExploreInterpretAs:
return pc.ParseExploreInterpretAs(v)
case SelectorKey_Matcher:
return pc.ParseMatcher(v)
default:
Expand Down
19 changes: 19 additions & 0 deletions traversal/walk.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,25 @@ func (prog Progress) walkAdv(n datamodel.Node, s selector.Selector, fn AdvVisitF
}

func (prog Progress) walkAdv_iterateAll(n datamodel.Node, s selector.Selector, fn AdvVisitFn) error {
if rs, ok := s.(selector.Transformable); ok {
willscott marked this conversation as resolved.
Show resolved Hide resolved
adl := rs.Transform()
if prog.Cfg.LinkSystem.KnownReifiers == nil {
return fmt.Errorf("adl requested but not supported by link system: %s", adl)
willscott marked this conversation as resolved.
Show resolved Hide resolved
}
reifier, ok := prog.Cfg.LinkSystem.KnownReifiers[adl]
if !ok {
return fmt.Errorf("unregistered adl requested: %s", adl)
willscott marked this conversation as resolved.
Show resolved Hide resolved
}

rn, err := reifier(linking.LinkContext{
Ctx: prog.Cfg.Ctx,
LinkPath: prog.Path,
}, n, &prog.Cfg.LinkSystem)
if err != nil {
return err
willscott marked this conversation as resolved.
Show resolved Hide resolved
}
n = rn
}
for itr := selector.NewSegmentIterator(n); !itr.Done(); {
ps, v, err := itr.Next()
if err != nil {
Expand Down