UNPKG

@signaldb/core

Version:

SignalDB is a client-side database that provides a simple MongoDB-like interface to the data with first-class typescript support to achieve an optimistic UI. Data persistence can be achieved by using storage providers that store the data through a JSON in

99 lines (98 loc) 3.88 kB
import intersection from "./index17.mjs"; //#region src/Collection/getIndexInfo.ts /** * Retrieves merged index information for a given flat selector by querying multiple * index providers. Combines results from all index providers to determine matched positions * and an optimized selector. * @template T - The type of the items in the collection. * @template I - The type of the unique identifier for the items. * @param indexProviders - An array of index providers to query. * @param selector - The flat selector used to filter items. * @returns An object containing: * - `matched`: A boolean indicating if the selector matched any items. * - `positions`: An array of matched item positions. * - `optimizedSelector`: A flat selector optimized based on the index results. */ function getMergedIndexInfo(indexProviders, selector) { return indexProviders.reduce((memo, indexProvider) => { const info = indexProvider.query(selector); if (!info.matched) return memo; const optimizedSelector = info.keepSelector ? memo.optimizedSelector : Object.fromEntries(Object.entries(memo.optimizedSelector).filter(([key]) => !info.fields.includes(key))); return { matched: true, positions: [...new Set(memo.matched ? intersection(memo.positions, info.positions) : info.positions)], optimizedSelector }; }, { matched: false, positions: [], optimizedSelector: { ...selector } }); } /** * Retrieves index information for a given complex selector by querying multiple * index providers. Handles nested `$and` and `$or` conditions in the selector and * optimizes the selector to minimize processing overhead. * @template T - The type of the items in the collection. * @template I - The type of the unique identifier for the items. * @param indexProviders - An array of index providers to query. * @param selector - The complex selector used to filter items. * @returns An object containing: * - `matched`: A boolean indicating if the selector matched any items. * - `positions`: An array of matched item positions. * - `optimizedSelector`: A selector optimized based on the index results, with unused * conditions removed. */ function getIndexInfo(indexProviders, selector) { if (selector == null || Object.keys(selector).length <= 0) return { matched: false, positions: [], optimizedSelector: selector }; const { $and, $or, ...rest } = selector; const flatInfo = getMergedIndexInfo(indexProviders, rest); let { matched, positions } = flatInfo; const newSelector = flatInfo.optimizedSelector; if (Array.isArray($and)) { const $andNew = []; for (const sel of $and) { const { matched: selMatched, positions: selPositions, optimizedSelector } = getIndexInfo(indexProviders, sel); if (selMatched) { positions = matched ? intersection(positions, selPositions) : selPositions; matched = true; if (Object.keys(optimizedSelector).length > 0) $andNew.push(optimizedSelector); } else $andNew.push(sel); } if ($andNew.length > 0) newSelector.$and = $andNew; } if (Array.isArray($or)) { const $orNew = []; const matchedBefore = matched; const positionsBefore = positions; let hasNonIndexField = false; for (const sel of $or) { const { matched: selMatched, positions: selPositions, optimizedSelector } = getIndexInfo(indexProviders, sel); if (selMatched) { positions = [...new Set([...positions, ...selPositions])]; matched = true; if (Object.keys(optimizedSelector).length > 0) $orNew.push(optimizedSelector); } else { $orNew.push(sel); hasNonIndexField = true; } } if ($orNew.length > 0) newSelector.$or = $orNew; if (hasNonIndexField) { newSelector.$or = $or; matched = matchedBefore; positions = positionsBefore; } } return { matched, positions: positions || [], optimizedSelector: newSelector }; } //#endregion export { getIndexInfo as default };