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

Add partial-match traversal of large bytes #375

Merged
merged 14 commits into from
Mar 7, 2022
13 changes: 10 additions & 3 deletions node/basicnode/bytes.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func (nb *plainBytes__Builder) Reset() {
// -- NodeAssembler -->

type plainBytes__Assembler struct {
w *plainBytes
w datamodel.Node
}

func (plainBytes__Assembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {
Expand All @@ -131,17 +131,24 @@ func (plainBytes__Assembler) AssignString(string) error {
return mixins.BytesAssembler{TypeName: "bytes"}.AssignString("")
}
func (na *plainBytes__Assembler) AssignBytes(v []byte) error {
*na.w = plainBytes(v)
na.w = datamodel.Node(plainBytes(v))
return nil
}
func (plainBytes__Assembler) AssignLink(datamodel.Link) error {
return mixins.BytesAssembler{TypeName: "bytes"}.AssignLink(nil)
}
func (na *plainBytes__Assembler) AssignNode(v datamodel.Node) error {
if lb, ok := v.(datamodel.LargeBytesNode); ok {
lbn, err := lb.AsLargeBytes()
if err == nil {
na.w = streamBytes{lbn}
return nil
}
}
if v2, err := v.AsBytes(); err != nil {
return err
} else {
*na.w = plainBytes(v2)
na.w = plainBytes(v2)
return nil
}
}
Expand Down
81 changes: 81 additions & 0 deletions node/basicnode/bytes_stream.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package basicnode

import (
"io"

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

var (
_ datamodel.Node = streamBytes{nil}
_ datamodel.NodePrototype = Prototype__Bytes{}
_ datamodel.NodeBuilder = &plainBytes__Builder{}
_ datamodel.NodeAssembler = &plainBytes__Assembler{}
)

func NewBytesFromReader(rs io.ReadSeeker) datamodel.Node {
return streamBytes{rs}
}

// streamBytes is a boxed reader that complies with datamodel.Node.
type streamBytes struct {
io.ReadSeeker
}

// -- Node interface methods -->

func (streamBytes) Kind() datamodel.Kind {
return datamodel.Kind_Bytes
}
func (streamBytes) LookupByString(string) (datamodel.Node, error) {
return mixins.Bytes{TypeName: "bytes"}.LookupByString("")
}
func (streamBytes) LookupByNode(key datamodel.Node) (datamodel.Node, error) {
return mixins.Bytes{TypeName: "bytes"}.LookupByNode(nil)
}
func (streamBytes) LookupByIndex(idx int64) (datamodel.Node, error) {
return mixins.Bytes{TypeName: "bytes"}.LookupByIndex(0)
}
func (streamBytes) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {
return mixins.Bytes{TypeName: "bytes"}.LookupBySegment(seg)
}
func (streamBytes) MapIterator() datamodel.MapIterator {
return nil
}
func (streamBytes) ListIterator() datamodel.ListIterator {
return nil
}
func (streamBytes) Length() int64 {
return -1
}
func (streamBytes) IsAbsent() bool {
return false
}
func (streamBytes) IsNull() bool {
return false
}
func (streamBytes) AsBool() (bool, error) {
return mixins.Bytes{TypeName: "bytes"}.AsBool()
}
func (streamBytes) AsInt() (int64, error) {
return mixins.Bytes{TypeName: "bytes"}.AsInt()
}
func (streamBytes) AsFloat() (float64, error) {
return mixins.Bytes{TypeName: "bytes"}.AsFloat()
}
func (streamBytes) AsString() (string, error) {
return mixins.Bytes{TypeName: "bytes"}.AsString()
}
func (n streamBytes) AsBytes() ([]byte, error) {
return io.ReadAll(n)
}
func (streamBytes) AsLink() (datamodel.Link, error) {
return mixins.Bytes{TypeName: "bytes"}.AsLink()
}
func (streamBytes) Prototype() datamodel.NodePrototype {
return Prototype__Bytes{}
}
func (n streamBytes) AsLargeBytes() (io.ReadSeeker, error) {
return n.ReadSeeker, nil
}
12 changes: 12 additions & 0 deletions node/basicnode/bytes_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package basicnode_test

import (
"testing"

"github.com/ipld/go-ipld-prime/node/basicnode"
"github.com/ipld/go-ipld-prime/node/tests"
)

func TestBytes(t *testing.T) {
tests.SpecTestBytes(t, basicnode.Prototype__Bytes{})
}
35 changes: 35 additions & 0 deletions node/tests/byteSpecs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package tests

import (
"io"
"testing"

qt "github.com/frankban/quicktest"

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

func SpecTestBytes(t *testing.T, np datamodel.NodePrototype) {
t.Run("byte node", func(t *testing.T) {
nb := np.NewBuilder()
err := nb.AssignBytes([]byte("asdf"))
qt.Check(t, err, qt.IsNil)
n := nb.Build()

qt.Check(t, n.Kind(), qt.Equals, datamodel.Kind_Bytes)
qt.Check(t, n.IsNull(), qt.IsFalse)
x, err := n.AsBytes()
qt.Check(t, err, qt.IsNil)
qt.Check(t, x, qt.DeepEquals, []byte("asdf"))

lbn, ok := n.(datamodel.LargeBytesNode)
if ok {
str, err := lbn.AsLargeBytes()
qt.Check(t, err, qt.IsNil)
bytes, err := io.ReadAll(str)
qt.Check(t, err, qt.IsNil)
qt.Check(t, bytes, qt.DeepEquals, []byte("asdf"))
}

})
}
14 changes: 14 additions & 0 deletions traversal/selector/builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type SelectorSpecBuilder interface {
ExploreFields(ExploreFieldsSpecBuildingClosure) SelectorSpec
ExploreInterpretAs(as string, next SelectorSpec) SelectorSpec
Matcher() SelectorSpec
MatcherSubset(from, to int64) SelectorSpec
}

// ExploreFieldsSpecBuildingClosure is a function that provided to SelectorSpecBuilder's
Expand Down Expand Up @@ -170,6 +171,19 @@ func (ssb *selectorSpecBuilder) Matcher() SelectorSpec {
}
}

func (ssb *selectorSpecBuilder) MatcherSubset(from, to int64) SelectorSpec {
return selectorSpec{
fluent.MustBuildMap(ssb.np, 1, func(na fluent.MapAssembler) {
na.AssembleEntry(selector.SelectorKey_Matcher).CreateMap(1, func(na fluent.MapAssembler) {
na.AssembleEntry(selector.SelectorKey_Subset).CreateMap(2, func(na fluent.MapAssembler) {
na.AssembleEntry(selector.SelectorKey_From).AssignInt(from)
na.AssembleEntry(selector.SelectorKey_To).AssignInt(to)
})
})
}),
}
}

type exploreFieldsSpecBuilder struct {
na fluent.MapAssembler
}
Expand Down
5 changes: 5 additions & 0 deletions traversal/selector/exploreAll.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ func (s ExploreAll) Decide(n datamodel.Node) bool {
return false
}

// Match always returns false because this is not a matcher
func (s ExploreAll) Match(node datamodel.Node) (datamodel.Node, error) {
return nil, nil
}

// ParseExploreAll assembles a Selector from a ExploreAll selector node
func (pc ParseContext) ParseExploreAll(n datamodel.Node) (Selector, error) {
if n.Kind() != datamodel.Kind_Map {
Expand Down
5 changes: 5 additions & 0 deletions traversal/selector/exploreFields.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ func (s ExploreFields) Decide(n datamodel.Node) bool {
return false
}

// Match always returns false because this is not a matcher
func (s ExploreFields) Match(node datamodel.Node) (datamodel.Node, error) {
return nil, nil
}

// ParseExploreFields assembles a Selector
// from a ExploreFields selector node
func (pc ParseContext) ParseExploreFields(n datamodel.Node) (Selector, error) {
Expand Down
5 changes: 5 additions & 0 deletions traversal/selector/exploreIndex.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ func (s ExploreIndex) Decide(n datamodel.Node) bool {
return false
}

// Match always returns false because this is not a matcher
func (s ExploreIndex) Match(node datamodel.Node) (datamodel.Node, error) {
return nil, nil
}

// ParseExploreIndex assembles a Selector
// from a ExploreIndex selector node
func (pc ParseContext) ParseExploreIndex(n datamodel.Node) (Selector, error) {
Expand Down
5 changes: 5 additions & 0 deletions traversal/selector/exploreInterpretAs.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ func (s ExploreInterpretAs) Decide(n datamodel.Node) bool {
return false
}

// Match always returns false because this is not a matcher
func (s ExploreInterpretAs) Match(node datamodel.Node) (datamodel.Node, error) {
return nil, nil
}

// NamedReifier indicates how this selector expects to Reify the current datamodel.Node.
func (s ExploreInterpretAs) NamedReifier() string {
return s.adl
Expand Down
5 changes: 5 additions & 0 deletions traversal/selector/exploreRange.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ func (s ExploreRange) Decide(n datamodel.Node) bool {
return false
}

// Match always returns false because this is not a matcher
func (s ExploreRange) Match(node datamodel.Node) (datamodel.Node, error) {
return nil, nil
}

// ParseExploreRange assembles a Selector
// from a ExploreRange selector node
func (pc ParseContext) ParseExploreRange(n datamodel.Node) (Selector, error) {
Expand Down
5 changes: 5 additions & 0 deletions traversal/selector/exploreRecursive.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@ func (s ExploreRecursive) Decide(n datamodel.Node) bool {
return s.current.Decide(n)
}

// Match always returns false because this is not a matcher
func (s ExploreRecursive) Match(node datamodel.Node) (datamodel.Node, error) {
return s.current.Match(node)
}

type exploreRecursiveContext struct {
edgesFound int
}
Expand Down
5 changes: 5 additions & 0 deletions traversal/selector/exploreRecursiveEdge.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ func (s ExploreRecursiveEdge) Decide(n datamodel.Node) bool {
return false
}

// Match always returns false because this is not a matcher
func (s ExploreRecursiveEdge) Match(node datamodel.Node) (datamodel.Node, error) {
return nil, nil
}

// ParseExploreRecursiveEdge assembles a Selector
// from a exploreRecursiveEdge selector node
func (pc ParseContext) ParseExploreRecursiveEdge(n datamodel.Node) (Selector, error) {
Expand Down
12 changes: 12 additions & 0 deletions traversal/selector/exploreUnion.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,18 @@ func (s ExploreUnion) Decide(n datamodel.Node) bool {
return false
}

// Match returns true for a Union selector based on the matched union.
func (s ExploreUnion) Match(n datamodel.Node) (datamodel.Node, error) {
for _, m := range s.Members {
if mn, err := m.Match(n); mn != nil {
return mn, nil
} else if err != nil {
return nil, err
}
}
return nil, nil
}

// ParseExploreUnion assembles a Selector
// from an ExploreUnion selector node
func (pc ParseContext) ParseExploreUnion(n datamodel.Node) (Selector, error) {
Expand Down
3 changes: 3 additions & 0 deletions traversal/selector/fieldKeys.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,8 @@ const (
SelectorKey_StopAt = "!"
SelectorKey_Condition = "&"
SelectorKey_As = "as"
SelectorKey_Subset = "subset"
SelectorKey_From = "["
SelectorKey_To = "]"
// not filling conditional keys since it's not complete
)
Loading