in uui-db/src/DbTable.ts [173:263]
private runQuery(q: DataQuery<TEntity>) {
let result: TEntity[] = null;
let filter = q.filter;
if (filter) {
const indexes = this.state.indexes;
// Try to use indexes to fulfill filter conditions
for (let n = 0; n < indexes.length; n++) {
const index = indexes[n];
if (index.field in filter) {
const { [index.field]: condition, ...rest } = filter as any;
let conditionValues: any[] = null;
if (condition != null && typeof condition === 'object') {
// Attempt to use index for 'in' and 'isNull' criteria.
// We need to be very conservative here, indexed field should work the same way as getPatternPredicate. So
// - it's better to leave corner cases to getPatternPredicate
const { in: inCriteria, isNull: nullCriteria, ...restCriteria } = condition as any;
if (inCriteria && Array.isArray(inCriteria)) {
conditionValues = inCriteria;
} else {
restCriteria.in = inCriteria;
}
// Conditions in getPatternPredicate are composed with 'and' logic,
// For now, let's not attempt to handle tricky cases like { in: [1,2] isNull: true }, or { in: [1, null] isNull: false }
// - just leave this to getPatternPredicate.
// Let's just handle the a most common case { isNull: true } - find all null and undefined
if (nullCriteria === true && !conditionValues) {
conditionValues = [null, undefined];
} else {
restCriteria.in = inCriteria;
}
// Keep other conditions, e.g. { in: [1,2,3], isNull: true } - in works via index, isNull - via filter
if (Object.keys(restCriteria).length > 0) {
rest[index.field] = restCriteria;
}
} else {
conditionValues = [condition];
}
if (conditionValues) {
result = [];
for (let i = 0; i < conditionValues.length; i++) {
const idsSet = index.map.get(conditionValues[i]);
if (idsSet) {
const idsArray = idsSet.toArray();
for (let j = 0; j < idsArray.length; j++) {
const item = this.state.pk.get(idsArray[j]);
result.push(item);
}
}
}
filter = Object.keys(rest).length > 0 ? (rest as any) : null;
break;
}
}
}
}
if (!result) {
result = this.state.pk.toArray();
}
if (filter) {
const predicate = getFilterPredicate<TEntity>(q.filter);
result = result.filter(predicate);
}
if (q.search) {
const searchFilter = getSearchFilter(q.search);
result = result.filter((item) => searchFilter(this.schema.searchBy.map((field) => (item as any)[field])));
}
if (q.sorting) {
const comparer = getOrderComparer(q.sorting);
result = result.sort(comparer);
}
if (q.range) {
result = result.slice(q.range.from, q.range.from + q.range.count);
}
return result;
}