Skip to content

Commit

Permalink
various fixes for netconf project
Browse files Browse the repository at this point in the history
  • Loading branch information
dhubler committed Jan 13, 2024
1 parent e4ae371 commit fe20e07
Show file tree
Hide file tree
Showing 9 changed files with 158 additions and 35 deletions.
13 changes: 12 additions & 1 deletion node/selection.go
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,8 @@ func (sel *Selection) set(r *FieldRequest, hnd *ValueHandle) error {
return nil
}

// GetValue let's you get the leaf value as a Value instance. Returns null if value is null
// Get let's you get the leaf value as a Value instance. Returns null if value is null
// Returns error if path is not found.
func (sel *Selection) Get() (val.Value, error) {
if !meta.IsLeaf(sel.Path.Meta) {
return nil, fmt.Errorf("%s is not a leaf", sel.Path.Meta.Ident())
Expand All @@ -640,6 +641,16 @@ func (sel *Selection) Get() (val.Value, error) {
return hnd.Val, err
}

// GetValue let's you get the leaf value at the specified path or ident. Returns null if
// value is null. Returns error if path is not found.
func (sel *Selection) GetValue(pathOrIdent string) (val.Value, error) {
s, err := sel.Find(pathOrIdent)
if err != nil {
return nil, err
}
return s.Get()
}

func (sel *Selection) get(r *FieldRequest, hnd *ValueHandle, useDefault bool) error {
if proceed, constraintErr := sel.Constraints.CheckFieldPreConstraints(r, hnd); !proceed || constraintErr != nil {
return constraintErr
Expand Down
3 changes: 2 additions & 1 deletion node/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ func NewValue(typ *meta.Type, v interface{}) (val.Value, error) {
}
switch typ.Format() {
case val.FmtIdentityRef:

return toIdentRef(typ.Base(), v)
case val.FmtIdentityRefList:
return toIdentRefList(typ.Base(), v)
Expand All @@ -78,6 +77,8 @@ func NewValue(typ *meta.Type, v interface{}) (val.Value, error) {
return cvt, err
case val.FmtUnionList:
return toUnionList(typ, v)
case val.FmtLeafRef, val.FmtLeafRefList:
return NewValue(typ.Resolve(), v)
}
return val.Conv(typ.Format(), v)
}
Expand Down
4 changes: 2 additions & 2 deletions nodeutil/json_rdr.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ func JsonContainerReader(container map[string]interface{}) node.Node {
}
s.OnChild = func(r node.ChildRequest) (child node.Node, e error) {
if r.New {
panic("Cannot write to JSON reader")
panic("cannot write to JSON reader")
}
if value, found := fqkGet(r.Meta, container); found {
if meta.IsList(r.Meta) {
Expand All @@ -146,7 +146,7 @@ func JsonContainerReader(container map[string]interface{}) node.Node {
}
s.OnField = func(r node.FieldRequest, hnd *node.ValueHandle) (err error) {
if r.Write {
panic("Cannot write to JSON reader")
panic("cannot write to JSON reader")
}
if val, found := fqkGet(r.Meta, container); found {
hnd.Val, err = leafOrLeafListJsonReader(r.Meta, val)
Expand Down
62 changes: 46 additions & 16 deletions nodeutil/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package nodeutil

import (
"context"
"errors"
"fmt"
"reflect"
"sort"
Expand Down Expand Up @@ -151,6 +152,10 @@ type Node struct {
// an rpc input.
OnNewObject func(t reflect.Type, m meta.Definition, insideList bool) (reflect.Value, error)

// OnNewNode is called when a new node needs to be created whether it is a child node of
// an rpc i/o or notification event.
OnNewNode func(n *Node, m meta.Meta, obj any) (node.Node, error)

OnContext func(n *Node, s *node.Selection) context.Context

c reflectContainer // internal handler based on object type to handle containers and leafs
Expand Down Expand Up @@ -291,7 +296,7 @@ func (n *Node) DoAction(r node.ActionRequest) (node.Node, error) {
if err != nil {
return nil, err
}
return a.do(n, r.Input)
return a.do(n, r.Meta, r.Input)
}

func (n *Node) Notify(r node.NotifyRequest) (node.NotifyCloser, error) {
Expand Down Expand Up @@ -343,6 +348,18 @@ func (ref *Node) exists(m meta.Definition) bool {
if found != nil && cerr == nil {
return true
}
} else if meta.IsChoice(m) {
cs, cerr := ref.Choose(nil, m.(*meta.Choice))
if cs != nil && cerr == nil {
// getting a case def might be the default case and not evidence
// data actually exists so we need to recurse into the case defs
for _, ddef := range cs.DataDefinitions() {
if ref.exists(ddef) {
return true
}
}
return true
}
} else {
r := node.FieldRequest{Meta: m.(meta.Leafable)}
var hnd node.ValueHandle
Expand Down Expand Up @@ -466,10 +483,10 @@ func (ref *Node) DoNewChild(r node.ChildRequest) (node.Node, error) {
return nil, err
}
if meta.IsList(r.Meta) && r.Selection.Path.Meta != r.Meta {
return ref.NewList(obj.Interface(), ref.onListUpdate(r.Meta.(*meta.List)))
return ref.NewList(r.Meta, obj.Interface(), ref.onListUpdate(r.Meta.(*meta.List)))
}

return ref.New(obj.Interface()), nil
return ref.New(r.Meta, obj.Interface())
}

func (ref *Node) onListUpdate(m *meta.List) NodeListUpdate {
Expand Down Expand Up @@ -508,30 +525,42 @@ func (ref *Node) DoGetChild(r node.ChildRequest) (node.Node, error) {
return nil, nil
}
if meta.IsList(r.Meta) && r.Selection.Path.Meta != r.Meta {
return ref.NewList(obj.Interface(), ref.onListUpdate(r.Meta.(*meta.List)))
return ref.NewList(r.Meta, obj.Interface(), ref.onListUpdate(r.Meta.(*meta.List)))
}
return ref.New(obj.Interface()), nil
return ref.New(r.Meta, obj.Interface())
}

func (ref *Node) NewList(obj any, u NodeListUpdate) (*Node, error) {
copy := ref.New(obj)
var err error
copy.l, err = ref.newListHandler(reflect.ValueOf(obj), u)
func (ref *Node) NewList(m meta.Meta, obj any, u NodeListUpdate) (node.Node, error) {
n, err := ref.New(m, obj)
if err != nil {
return nil, err
}
return copy, nil
if copy, isCopy := n.(*Node); isCopy {
var err error
copy.l, err = ref.newListHandler(reflect.ValueOf(obj), u)
if err != nil {
return nil, err
}
}
return n, nil
}

func (ref *Node) New(m meta.Meta, obj any) (node.Node, error) {
if ref.OnNewNode != nil {
return ref.OnNewNode(ref, m, obj)
}
return ref.DoNewNode(m, obj)
}

func (ref *Node) New(obj any) *Node {
func (ref *Node) DoNewNode(m meta.Meta, obj any) (*Node, error) {
if _, isVal := obj.(reflect.Value); isVal {
panic("passing in reflect.Value and not true obj")
return nil, errors.New("passing in reflect.Value and not true obj")
}
copy := *ref
copy.Object = obj
copy.l = nil
copy.c = nil
return &copy
return &copy, nil
}

type reflectContainer interface {
Expand Down Expand Up @@ -587,7 +616,7 @@ func (ref *Node) DoGetByKey(r node.ListRequest) (node.Node, error) {
if err != nil || !item.IsValid() || item.IsNil() {
return nil, err
}
return ref.New(item.Interface()), nil
return ref.New(r.Meta, item.Interface())
}

func (ref *Node) DoGetByRow(r node.ListRequest) (node.Node, []val.Value, error) {
Expand All @@ -605,7 +634,8 @@ func (ref *Node) DoGetByRow(r node.ListRequest) (node.Node, []val.Value, error)
}
}
}
return ref.New(item.Interface()), key, nil
n, err := ref.New(r.Meta, item.Interface())
return n, key, err

}

Expand All @@ -618,7 +648,7 @@ func (ref *Node) DoNewListItem(r node.ListRequest) (node.Node, error) {
if err != nil || !item.IsValid() || item.IsNil() {
return nil, err
}
return ref.New(item.Interface()), nil
return ref.New(r.Meta, item.Interface())
}

func (ref *Node) getValue(v val.Value) any {
Expand Down
10 changes: 7 additions & 3 deletions nodeutil/node_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,17 @@ func newActionHandler(src reflect.Value, rpc *meta.Rpc, opts NodeOptions) (*acti
return def, nil
}

func (def *actionHandler) do(n *Node, in *node.Selection) (node.Node, error) {
func (def *actionHandler) do(n *Node, m *meta.Rpc, in *node.Selection) (node.Node, error) {
inVal, err := def.newInput(in != nil)
if err != nil {
return nil, err
}
if in != nil {
if err = in.UpsertInto(n.New(inVal.Interface())); err != nil {
inNode, err := n.New(m.Input(), inVal.Interface())
if err != nil {
return nil, err
}
if err = in.UpsertInto(inNode); err != nil {
return nil, err
}
}
Expand All @@ -49,7 +53,7 @@ func (def *actionHandler) do(n *Node, in *node.Selection) (node.Node, error) {
}

if respVal.IsValid() {
return n.New(respVal.Interface()), nil
return n.New(m.Output(), respVal.Interface())
}

return nil, nil
Expand Down
26 changes: 18 additions & 8 deletions nodeutil/node_slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func newSliceAsList(ref *Node, src reflect.Value, u NodeListUpdate) *sliceAsList
}

func (def *sliceAsList) getByKey(r node.ListRequest) (reflect.Value, error) {
row, v, err := def.findByKey(r.Key, r.Meta.KeyMeta())
row, v, err := def.findByKey(r.Meta, r.Key, r.Meta.KeyMeta())
if row < 0 || err != nil {
return v, err
}
Expand All @@ -40,17 +40,20 @@ func (def *sliceAsList) getByRow(r node.ListRequest) (reflect.Value, []reflect.V
if !v.IsValid() || v.IsZero() {
return empty, nil, nil
}
key, _, err := def.getKey(v, r.Meta.KeyMeta())
key, _, err := def.getKey(v, r.Meta, r.Meta.KeyMeta())
return v, key, err
}

func (def *sliceAsList) getKey(item reflect.Value, keyMeta []meta.Leafable) ([]reflect.Value, []val.Value, error) {
func (def *sliceAsList) getKey(item reflect.Value, m meta.Meta, keyMeta []meta.Leafable) ([]reflect.Value, []val.Value, error) {
if len(keyMeta) == 0 || reflectIsEmpty(item) {
return nil, nil, nil
}

// construct mock field requests to get key so we ensure we consult the correct customizations
ref2 := def.ref.New(item.Interface())
ref2, err := def.ref.New(m, item.Interface())
if err != nil {
return nil, nil, fmt.Errorf("%w attempting to get key", err)
}
rvKey := make([]reflect.Value, len(keyMeta))
nvKey := make([]val.Value, len(keyMeta))
for i, kmeta := range keyMeta {
Expand All @@ -61,12 +64,19 @@ func (def *sliceAsList) getKey(item reflect.Value, keyMeta []meta.Leafable) ([]r
return nil, nil, fmt.Errorf("%w when get key", err)
}
nvKey[i] = hnd.Val
rvKey[i] = reflect.ValueOf(ref2.getValue(hnd.Val))
switch x := ref2.(type) {
case *Node:
// use opts to help coerse value to right
rvKey[i] = reflect.ValueOf(x.getValue(hnd.Val))
default:
// not a *Node, so just use value directly and trust it's right type
rvKey[i] = reflect.ValueOf(hnd.Val.Value())
}
}
return rvKey, nvKey, nil
}

func (def *sliceAsList) findByKey(target []val.Value, keyMeta []meta.Leafable) (int, reflect.Value, error) {
func (def *sliceAsList) findByKey(m meta.Meta, target []val.Value, keyMeta []meta.Leafable) (int, reflect.Value, error) {
notfound := -1
var empty reflect.Value
// full table scan of items in list to find first item that matches key. consider replacing
Expand All @@ -77,7 +87,7 @@ func (def *sliceAsList) findByKey(target []val.Value, keyMeta []meta.Leafable) (
if !candidate.IsValid() {
return notfound, empty, fmt.Errorf("row %d of %T is invalid", row, def.src.Type())
}
_, candidateKey, err := def.getKey(candidate, keyMeta)
_, candidateKey, err := def.getKey(candidate, m, keyMeta)
if err != nil {
return notfound, empty, err
}
Expand All @@ -95,7 +105,7 @@ func (def *sliceAsList) findByKey(target []val.Value, keyMeta []meta.Leafable) (
}

func (def *sliceAsList) deleteByKey(r node.ListRequest) error {
row, _, err := def.findByKey(r.Key, r.Meta.KeyMeta())
row, _, err := def.findByKey(r.Meta, r.Key, r.Meta.KeyMeta())
if row < 0 || err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions nodeutil/schema2.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (api schema2) manage(obj any) node.Node {
return n, nil
case "dataDef":
if x, isChoice := n.Object.(*meta.Choice); isChoice {
return n.NewList(x.Cases(), nil)
return n.NewList(r.Meta, x.Cases(), nil)
}
hasDefs := n.Object.(meta.HasDataDefinitions)
if hasRecursiveChild(hasDefs) {
Expand All @@ -77,7 +77,7 @@ func (api schema2) manage(obj any) node.Node {
copy[i] = defs[i]
}
}
return n.NewList(copy, nil)
return n.NewList(r.Meta, copy, nil)
}
case "unique":
if x, ok := n.Object.(*meta.List); ok {
Expand Down
67 changes: 67 additions & 0 deletions parser/testdata/augment/gold/refine.lex
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
module "module"
[ident] "refine"
{ "{"
grouping "grouping"
[ident] "g1"
{ "{"
uses "uses"
[ident] "g2"
; ";"
} "}"
grouping "grouping"
[ident] "g2"
{ "{"
uses "uses"
[ident] "g3"
{ "{"
augment "augment"
[string] "\"t1/t2\""
{ "{"
leaf "leaf"
[ident] "l2"
{ "{"
description "descriptio"...
[string] "\"orig\""
; ";"
type "type"
[ident] "string"
; ";"
} "}"
} "}"
} "}"
} "}"
grouping "grouping"
[ident] "g3"
{ "{"
choice "choice"
[ident] "t1"
{ "{"
case "case"
[ident] "t2"
{ "{"
leaf "leaf"
[ident] "l1"
{ "{"
type "type"
[ident] "string"
; ";"
} "}"
} "}"
} "}"
} "}"
notification "notificati"...
[ident] "c"
{ "{"
uses "uses"
[ident] "g1"
{ "{"
refine "refine"
[string] "\"t1/t2/l2\""
{ "{"
description "descriptio"...
[string] "\"here\""
; ";"
} "}"
} "}"
} "}"
} "}"
Loading

0 comments on commit fe20e07

Please sign in to comment.