@@ -18,7 +18,6 @@ import (
1818 "encoding/json"
1919 "fmt"
2020 "net/http"
21- "reflect"
2221 "sort"
2322 "strconv"
2423 "strings"
@@ -28,6 +27,12 @@ import (
2827 "golang.org/x/net/context"
2928)
3029
30+ // QueryNode represents a data node retrieved from an ordered query.
31+ type QueryNode interface {
32+ Key () string
33+ Unmarshal (v interface {}) error
34+ }
35+
3136// Query represents a complex query that can be executed on a Ref.
3237//
3338// Complex queries can consist of up to 2 components: a required ordering constraint, and an
@@ -112,40 +117,23 @@ func (q *Query) Get(ctx context.Context, v interface{}) error {
112117 return resp .Unmarshal (http .StatusOK , v )
113118}
114119
115- // GetOrdered executes the Query and provides the results as an ordered list.
116- //
117- // v must be a pointer to an array or a slice. Only the child values returned by the query are
118- // unmarshalled into v. Top-level keys are not returned. Although if the Query was created using
119- // OrderByKey(), the returned values will still be ordered based on their keys.
120- func (q * Query ) GetOrdered (ctx context.Context , v interface {}) error {
121- rv := reflect .ValueOf (v )
122- if rv .Kind () != reflect .Ptr || rv .IsNil () {
123- return fmt .Errorf ("nil or not a pointer" )
124- }
125- if rv .Elem ().Kind () != reflect .Slice && rv .Elem ().Kind () != reflect .Array {
126- return fmt .Errorf ("non-array non-slice pointer" )
127- }
128-
120+ // GetOrdered executes the Query and returns the results as an ordered slice.
121+ func (q * Query ) GetOrdered (ctx context.Context ) ([]QueryNode , error ) {
129122 var temp interface {}
130123 if err := q .Get (ctx , & temp ); err != nil {
131- return err
124+ return nil , err
132125 }
133-
134126 if temp == nil {
135- return nil
127+ return nil , nil
136128 }
137- sr := newSortableQueryResult (temp , q .order )
138- sort .Sort (sr )
139129
140- var values []interface {}
141- for _ , val := range sr {
142- values = append (values , val .Value )
143- }
144- b , err := json .Marshal (values )
145- if err != nil {
146- return err
130+ sn := newSortableNodes (temp , q .order )
131+ sort .Sort (sn )
132+ result := make ([]QueryNode , len (sn ))
133+ for i , v := range sn {
134+ result [i ] = v
147135 }
148- return json . Unmarshal ( b , v )
136+ return result , nil
149137}
150138
151139// OrderByChild returns a Query that orders data by child values before applying filters.
@@ -307,14 +295,30 @@ func newComparableKey(v interface{}) *comparableKey {
307295 return & comparableKey {Num : & f }
308296}
309297
310- type queryResult struct {
311- Key * comparableKey
298+ type queryNodeImpl struct {
299+ CompKey * comparableKey
312300 Value interface {}
313301 Index interface {}
314302 IndexType int
315303}
316304
317- func newQueryResult (key , val interface {}, order orderBy ) * queryResult {
305+ func (q * queryNodeImpl ) Key () string {
306+ if q .CompKey .Str != nil {
307+ return * q .CompKey .Str
308+ }
309+ // Numeric keys in queryNodeImpl are always array indices, and can be safely coverted into int.
310+ return strconv .Itoa (int (* q .CompKey .Num ))
311+ }
312+
313+ func (q * queryNodeImpl ) Unmarshal (v interface {}) error {
314+ b , err := json .Marshal (q .Value )
315+ if err != nil {
316+ return err
317+ }
318+ return json .Unmarshal (b , v )
319+ }
320+
321+ func newQueryNode (key , val interface {}, order orderBy ) * queryNodeImpl {
318322 var index interface {}
319323 if prop , ok := order .(orderByProperty ); ok {
320324 if prop == "$value" {
@@ -326,25 +330,25 @@ func newQueryResult(key, val interface{}, order orderBy) *queryResult {
326330 path := order .(orderByChild )
327331 index = extractChildValue (val , string (path ))
328332 }
329- return & queryResult {
330- Key : newComparableKey (key ),
333+ return & queryNodeImpl {
334+ CompKey : newComparableKey (key ),
331335 Value : val ,
332336 Index : index ,
333337 IndexType : getIndexType (index ),
334338 }
335339}
336340
337- type sortableQueryResult []* queryResult
341+ type sortableNodes []* queryNodeImpl
338342
339- func (s sortableQueryResult ) Len () int {
343+ func (s sortableNodes ) Len () int {
340344 return len (s )
341345}
342346
343- func (s sortableQueryResult ) Swap (i , j int ) {
347+ func (s sortableNodes ) Swap (i , j int ) {
344348 s [i ], s [j ] = s [j ], s [i ]
345349}
346350
347- func (s sortableQueryResult ) Less (i , j int ) bool {
351+ func (s sortableNodes ) Less (i , j int ) bool {
348352 a , b := s [i ], s [j ]
349353 var aKey , bKey * comparableKey
350354 if a .IndexType == b .IndexType {
@@ -353,7 +357,7 @@ func (s sortableQueryResult) Less(i, j int) bool {
353357 if (a .IndexType == typeNumeric || a .IndexType == typeString ) && a .Index != b .Index {
354358 aKey , bKey = newComparableKey (a .Index ), newComparableKey (b .Index )
355359 } else {
356- aKey , bKey = a .Key , b .Key
360+ aKey , bKey = a .CompKey , b .CompKey
357361 }
358362 } else {
359363 // If the indices are of different types, use the type ordering of Firebase.
@@ -363,18 +367,18 @@ func (s sortableQueryResult) Less(i, j int) bool {
363367 return aKey .Compare (bKey ) < 0
364368}
365369
366- func newSortableQueryResult (values interface {}, order orderBy ) sortableQueryResult {
367- var entries sortableQueryResult
370+ func newSortableNodes (values interface {}, order orderBy ) sortableNodes {
371+ var entries sortableNodes
368372 if m , ok := values .(map [string ]interface {}); ok {
369373 for key , val := range m {
370- entries = append (entries , newQueryResult (key , val , order ))
374+ entries = append (entries , newQueryNode (key , val , order ))
371375 }
372376 } else if l , ok := values .([]interface {}); ok {
373377 for key , val := range l {
374- entries = append (entries , newQueryResult (key , val , order ))
378+ entries = append (entries , newQueryNode (key , val , order ))
375379 }
376380 } else {
377- entries = append (entries , newQueryResult (0 , values , order ))
381+ entries = append (entries , newQueryNode (0 , values , order ))
378382 }
379383 return entries
380384}
0 commit comments