Skip to content
This repository was archived by the owner on Nov 4, 2024. It is now read-only.

Commit 85c0367

Browse files
authored
Merge pull request #36 from neuronlabs/develop
Added `OrderedFields`
2 parents 34afe09 + c83f2c2 commit 85c0367

File tree

4 files changed

+197
-0
lines changed

4 files changed

+197
-0
lines changed

mapping/structfield.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package mapping
33
import (
44
"net/url"
55
"reflect"
6+
"sort"
67
"strings"
78

89
"github.com/neuronlabs/errors"
@@ -701,3 +702,46 @@ func (f FieldKind) String() string {
701702
}
702703
return "Unknown"
703704
}
705+
706+
var _ sort.Interface = OrderedFields{}
707+
708+
// OrderedFields is the wrapper over the slice of struct fields that allows to keep the fields
709+
// in an ordered sorting. The sorts is based on the fields index.
710+
type OrderedFields []*StructField
711+
712+
// Insert inserts the field into an ordered fields slice. In order to insert the field
713+
// a pointer to ordered fields must be used.
714+
func (o *OrderedFields) Insert(field *StructField) {
715+
for i, in := range *o {
716+
if !o.less(in, field) {
717+
(*o) = append((*o)[:i], append([]*StructField{field}, (*o)[i:]...)...)
718+
break
719+
}
720+
}
721+
}
722+
723+
// Len implements sort.Interface interface.
724+
func (o OrderedFields) Len() int {
725+
return len(o)
726+
}
727+
728+
// Less implements sort.Interface interface.
729+
func (o OrderedFields) Less(i, j int) bool {
730+
return o.less(o[i], o[j])
731+
}
732+
733+
// Swap implements sort.Interface interface.
734+
func (o OrderedFields) Swap(i, j int) {
735+
o[i], o[j] = o[j], o[i]
736+
}
737+
738+
func (o OrderedFields) less(first, second *StructField) bool {
739+
var result bool
740+
for k := 0; k < len(first.fieldIndex); k++ {
741+
if first.fieldIndex[k] != second.fieldIndex[k] {
742+
result = first.fieldIndex[k] < second.fieldIndex[k]
743+
break
744+
}
745+
}
746+
return result
747+
}

mapping/structfield_test.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package mapping
2+
3+
import (
4+
"sort"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
"github.com/stretchr/testify/require"
9+
)
10+
11+
// TestOrderedFields tests the ordered fields methods.
12+
func TestOrderedFields(t *testing.T) {
13+
type Model struct {
14+
ID int
15+
Name string
16+
First string
17+
Second int
18+
Third string
19+
}
20+
mm := testingModelMap(t)
21+
22+
err := mm.RegisterModels(Model{})
23+
require.NoError(t, err)
24+
25+
m, err := mm.GetModelStruct(Model{})
26+
require.NoError(t, err)
27+
28+
fields := m.Fields()
29+
30+
// unsort the slice
31+
fields[0], fields[3], fields[2], fields[4] = fields[3], fields[0], fields[4], fields[2]
32+
33+
// Remove the 'Name' field at index [1]
34+
fields = append(fields[:1], fields[2:]...)
35+
36+
ordered := OrderedFields(fields)
37+
// sort the fields
38+
sort.Sort(ordered)
39+
40+
for i, field := range ordered {
41+
switch i {
42+
case 0:
43+
assert.Equal(t, "ID", field.Name())
44+
case 1:
45+
assert.Equal(t, "First", field.Name())
46+
case 2:
47+
assert.Equal(t, "Second", field.Name())
48+
case 3:
49+
assert.Equal(t, "Third", field.Name())
50+
}
51+
}
52+
53+
// insert back the name field
54+
nameField, ok := m.Attribute("Name")
55+
require.True(t, ok)
56+
57+
orderedPtr := &ordered
58+
orderedPtr.Insert(nameField)
59+
60+
assert.Len(t, ordered, 5)
61+
62+
for i, field := range ordered {
63+
switch i {
64+
case 0:
65+
assert.Equal(t, "ID", field.Name())
66+
case 1:
67+
assert.Equal(t, "Name", field.Name())
68+
case 2:
69+
assert.Equal(t, "First", field.Name())
70+
case 3:
71+
assert.Equal(t, "Second", field.Name())
72+
case 4:
73+
assert.Equal(t, "Third", field.Name())
74+
}
75+
}
76+
77+
}

query/scope-fieldset.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package query
22

33
import (
44
"reflect"
5+
"sort"
56

67
"github.com/neuronlabs/errors"
78

@@ -10,6 +11,18 @@ import (
1011
"github.com/neuronlabs/neuron-core/mapping"
1112
)
1213

14+
// OrderedFieldset gets the fieldset fields sorted by the struct field's index.
15+
func (s *Scope) OrderedFieldset() (ordered mapping.OrderedFields) {
16+
var i int
17+
ordered = mapping.OrderedFields(make([]*mapping.StructField, len(s.Fieldset)))
18+
for _, field := range s.Fieldset {
19+
ordered[i] = field
20+
i++
21+
}
22+
sort.Sort(ordered)
23+
return ordered
24+
}
25+
1326
// InFieldset checks if the provided field is in the scope's fieldset.
1427
func (s *Scope) InFieldset(field interface{}) (*mapping.StructField, bool) {
1528
switch fv := field.(type) {

query/scope-fieldset_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package query
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
"github.com/stretchr/testify/require"
8+
)
9+
10+
// TestOrderedFielset test the ordered fieldset function.
11+
func TestOrderedFielset(t *testing.T) {
12+
type Ordered struct {
13+
ID int
14+
First string
15+
Second string
16+
Third string
17+
}
18+
19+
c := newController(t)
20+
err := c.RegisterModels(Ordered{})
21+
require.NoError(t, err)
22+
23+
t.Run("All", func(t *testing.T) {
24+
s, err := NewC(c, &Ordered{})
25+
require.NoError(t, err)
26+
27+
s.setAllFields()
28+
29+
ordered := s.OrderedFieldset()
30+
for i, field := range ordered {
31+
switch i {
32+
case 0:
33+
assert.Equal(t, "ID", field.Name())
34+
case 1:
35+
assert.Equal(t, "First", field.Name())
36+
case 2:
37+
assert.Equal(t, "Second", field.Name())
38+
case 3:
39+
assert.Equal(t, "Third", field.Name())
40+
}
41+
}
42+
})
43+
44+
t.Run("Custom", func(t *testing.T) {
45+
s, err := NewC(c, &Ordered{})
46+
require.NoError(t, err)
47+
48+
err = s.SetFields("first", "id", "third")
49+
require.NoError(t, err)
50+
51+
ordered := s.OrderedFieldset()
52+
for i, field := range ordered {
53+
switch i {
54+
case 0:
55+
assert.Equal(t, "ID", field.Name())
56+
case 1:
57+
assert.Equal(t, "First", field.Name())
58+
case 2:
59+
assert.Equal(t, "Third", field.Name())
60+
}
61+
}
62+
})
63+
}

0 commit comments

Comments
 (0)