InMemorySortFallback returns a query fallback function for Options.RunQueryFallback. The function accepts a query with an OrderBy clause. It runs the query without that clause, reading all documents into memory, then sorts the documents according to the OrderBy clause. Only string, numeric, time an
(createDocument func() any)
| 545 | // The DocumentIterator returned by the FallbackFunc will also expect the same type of document. |
| 546 | // If nil, then a map[string]interface{} will be used. |
| 547 | func InMemorySortFallback(createDocument func() any) FallbackFunc { |
| 548 | if createDocument == nil { |
| 549 | createDocument = func() any { return map[string]any{} } |
| 550 | } |
| 551 | return func(ctx context.Context, q *driver.Query, run RunQueryFunc) (driver.DocumentIterator, error) { |
| 552 | if q.OrderByField == "" { |
| 553 | return nil, errors.New("InMemorySortFallback expects an OrderBy query") |
| 554 | } |
| 555 | // Run the query without the OrderBy. |
| 556 | orderByField := q.OrderByField |
| 557 | q.OrderByField = "" |
| 558 | iter, err := run(ctx, q) |
| 559 | if err != nil { |
| 560 | return nil, err |
| 561 | } |
| 562 | defer iter.Stop() |
| 563 | // Collect the results into a slice. |
| 564 | var docs []driver.Document |
| 565 | for { |
| 566 | doc, err := driver.NewDocument(createDocument()) |
| 567 | if err != nil { |
| 568 | return nil, err |
| 569 | } |
| 570 | err = iter.Next(ctx, doc) |
| 571 | if err == io.EOF { |
| 572 | break |
| 573 | } |
| 574 | if err != nil { |
| 575 | return nil, err |
| 576 | } |
| 577 | docs = append(docs, doc) |
| 578 | } |
| 579 | // Sort the documents. |
| 580 | // OrderByField is a single field, not a field path. |
| 581 | // First, put the field values in another slice, so we can |
| 582 | // return on error. |
| 583 | sortValues := make([]any, len(docs)) |
| 584 | for i, doc := range docs { |
| 585 | v, err := doc.GetField(orderByField) |
| 586 | if err != nil { |
| 587 | return nil, err |
| 588 | } |
| 589 | sortValues[i] = v |
| 590 | } |
| 591 | sort.Sort(docsForSorting{docs, sortValues, q.OrderAscending}) |
| 592 | return &sliceIterator{docs: docs}, nil |
| 593 | } |
| 594 | } |
| 595 | |
| 596 | type docsForSorting struct { |
| 597 | docs []driver.Document |