-
Notifications
You must be signed in to change notification settings - Fork 0
/
x_document.go
164 lines (132 loc) · 4.2 KB
/
x_document.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
package birch
import (
"sort"
"github.com/tychoish/birch/bsonerr"
"github.com/tychoish/birch/bsontype"
)
// MarshalDocument satisfies the DocumentMarshaler interface, and
// returns the document itself.
func (d *Document) MarshalDocument() (*Document, error) { return d, nil }
// UnmarshalDocument satisfies the DocumentUnmarshaler interface and
// appends the elements of the input document to the underlying
// document. If the document is populated this could result in a
// document that has multiple identical keys.
func (d *Document) UnmarshalDocument(in *Document) error {
iter := in.Iterator()
for iter.Next(iterCtx) {
d.Append(iter.Value())
}
return iter.Close()
}
// ExportMap converts the values of the document to a map of strings
// to interfaces, recursively, using the Value.Interface() method.
func (d *Document) ExportMap() map[string]any {
out := make(map[string]any, d.Len())
iter := d.Iterator()
for iter.Next(iterCtx) {
elem := iter.Value()
out[elem.Key()] = elem.Value().Interface()
}
return out
}
// Elements is a representation of a slice of elements, and implements
// the sort.Interface to support ordering the keys of a document.
type Elements []*Element
func (c Elements) Len() int { return len(c) }
func (c Elements) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c Elements) Less(i, j int) bool {
ik := c[i].Key()
jk := c[j].Key()
if ik != jk {
return ik < jk
}
it := c[i].value.Type()
jt := c[j].value.Type()
if it != jt {
return it < jt
}
switch it {
case bsontype.Double:
return c[i].Value().Double() < c[j].Value().Double()
case bsontype.String:
return c[i].Value().StringValue() < c[j].Value().StringValue()
case bsontype.ObjectID:
return c[i].Value().ObjectID().Hex() < c[j].Value().ObjectID().Hex()
case bsontype.DateTime:
return c[i].Value().Time().Before(c[j].Value().Time())
case bsontype.Int32:
return c[i].Value().Int32() < c[j].Value().Int32()
case bsontype.Int64:
return c[i].Value().Int64() < c[j].Value().Int64()
default:
return false
}
}
// Copy returns a new Elements slice with the same underlying
// Elements. The copy is "shallow."
func (c Elements) Copy() Elements {
out := make(Elements, len(c))
for idx := range c {
out[idx] = c[idx]
}
return out
}
// Elements provides access to a slice of the Elements in the
// document. Mutating this list will mutate the content of the
// document.
func (d *Document) Elements() Elements {
return d.elems
}
// Sorted returns a new document containing a (shallow copy) of the
// elements from the source document ordered according to their value.
func (d *Document) Sorted() *Document {
elems := d.Elements().Copy()
sort.Stable(elems)
return DC.Elements(elems...)
}
// LookupElement iterates through the elements in a document looking
// for one with the correct key and returns that element. It is NOT
// recursive. When the element is not defined, the return value
// is nil.
func (d *Document) LookupElement(key string) *Element {
iter := d.Iterator()
for iter.Next(iterCtx) {
elem := iter.Value()
if elem.Key() == key {
return elem
}
}
return nil
}
// Lookup iterates through the elements in a document looking
// for one with the correct key and returns the value for that key. It
// is NOT recursive. When the element is not present.
func (d *Document) Lookup(key string) *Value {
elem := d.LookupElement(key)
if elem == nil {
return nil
}
return elem.value
}
// LookupElementErr iterates through the elements in a document looking
// for one with the correct key and returns the Element for that key. It
// is NOT recursive. When the element is not defined, it returns a
// ElementNotFound error.
func (d *Document) LookupElementErr(key string) (*Element, error) {
elem := d.LookupElement(key)
if elem == nil {
return nil, bsonerr.ElementNotFound
}
return elem, nil
}
// LookupErr iterates through the elements in a document looking
// for one with the correct key and returns the value for that key. It
// is NOT recursive. When the element is not defined, it returns a
// ElementNotFound error.
func (d *Document) LookupErr(key string) (*Value, error) {
elem := d.LookupElement(key)
if elem == nil {
return nil, bsonerr.ElementNotFound
}
return elem.value, nil
}