Skip to content

Commit

Permalink
feat: map/list interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
smrz2001 committed Aug 1, 2022
1 parent f628b18 commit aad4595
Show file tree
Hide file tree
Showing 12 changed files with 312 additions and 13 deletions.
8 changes: 8 additions & 0 deletions datamodel/container.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package datamodel

type Container interface {
Empty() bool
Length() int64
Clear()
Values() []Node
}
11 changes: 11 additions & 0 deletions datamodel/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package datamodel

type List interface {
Get(idx int64) (Node, bool)
Remove(idx int64)
Append(values ...interface{})
Insert(idx int64, values ...interface{})
Set(idx int64, value interface{})

Container
}
10 changes: 10 additions & 0 deletions datamodel/map.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package datamodel

type Map interface {
Put(key string, value interface{}) bool
Get(key string) (value Node, found bool)
Remove(key string) bool
Keys() []string

Container
}
4 changes: 2 additions & 2 deletions traversal/amendAny.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,10 @@ func (a *anyAmender) Prototype() datamodel.NodePrototype {

// -- Amender -->

func (a *anyAmender) Get(prog *Progress, path datamodel.Path, trackProgress bool) (datamodel.Node, error) {
func (a *anyAmender) Fetch(prog *Progress, path datamodel.Path, trackProgress bool) (datamodel.Node, error) {
// If the base node is an amender, use it, otherwise return the base node.
if amd, castOk := a.base.(Amender); castOk {
return amd.Get(prog, path, trackProgress)
return amd.Fetch(prog, path, trackProgress)
}
return a.base, nil
}
Expand Down
4 changes: 2 additions & 2 deletions traversal/amendLink.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ func (a *linkAmender) Prototype() datamodel.NodePrototype {

// -- Amender -->

func (a *linkAmender) Get(prog *Progress, path datamodel.Path, trackProgress bool) (datamodel.Node, error) {
func (a *linkAmender) Fetch(prog *Progress, path datamodel.Path, trackProgress bool) (datamodel.Node, error) {
// Check the budget
if prog.Budget != nil {
if prog.Budget.LinkBudget <= 0 {
Expand All @@ -133,7 +133,7 @@ func (a *linkAmender) Get(prog *Progress, path datamodel.Path, trackProgress boo
if path.Len() == 0 {
return a.Build(), nil
}
return a.child.Get(prog, path, trackProgress)
return a.child.Fetch(prog, path, trackProgress)
}

func (a *linkAmender) Transform(prog *Progress, path datamodel.Path, fn TransformFn, createParents bool) (datamodel.Node, error) {
Expand Down
52 changes: 50 additions & 2 deletions traversal/amendList.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

var (
_ datamodel.Node = &listAmender{}
_ datamodel.List = &listAmender{}
_ Amender = &listAmender{}
)

Expand Down Expand Up @@ -160,7 +161,7 @@ func (itr *listAmender_Iterator) Done() bool {

// -- Amender -->

func (a *listAmender) Get(prog *Progress, path datamodel.Path, trackProgress bool) (datamodel.Node, error) {
func (a *listAmender) Fetch(prog *Progress, path datamodel.Path, trackProgress bool) (datamodel.Node, error) {
// If the root is requested, return the `Node` view of the amender.
if path.Len() == 0 {
return a.Build(), nil
Expand Down Expand Up @@ -188,7 +189,7 @@ func (a *listAmender) Get(prog *Progress, path datamodel.Path, trackProgress boo
if err != nil {
return nil, err
}
return childAmender.Get(prog, remainingPath, trackProgress)
return childAmender.Fetch(prog, remainingPath, trackProgress)
}

func (a *listAmender) Transform(prog *Progress, path datamodel.Path, fn TransformFn, createParents bool) (datamodel.Node, error) {
Expand Down Expand Up @@ -343,3 +344,50 @@ func (a *listAmender) storeChildAmender(childIdx int64, n datamodel.Node, k data
}
return a.opts.newAmender(n, a, k, create), nil
}

// -- List -->

func NewList(base interface{}) datamodel.List {
// TODO: `base` must be of "list" type
return AmendOptions{}.newListAmender(nodeForType(base), nil, false).(*listAmender)
}

func (a *listAmender) Get(idx int64) (datamodel.Node, bool) {
//TODO implement me
panic("implement me")
}

func (a *listAmender) Remove(idx int64) {
//TODO implement me
panic("implement me")
}

func (a *listAmender) Append(values ...interface{}) {
//TODO implement me
panic("implement me")
}

func (a *listAmender) Insert(idx int64, values ...interface{}) {
//TODO implement me
panic("implement me")
}

func (a *listAmender) Set(idx int64, value interface{}) {
//TODO implement me
panic("implement me")
}

func (a *listAmender) Empty() bool {
//TODO implement me
panic("implement me")
}

func (a *listAmender) Clear() {
//TODO implement me
panic("implement me")
}

func (a *listAmender) Values() []datamodel.Node {
//TODO implement me
panic("implement me")
}
80 changes: 78 additions & 2 deletions traversal/amendMap.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

var (
_ datamodel.Node = &mapAmender{}
_ datamodel.Map = &mapAmender{}
_ Amender = &mapAmender{}
)

Expand Down Expand Up @@ -208,7 +209,7 @@ func (itr *mapAmender_Iterator) Done() bool {

// -- Amender -->

func (a *mapAmender) Get(prog *Progress, path datamodel.Path, trackProgress bool) (datamodel.Node, error) {
func (a *mapAmender) Fetch(prog *Progress, path datamodel.Path, trackProgress bool) (datamodel.Node, error) {
// If the root is requested, return the `Node` view of the amender.
if path.Len() == 0 {
return a.Build(), nil
Expand All @@ -228,7 +229,7 @@ func (a *mapAmender) Get(prog *Progress, path datamodel.Path, trackProgress bool
if err != nil {
return nil, err
}
return a.storeChildAmender(childSeg, childVal, childVal.Kind(), false, trackProgress).Get(prog, remainingPath, trackProgress)
return a.storeChildAmender(childSeg, childVal, childVal.Kind(), false, trackProgress).Fetch(prog, remainingPath, trackProgress)
}

func (a *mapAmender) Transform(prog *Progress, path datamodel.Path, fn TransformFn, createParents bool) (datamodel.Node, error) {
Expand Down Expand Up @@ -331,3 +332,78 @@ func (a *mapAmender) storeChildAmender(seg datamodel.PathSegment, n datamodel.No
}
return childAmender
}

// -- Map -->

func NewMap(base interface{}) datamodel.Map {
// TODO: `base` must be of "map" type
return AmendOptions{}.newMapAmender(nodeForType(base), nil, false).(*mapAmender)
}

func (a *mapAmender) Put(key string, value interface{}) bool {
if _, err := a.Transform(&Progress{}, datamodel.ParsePath("/"+key), func(progress Progress, node datamodel.Node) (datamodel.Node, error) {
return nodeForType(value), nil
}, false); err != nil {
return false
} else {
return true
}
}

func (a *mapAmender) Get(key string) (value datamodel.Node, found bool) {
if v, err := a.Fetch(&Progress{}, datamodel.ParsePath("/"+key), true); err != nil {
return nil, false
} else {
return nodeForType(v), true
}
}

func (a *mapAmender) Remove(key string) bool {
if _, err := a.Transform(&Progress{}, datamodel.ParsePath("/"+key), func(progress Progress, node datamodel.Node) (datamodel.Node, error) {
return nil, nil
}, false); err != nil {
return false
} else {
return true
}
}

func (a *mapAmender) Keys() []string {
keys := make([]string, a.Length())
count := 0
for itr := a.MapIterator(); !itr.Done(); {
if k, _, err := itr.Next(); err != nil {
return []string{}
} else if key, err := k.AsString(); err != nil {
return []string{}
} else {
keys[count] = key
count++
}
}
return keys
}

func (a *mapAmender) Empty() bool {
return a.Length() == 0
}

func (a *mapAmender) Clear() {
a.Transform(&Progress{}, datamodel.ParsePath("/"), func(progress Progress, node datamodel.Node) (datamodel.Node, error) {
return nil, nil
}, false)
}

func (a *mapAmender) Values() []datamodel.Node {
values := make([]datamodel.Node, a.Length())
count := 0
for itr := a.MapIterator(); !itr.Done(); {
_, v, err := itr.Next()
if err != nil {
return []datamodel.Node{}
}
values[count] = v
count++
}
return values
}
71 changes: 71 additions & 0 deletions traversal/amendUtils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package traversal

import (
"log"

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

func nodeForType(base interface{}) datamodel.Node {
if base == nil {
return nil
}
switch typ := base.(type) {
case Amender:
return base.(Amender).Build()
case datamodel.Node:
return base.(datamodel.Node)
case datamodel.Link:
return basicnode.NewLink(base.(datamodel.Link))
case bool:
return basicnode.NewBool(base.(bool))
case int8:
return basicnode.NewInt(int64(base.(int8)))
case int16:
return basicnode.NewInt(int64(base.(int16)))
case int32:
return basicnode.NewInt(int64(base.(int32)))
case int64:
return basicnode.NewInt(base.(int64))
case int:
return basicnode.NewInt(int64(base.(int)))
case uint8:
return basicnode.NewUint(uint64(base.(uint8)))
case uint16:
return basicnode.NewUint(uint64(base.(uint16)))
case uint32:
return basicnode.NewUint(uint64(base.(uint32)))
case uint64:
return basicnode.NewUint(base.(uint64))
case uint:
return basicnode.NewUint(uint64(base.(uint)))
case float32:
return basicnode.NewFloat(float64(base.(float32)))
case float64:
return basicnode.NewFloat(base.(float64))
case string:
return basicnode.NewString(base.(string))
case []byte: // Special handling for array of bytes
{
return basicnode.NewBytes(base.([]byte))
}
case map[string]interface{}:
{
a := AmendOptions{}.newMapAmender(nil, nil, false)
for k, v := range base.(map[string]interface{}) {
a.(datamodel.Map).Put(k, v)
}
return a.Build()
}
case []interface{}:
{
a := AmendOptions{}.newListAmender(nil, nil, false)
a.(datamodel.List).Append(base.([]interface{}))
return a.Build()
}
default:
log.Printf("invalid type: %s", typ)
panic("unreachable")
}
}
4 changes: 2 additions & 2 deletions traversal/amender.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package traversal
import "github.com/ipld/go-ipld-prime/datamodel"

type Amender interface {
// Get returns the node at the specified path. It will not create any intermediate nodes because this is just a
// Fetch returns the node at the specified path. It will not create any intermediate nodes because this is just a
// retrieval and not a modification operation.
Get(prog *Progress, path datamodel.Path, trackProgress bool) (datamodel.Node, error)
Fetch(prog *Progress, path datamodel.Path, trackProgress bool) (datamodel.Node, error)

// Transform will do an in-place transformation of the node at the specified path and return its previous value.
// If `createParents = true`, any missing parents will be created, otherwise this function will return an error.
Expand Down
2 changes: 1 addition & 1 deletion traversal/focus.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func (prog Progress) Get(n datamodel.Node, p datamodel.Path) (datamodel.Node, er
// For Get calls, trackProgress=false, which avoids some allocations for state tracking that's not needed by that call.
func (prog *Progress) get(n datamodel.Node, p datamodel.Path, trackProgress bool) (datamodel.Node, error) {
prog.init()
return NewAmender(n).Get(prog, p, trackProgress)
return NewAmender(n).Fetch(prog, p, trackProgress)
}

// FocusedTransform traverses a datamodel.Node graph, reaches a single Node,
Expand Down
Loading

0 comments on commit aad4595

Please sign in to comment.