feat: reduce round trips for bulk and schema-checked reads - #683
Merged
Conversation
Merged
pdlug
added a commit
that referenced
this pull request
Sep 11, 2026
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @nicia-ai/typegraph@0.58.0 ### Highlights TypeGraph 0.58 reduces database round trips in graph read paths. `store.bulkFindEdgesTo` and its pinned-view counterpart resolve inbound edges for a set of targets across node and edge kinds, mirroring `bulkFindEdgesFrom`. Callers can replace per-target lookups with a set-oriented read while retaining input order, repeated and empty target buckets, temporal visibility, and per-input limits. For a single edge kind, the existing `edges.Kind.bulkFindTo` remains available. Whole-node and whole-edge selections now choose a full-row fetch before executing SQL, including nested and spread selections detected during planning. Previously, a fresh query instance could issue a projected query, discover that the selector needed the complete entity, and fetch again. These selections now avoid that extra statement without requiring applications to retain query instances between requests. Selectors whose field needs depend on row values keep the existing fallback. `executeChecked(expectedSchemaVersion)` combines a relational read with an active schema-version check in one statement snapshot. It offers an explicit alternative to probing the committed version before fetching data: a mismatch raises `SchemaChangedError` before the selector runs, even when the query returns no rows. Applications can then reload the schema and rebuild the query before retrying. The check covers that statement; it does not pin later reads in the request or replace write fences. ### Upgrade notes - Update hand-built `Store` mocks and wrappers exposing the full store surface with `bulkFindEdgesTo`; query wrappers exposing the full executable-query surface must also forward `executeChecked`. Library-created stores, pinned views, and queries provide the new methods automatically. - When adopting `executeChecked`, catch `SchemaChangedError`, reload the reconciled schema, and rebuild the query before retrying. Start a new transaction if the old transaction holds a repeatable-read snapshot. An expected version of `undefined` means no active schema and is distinct from version zero. - Use checked reads for relational queries with ordinary bound values. They fetch full rows and support traversals, ordering, offsets, and limits; recursive and relevance-ranked queries require a separate schema probe. Replace named `param()` references with bound values before building a checked query. - Custom backends adopting checked reads must supply `tableNames.schemaVersions`, naming a relation with `graph_id`, `version`, and `is_active` columns whose active row agrees with `getActiveSchema`. A missing binding raises `ConfigurationError` before SQL execution. Bundled SQLite and PostgreSQL backends supply it automatically; this release requires no database migration. ### Minor Changes - [#683](#683) [`ce35043`](ce35043) Thanks [@pdlug](https://github.com/pdlug)! - Add `store.bulkFindEdgesTo` and its pinned-view counterpart for set-oriented inbound reads across edge kinds. Detect whole-node and whole-edge selections before issuing a projected query, avoiding a redundant fetch for fresh query instances. Add `executeChecked(expectedSchemaVersion)` for a relational read and committed-schema check in one statement, with `SchemaChangedError` on mismatch, including empty results. --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Paul Dlug <paul@nicia.ai>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Graph reads can spend extra round trips resolving inbound edges, retrying projected selections, and probing schema freshness before fetching data. This adds set-oriented reverse reads and an explicit schema-checked read API, and plans whole-entity selections before execution.
store.bulkFindEdgesToand its pinned-view counterpart mirrorbulkFindEdgesFrom, grouping inbound edges by target across node and edge kinds. They share the existing endpoint-set implementation and preserve input ordering, repeated and empty buckets, temporal visibility, and per-input limits. The existing single-kindedges.Kind.bulkFindToremains available.Selectors returning whole nodes or edges, including nested and spread selections, choose full rows before issuing SQL. This avoids the projected-query/full-fetch retry for fresh query instances. Data-dependent selectors retain the existing fallback when their runtime field needs cannot be inferred ahead of execution.
executeChecked(expectedSchemaVersion)reads relational results and the active schema version in one statement snapshot. It throwsSchemaChangedErrorbefore invoking the selector on a mismatch, including empty results, so callers can reload the schema, rebuild the query, and retry. Bundled backends expose the schema-version table binding; custom backends without it are refused. Checked reads use full projections and reject recursive and relevance-ranked queries. They check one statement without changing store-open caching or write-fence semantics.Documentation also shows the existing ordered traversal with
LIMIT 1for fetching the newest target in one statement. A minor changeset records the additive APIs.The compatibility ledger records exact exceptions for the additive methods on library-created handles and the new reverse-read parameter type. Existing custom backend implementations gain no required members.
Closes #684