* Executes the query and returns projected ResourceViews. `.where(...)` * predicates may reference source-derived fields, so they force the slow * path: fetch the full view, filter, then sort/limit. Without `.where`, * sort/offset/limit are pushed into `executeQuery` so source is read only
()
| 592 | * for the surviving slice. |
| 593 | */ |
| 594 | toArray(): ResourceView[] { |
| 595 | const userSelect = (this._descriptor.select ?? DEFAULT_SELECT).map( |
| 596 | normalizeSelectEntry |
| 597 | ); |
| 598 | const userFields = userSelect.map(e => e.field); |
| 599 | |
| 600 | if (this._jsPredicates.length === 0) { |
| 601 | return executeQuery( |
| 602 | { |
| 603 | filter: this._descriptor.filter, |
| 604 | select: userSelect, |
| 605 | sort: this._descriptor.sort, |
| 606 | offset: this._descriptor.offset, |
| 607 | limit: this._descriptor.limit, |
| 608 | }, |
| 609 | this.workspace, |
| 610 | this.graph, |
| 611 | { trusted: this.trusted, readSource: this.readSource } |
| 612 | ).results; |
| 613 | } |
| 614 | |
| 615 | const sourceDerived = userFields.filter(requiresSource); |
| 616 | const fullSelect: SelectEntry[] = [ |
| 617 | ...ALL_QUERY_FIELDS.map(f => ({ field: f, label: f })), |
| 618 | ...sourceDerived.map(f => ({ field: f, label: f })), |
| 619 | ]; |
| 620 | let results = executeQuery( |
| 621 | { |
| 622 | filter: this._descriptor.filter, |
| 623 | select: fullSelect, |
| 624 | }, |
| 625 | this.workspace, |
| 626 | this.graph, |
| 627 | { trusted: this.trusted, readSource: this.readSource } |
| 628 | ).results; |
| 629 | |
| 630 | for (const pred of this._jsPredicates) { |
| 631 | try { |
| 632 | results = results.filter(pred); |
| 633 | } catch (e) { |
| 634 | Logger.warn(`[foam-query] JS predicate error: ${e}`); |
| 635 | } |
| 636 | } |
| 637 | |
| 638 | if (this._descriptor.sort) { |
| 639 | const { field, direction } = parseSortDescriptor(this._descriptor.sort); |
| 640 | results = [...results].sort((a, b) => { |
| 641 | const cmp = compareValues(a[field], b[field]); |
| 642 | return direction === 'desc' ? -cmp : cmp; |
| 643 | }); |
| 644 | } |
| 645 | |
| 646 | const offsetN = this._descriptor.offset ?? 0; |
| 647 | if (offsetN > 0) results = results.slice(offsetN); |
| 648 | if (this._descriptor.limit !== undefined) |
| 649 | results = results.slice(0, this._descriptor.limit); |
| 650 | |
| 651 | return results.map(r => { |
no test coverage detected