* Performs a range query with options * This is more efficient for compound queries like "WHERE a > 5 AND a < 10"
(options: RangeQueryOptions = {})
| 230 | * This is more efficient for compound queries like "WHERE a > 5 AND a < 10" |
| 231 | */ |
| 232 | rangeQuery(options: RangeQueryOptions = {}): Set<TKey> { |
| 233 | const { from, to, fromInclusive = true, toInclusive = true } = options |
| 234 | const result = new Set<TKey>() |
| 235 | |
| 236 | // Check if from/to were explicitly provided (even if undefined) |
| 237 | // vs not provided at all (should use min/max key) |
| 238 | const hasFrom = `from` in options |
| 239 | const hasTo = `to` in options |
| 240 | |
| 241 | const fromKey = hasFrom |
| 242 | ? normalizeForBTree(from) |
| 243 | : this.orderedEntries.minKey() |
| 244 | const toKey = hasTo ? normalizeForBTree(to) : this.orderedEntries.maxKey() |
| 245 | |
| 246 | this.orderedEntries.forRange( |
| 247 | fromKey, |
| 248 | toKey, |
| 249 | toInclusive, |
| 250 | (indexedValue, _) => { |
| 251 | // Only exclude the boundary when an exclusive lower bound was |
| 252 | // actually provided. Without a `from` bound, `fromKey` defaults to |
| 253 | // the minimum key and must not be dropped. Compare against the |
| 254 | // normalized key since indexed values are stored normalized |
| 255 | // (e.g. dates as timestamps), so the raw `from` would never match. |
| 256 | if ( |
| 257 | hasFrom && |
| 258 | !fromInclusive && |
| 259 | this.compareFn(indexedValue, fromKey) === 0 |
| 260 | ) { |
| 261 | // the B+ tree `forRange` method does not support exclusive lower bounds |
| 262 | // so we need to exclude it manually |
| 263 | return |
| 264 | } |
| 265 | |
| 266 | const keys = this.valueMap.get(indexedValue) |
| 267 | if (keys) { |
| 268 | keys.forEach((key) => result.add(key)) |
| 269 | } |
| 270 | }, |
| 271 | ) |
| 272 | |
| 273 | return result |
| 274 | } |
| 275 | |
| 276 | /** |
| 277 | * Performs a reversed range query |