import { NestedCollectionFetchAllCollectionState } from './NestedCollectionFetchAllCollectionState'; import { QueryState, TaskState } from '@wix/bex-core'; import { EventEmitter } from 'events'; import { TypedEmitter } from '@wix/bex-core/events'; import { NestedCollectionState } from './NestedCollectionState'; import { action, computed, makeObservable } from 'mobx'; import { EagerLazyModeOptions } from './types'; export interface NestedCollectionFetchAllStateParams { readonly nestedCollectionState: NestedCollectionState; readonly query: QueryState<{}>; readonly options: EagerLazyModeOptions; } export class NestedCollectionFetchAllState { readonly nestedCollectionState; readonly events = new EventEmitter() as TypedEmitter<{ fetchAllAbortSignal: () => unknown; }>; readonly fetchedAllPromise; readonly options; readonly query; readonly initTask = new TaskState(); readonly collections: NestedCollectionFetchAllCollectionState[]; isFetchAllAborted = false; constructor(params: NestedCollectionFetchAllStateParams) { const { nestedCollectionState } = params; this.options = params.options; this.query = params.query; const { levels } = nestedCollectionState; this.nestedCollectionState = nestedCollectionState; this.fetchedAllPromise = new Promise((resolve) => { this.events.once('fetchAllAbortSignal', resolve); }); this.collections = levels.map((levelDescriptor) => { return new NestedCollectionFetchAllCollectionState({ levelDescriptor, fetchAllState: this, }); }); makeObservable(this, { total: computed, _setInitialExpandAllByThreshold: action, }); } init({ invalidate }: { invalidate: boolean } = { invalidate: false }) { const { initTask, fetchedAllPromise, nestedCollectionState, collections } = this; if (invalidate) { collections.forEach((c) => { c.collection.invalidate(); }); } const disposers = [...collections.map((c) => c.init())]; initTask.runOnce(async () => { collections.forEach(({ initTask }) => { initTask.runOnce(); }); const collectionsFetchAllPromise = Promise.all( collections.map((c) => c.initTask.status.promise), ); await Promise.race([collectionsFetchAllPromise, fetchedAllPromise]); nestedCollectionState.isFetchAllAborted = this.isFetchAllAborted; nestedCollectionState._fetchAllTotal = this.total; if (this.isFetchAllAborted) { nestedCollectionState.expandAll = false; // override expandAll to false if fetchAll was aborted } else { this._setInitialExpandAllByThreshold(); this._populateParentIdRequestsCache(); } }); return () => { disposers.forEach((d) => d()); }; } _setInitialExpandAllByThreshold() { const { nestedCollectionState, total, options: { expandAllThreshold }, } = this; nestedCollectionState.total = total; nestedCollectionState.expandAll = total <= expandAllThreshold; } _populateParentIdRequestsCache() { const { uniqueCollections } = this; uniqueCollections.forEach((c, index, arr) => { c._populateCache(arr[index + 1]); }); } get uniqueCollections() { const { collections } = this; return Array.from( collections .reduce((map, c) => { map.set(c.collection.getCurrentQuery(), c); return map; }, new Map>()) .values(), ); } get total() { const { uniqueCollections } = this; return uniqueCollections.reduce((acc, c) => { return acc + c.collection.result.total; }, 0); } _otherLevelSameCollectionExists( collection: NestedCollectionFetchAllCollectionState, ) { const { collections } = this; return collections.some((other) => { return ( other !== collection && other.collection.getCurrentQuery() === collection.collection.getCurrentQuery() ); }); } }