Query
A Query represents a live view over a repository or another query, supporting:
-
Query chaining: Queries can be chained together, where one query's results become the input for another query. This allows building complex data transformations through composition.
-
Incremental updates: When the underlying data changes, queries automatically update their results. Changes propagate efficiently through query chains - only the affected results are recomputed rather than re-running the entire query.
-
Persistent caching: Results are continuously cached to disk, both during the initial linear scan and as the source data changes. This allows queries to be efficiently resumed after being suspended or closed, without having to re-scan the entire dataset.
-
Efficient indexing: When sorted by a field, queries act as persistent indexes enabling O(log n) lookups on that field. The index stays up-to-date as data changes and results are cached for immediate availability.
Query chaining example:
// Chain queries to find recent important todos
const importantTodos = new Query({
source: repo,
predicate: todo => todo.important
});
const recentImportant = new Query({
source: importantTodos,
predicate: todo => isRecent(todo.date)
});
You can also use queries as efficient indexes:
// Create an index over user emails
const usersByEmail = new Query({
source: '/sys/users',
schema: kSchemaUser,
sortBy: 'email'
});
// O(log n) lookup by email after index is built
await usersByEmail.loadingFinished();
const user = usersByEmail.find('email', 'user@example.com');
Extends: Emitter
Constructor
new Query(config: QueryConfig<IS, OS, CTX>)
Creates a new Query instance.
Methods
close()
close(): void
Closes this query and cleans up its resources. This:
- Emits a 'Closed' event
- Unregisters from query persistence to stop caching
- Removes source change listeners
- Marks the query as closed
Once closed, a query cannot be reopened. Create a new query instance instead.
entries()
entries(): Generator<Entry<OS>>
Returns a generator that yields key-value pairs for all items in the query results. Each entry contains the item's path key and its corresponding value.
find()
find(fieldName: keyof OS['fields'], value: SchemaDataType<OS>[keyof OS['fields']]): ManagedItem<OS, Schema>
Finds the first item in the query results where the specified field matches the given value. If the field is the sort field, uses binary search for O(log n) lookup. Otherwise performs a linear scan.
has()
has(path: string): boolean
Checks if a given path is included in the query results.
loadingFinished()
loadingFinished(): Promise<true>
Returns a promise that resolves to true when the query finishes loading its initial results. If loading is already finished, the promise resolves on the next event loop cycle.
onLoadingFinished()
onLoadingFinished(handler: () => void): () => void
Registers a callback to be invoked when the query finishes loading its initial results. If loading is already finished, the callback will be scheduled to run on the next event loop cycle.
onResultsChanged()
onResultsChanged(handler: () => void): () => void
Registers a callback to be invoked when the query results change due to updates in the underlying data source.
paths()
paths(): Iterable<string>
Gets an iterable of all paths included in the query results.
results()
results(): readonly ManagedItem<OS, Schema>[]
Gets the results of the query as an array of managed items. The returned items are mutable - any changes made to them will automatically trigger the query to update its results.
resume()
resume(): Promise<void>
suspend()
suspend(): void
valueForPath()
valueForPath(key: string): Item<OS>
Gets the item value for a given path key. The value is retrieved from the repository's committed head or temporary records.
Inherited Methods
From Emitter
attach()
, detach()
, detachAll()
, emit()
, mute()
, once()
, unmute()
See Emitter for detailed documentation