public query()

in uui-db/src/IxSet.ts [137:245]


    public query(query: DbQuery<TEntity>) {
        const filter: DataQueryFilter<TEntity> = query.filter || {};
        const filterFields = Object.keys(filter) as (keyof TEntity)[];
        const filterFieldTypes = {} as Record<keyof TEntity, FilterConditionType>;
        filterFields.forEach((f) => {
            const condition = filter[f] as DataQueryFilterCondition<any>;
            if (condition != null && typeof condition === 'object') {
                if (condition.in) {
                    filterFieldTypes[f] = FilterConditionType.Multi;
                }
            } else {
                filterFieldTypes[f] = FilterConditionType.Single;
            }
        });

        let plans = this.indexes
            .map((index) => {
                if (filterFieldTypes[index.fields[0]]) {
                    let matchCount = 0;
                    const from: IndexKey<TEntity> = { [ID]: -Infinity } as any;
                    const to: IndexKey<TEntity> = { [ID]: +Infinity } as any;
                    const lookupFields = {} as Record<keyof TEntity, boolean>;
                    let isRemainingUnused = false;

                    for (let i = 0; i < index.fields.length; i++) {
                        const field: keyof TEntity = index.fields[i];
                        if (!isRemainingUnused && filterFieldTypes[field] === FilterConditionType.Single) {
                            lookupFields[field] = true;
                            from[field] = filter[field] as any;
                            to[field] = filter[field] as any;
                            matchCount++;
                        } else {
                            isRemainingUnused = true;
                            from[field] = -Infinity as any;
                            to[field] = Infinity as any;
                        }
                    }

                    let remainingFilter: DataQueryFilter<TEntity> = null;
                    filterFields
                        .filter((f) => !lookupFields[f])
                        .forEach((f) => {
                            if (!remainingFilter) {
                                remainingFilter = {};
                            }
                            remainingFilter[f] = filter[f];
                        });

                    const score = matchCount;
                    if (matchCount > 0) {
                        return {
                            score, index, from, to, remainingFilter,
                        };
                    }
                }

                return null;
            })
            .filter((p) => p != null);

        plans = orderBy(plans, (plan) => plan.score, 'desc');
        const plan = plans[0];

        // const indexEntities = plan.index.tree.entries();

        let treeIterator: IterableIterator<TEntity>;

        if (plan) {
            const indexIterator = plan.index.tree.entries(plan.from);
            treeIterator = iterator(() => {
                const next = indexIterator.next() as any;
                if (!next.value) {
                    return next;
                }
                next.value = next.value[0];
                if (plan.index.compare(next.value, plan.to) > 0) {
                    next.done = true;
                    next.value = null;
                    return next;
                }
                next.value = this.pk.get(next.value[ID]);
                return next;
            });
        } else {
            treeIterator = this.pk.values();
        }

        const result: TEntity[] = [];

        const filterPredicate = getFilterPredicate(plan ? plan.remainingFilter : filter);

        let current;
        let index = 0;
        let count = 0;
        const rangeFrom = (query.range && query.range.from) || 0;
        const rangeCount = (query.range && query.range.count) || Number.MAX_SAFE_INTEGER;
        while (!(current = treeIterator.next()).done && count < rangeCount) {
            const entity: TEntity = current.value;
            const passedFilter = !filterPredicate || filterPredicate(entity);

            if (passedFilter && index >= rangeFrom) {
                result.push(entity);
                count++;
            }
            index++;
        }

        return result;
    }