import type { ScanOptions } from '../kv-storage/base-kv-storage.js' import { Keys } from './keys.js' /** * A key and its whole subtree: `[prefix, prefix + '0')`. Escaping guarantees nothing else sorts * in that range (not even lookalikes such as `prefix-x`). The empty prefix is every key. */ export class KeyRange { /** Inclusive lower bound (`undefined` = unbounded). */ readonly gte: string | undefined /** Exclusive upper bound (`undefined` = unbounded). */ readonly lt: string | undefined constructor(readonly prefix: string) { this.gte = prefix === '' ? undefined : prefix this.lt = prefix === '' ? undefined : prefix + Keys.afterSeparator } contains(key: string): boolean { return this.prefix === '' || key === this.prefix || key.startsWith(this.prefix + Keys.separator) } /** Whether a scan over `[gte, lt)` stays inside this range. */ covers(gte: string | undefined, lt: string | undefined): boolean { if (this.prefix === '') return true return gte !== undefined && lt !== undefined && gte >= this.gte! && lt <= this.lt! } /** Scan options narrowed to this range, or `undefined` if nothing is left. */ clamp(options: ScanOptions): ScanOptions | undefined { const gte = this.gte !== undefined && (options.gte === undefined || options.gte < this.gte) ? this.gte : options.gte const lt = this.lt !== undefined && (options.lt === undefined || options.lt > this.lt) ? this.lt : options.lt if (gte !== undefined && lt !== undefined && gte >= lt) return undefined return { ...options, gte, lt } } }