Skip to content

Commit 444a566

Browse files
implement sort elements based on schema keys
1 parent 9143ee6 commit 444a566

File tree

4 files changed

+77
-31
lines changed

4 files changed

+77
-31
lines changed

pkg/datastore/target/nc.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"time"
2424

2525
"github.com/beevik/etree"
26+
"github.com/sdcio/data-server/pkg/tree"
2627
sdcpb "github.com/sdcio/sdc-protos/sdcpb"
2728
log "github.com/sirupsen/logrus"
2829

@@ -268,7 +269,7 @@ func (t *ncTarget) reconnect() {
268269

269270
func (t *ncTarget) setRunning(source TargetSource) (*sdcpb.SetDataResponse, error) {
270271

271-
xtree, err := source.ToXML(true, t.sbiConfig.NetconfOptions.IncludeNS, t.sbiConfig.NetconfOptions.OperationWithNamespace, t.sbiConfig.NetconfOptions.UseOperationRemove, false)
272+
xtree, err := source.ToXML(true, t.sbiConfig.NetconfOptions.IncludeNS, t.sbiConfig.NetconfOptions.OperationWithNamespace, t.sbiConfig.NetconfOptions.UseOperationRemove, tree.SchemaBound)
272273
if err != nil {
273274
return nil, err
274275
}
@@ -328,7 +329,7 @@ func filterRPCErrors(xml *etree.Document, severity string) ([]string, error) {
328329
}
329330

330331
func (t *ncTarget) setCandidate(source TargetSource) (*sdcpb.SetDataResponse, error) {
331-
xtree, err := source.ToXML(true, t.sbiConfig.NetconfOptions.IncludeNS, t.sbiConfig.NetconfOptions.OperationWithNamespace, t.sbiConfig.NetconfOptions.UseOperationRemove, false)
332+
xtree, err := source.ToXML(true, t.sbiConfig.NetconfOptions.IncludeNS, t.sbiConfig.NetconfOptions.OperationWithNamespace, t.sbiConfig.NetconfOptions.UseOperationRemove, tree.SchemaBound)
332333
if err != nil {
333334
return nil, err
334335
}

pkg/datastore/target/target.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"fmt"
2020

2121
"github.com/beevik/etree"
22+
"github.com/sdcio/data-server/pkg/tree"
2223
sdcpb "github.com/sdcio/sdc-protos/sdcpb"
2324
"google.golang.org/grpc"
2425

@@ -74,7 +75,7 @@ type TargetSource interface {
7475
// ToJsonIETF returns the Tree contained structure as JSON_IETF
7576
// use e.g. json.MarshalIndent() on the returned struct
7677
ToJsonIETF(onlyNewOrUpdated bool, ordered bool) (any, error)
77-
ToXML(onlyNewOrUpdated bool, honorNamespace bool, operationWithNamespace bool, useOperationRemove bool, ordered bool) (*etree.Document, error)
78+
ToXML(onlyNewOrUpdated bool, honorNamespace bool, operationWithNamespace bool, useOperationRemove bool, ordering tree.OrderingMethod) (*etree.Document, error)
7879
ToProtoUpdates(ctx context.Context, onlyNewOrUpdated bool) ([]*sdcpb.Update, error)
7980
ToProtoDeletes(ctx context.Context) ([]*sdcpb.Path, error)
8081
}

pkg/tree/entry.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ const (
1919
RunningIntentName = "running"
2020
)
2121

22+
type OrderingMethod uint
23+
24+
const (
25+
None OrderingMethod = iota
26+
Alphabetical
27+
SchemaBound
28+
)
29+
2230
type EntryImpl struct {
2331
*sharedEntryAttributes
2432
}
@@ -120,8 +128,8 @@ type Entry interface {
120128
// toJsonInternal the internal function that produces JSON and JSON_IETF
121129
// Not for external usage
122130
toJsonInternal(onlyNewOrUpdated bool, ietf bool, ordered bool) (j any, err error)
123-
ToXML(onlyNewOrUpdated bool, honorNamespace bool, operationWithNamespace bool, useOperationRemove bool, ordered bool) (*etree.Document, error)
124-
toXmlInternal(parent *etree.Element, onlyNewOrUpdated bool, honorNamespace bool, operationWithNamespace bool, useOperationRemove bool, ordered bool) (doAdd bool, err error)
131+
ToXML(onlyNewOrUpdated bool, honorNamespace bool, operationWithNamespace bool, useOperationRemove bool, ordering OrderingMethod) (*etree.Document, error)
132+
toXmlInternal(parent *etree.Element, onlyNewOrUpdated bool, honorNamespace bool, operationWithNamespace bool, useOperationRemove bool, ordering OrderingMethod) (doAdd bool, err error)
125133
// ImportConfig allows importing config data received from e.g. the device in different formats (json, xml) to be imported into the tree.
126134
ImportConfig(ctx context.Context, t importer.ImportConfigAdapter, intentName string, intentPrio int32) error
127135
}

pkg/tree/xml.go

Lines changed: 62 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package tree
22

33
import (
4+
"cmp"
45
"fmt"
56
"slices"
67

@@ -13,16 +14,16 @@ import (
1314
// If honorNamespace is set, the xml elements will carry their respective namespace attributes.
1415
// If operationWithNamespace is set, the operation attributes added to the to be deleted alements will also carry the Netconf Base namespace.
1516
// If useOperationRemove is set, the remove operation will be used for deletes, instead of the delete operation.
16-
func (s *sharedEntryAttributes) ToXML(onlyNewOrUpdated, honorNamespace, operationWithNamespace, useOperationRemove bool, ordered bool) (*etree.Document, error) {
17+
func (s *sharedEntryAttributes) ToXML(onlyNewOrUpdated, honorNamespace, operationWithNamespace, useOperationRemove bool, ordering OrderingMethod) (*etree.Document, error) {
1718
doc := etree.NewDocument()
18-
_, err := s.toXmlInternal(&doc.Element, onlyNewOrUpdated, honorNamespace, operationWithNamespace, useOperationRemove, ordered)
19+
_, err := s.toXmlInternal(&doc.Element, onlyNewOrUpdated, honorNamespace, operationWithNamespace, useOperationRemove, ordering)
1920
if err != nil {
2021
return nil, err
2122
}
2223
return doc, nil
2324
}
2425

25-
func (s *sharedEntryAttributes) toXmlInternal(parent *etree.Element, onlyNewOrUpdated bool, honorNamespace bool, operationWithNamespace bool, useOperationRemove bool, ordered bool) (doAdd bool, err error) {
26+
func (s *sharedEntryAttributes) toXmlInternal(parent *etree.Element, onlyNewOrUpdated bool, honorNamespace bool, operationWithNamespace bool, useOperationRemove bool, ordering OrderingMethod) (doAdd bool, err error) {
2627

2728
switch s.schema.GetSchema().(type) {
2829
case nil:
@@ -42,31 +43,45 @@ func (s *sharedEntryAttributes) toXmlInternal(parent *etree.Element, onlyNewOrUp
4243

4344
childs := s.filterActiveChoiceCaseChilds()
4445

45-
if ordered {
46-
keys := make([]string, 0, len(childs))
47-
for k := range childs {
48-
keys = append(keys, k)
49-
}
50-
slices.Sort(keys)
46+
keys := make([]string, 0, len(childs))
47+
for k := range childs {
48+
keys = append(keys, k)
49+
}
5150

52-
for _, k := range keys {
53-
// recurse the call
54-
// no additional element is created, since we're on a key level, so add to parent element
55-
doAdd, err := childs[k].toXmlInternal(parent, onlyNewOrUpdated, honorNamespace, operationWithNamespace, useOperationRemove, ordered)
56-
if err != nil {
57-
return false, err
58-
}
59-
// only if there was something added in the childs, the element itself is meant to be added.
60-
// we keep track of that via overAllDoAdd.
61-
overallDoAdd = doAdd || overallDoAdd
51+
switch ordering {
52+
case Alphabetical:
53+
slices.Sort(keys)
54+
case None:
55+
case SchemaBound:
56+
schemaParent, _ := s.GetFirstAncestorWithSchema()
57+
if schemaParent == nil {
58+
return false, fmt.Errorf("no ancestor has schema for %v", s)
6259
}
63-
return overallDoAdd, nil
60+
schemaKeys := schemaParent.GetSchemaKeys()
61+
slices.SortFunc(keys, func(a, b string) int {
62+
aIdx := slices.Index(schemaKeys, a)
63+
bIdx := slices.Index(schemaKeys, b)
64+
switch {
65+
case aIdx == -1 && bIdx == -1:
66+
// if neither are keys, sort them against each other
67+
return cmp.Compare(a, b)
68+
case aIdx == -1:
69+
return 1
70+
case bIdx == -1:
71+
return -1
72+
default:
73+
return cmp.Compare(aIdx, bIdx)
74+
}
75+
})
76+
77+
default:
78+
return false, fmt.Errorf("unknown ordering method: %v", ordering)
6479
}
6580

66-
for _, c := range childs {
81+
for _, k := range keys {
6782
// recurse the call
6883
// no additional element is created, since we're on a key level, so add to parent element
69-
doAdd, err := c.toXmlInternal(parent, onlyNewOrUpdated, honorNamespace, operationWithNamespace, useOperationRemove, ordered)
84+
doAdd, err := childs[k].toXmlInternal(parent, onlyNewOrUpdated, honorNamespace, operationWithNamespace, useOperationRemove, ordering)
7085
if err != nil {
7186
return false, err
7287
}
@@ -87,8 +102,16 @@ func (s *sharedEntryAttributes) toXmlInternal(parent *etree.Element, onlyNewOrUp
87102
return false, err
88103
}
89104

90-
if ordered {
105+
switch ordering {
106+
case Alphabetical:
107+
slices.SortFunc(childs, func(a, b Entry) int {
108+
return cmp.Compare(a.PathName(), b.PathName())
109+
})
110+
case SchemaBound:
91111
slices.SortFunc(childs, getListEntrySortFunc(s))
112+
case None:
113+
default:
114+
return false, fmt.Errorf("unknown ordering method: %v", ordering)
92115
}
93116

94117
// go through the childs creating the xml elements
@@ -98,7 +121,7 @@ func (s *sharedEntryAttributes) toXmlInternal(parent *etree.Element, onlyNewOrUp
98121
// process the honorNamespace instruction
99122
xmlAddNamespaceConditional(s, s.parent, newElem, honorNamespace)
100123
// recurse the call
101-
doAdd, err := child.toXmlInternal(newElem, onlyNewOrUpdated, honorNamespace, operationWithNamespace, useOperationRemove, ordered)
124+
doAdd, err := child.toXmlInternal(newElem, onlyNewOrUpdated, honorNamespace, operationWithNamespace, useOperationRemove, ordering)
102125
if err != nil {
103126
return false, err
104127
}
@@ -147,8 +170,21 @@ func (s *sharedEntryAttributes) toXmlInternal(parent *etree.Element, onlyNewOrUp
147170
keys = append(keys, k)
148171
}
149172

150-
if ordered {
173+
switch ordering {
174+
case Alphabetical:
151175
slices.Sort(keys)
176+
case SchemaBound:
177+
if s.parent == nil {
178+
slices.Sort(keys)
179+
} else {
180+
cldrn := s.schema.GetContainer().GetChildren()
181+
slices.SortFunc(keys, func(a, b string) int {
182+
return cmp.Compare(slices.Index(cldrn, a), slices.Index(cldrn, b))
183+
})
184+
}
185+
case None:
186+
default:
187+
return false, fmt.Errorf("unknown ordering method: %v", ordering)
152188
}
153189

154190
// iterate through all the childs
@@ -165,7 +201,7 @@ func (s *sharedEntryAttributes) toXmlInternal(parent *etree.Element, onlyNewOrUp
165201
newElem = parent
166202
}
167203
// recurse the call to all the children
168-
doAdd, err := s.childs[k].toXmlInternal(newElem, onlyNewOrUpdated, honorNamespace, operationWithNamespace, useOperationRemove, ordered)
204+
doAdd, err := s.childs[k].toXmlInternal(newElem, onlyNewOrUpdated, honorNamespace, operationWithNamespace, useOperationRemove, ordering)
169205
if err != nil {
170206
return false, err
171207
}

0 commit comments

Comments
 (0)