/** * Query Graph — cross-module reads that traverse {@link LinkDefinition}s. * * Modules expose {@link EntityFetcher}s for their entities. The graph * planner fetches base records, walks link definitions for any dotted * fields in the selection, issues parallel fetches for the linked * entities, and stitches the results in-memory. * * This is an application-layer join, not a SQL join: modules never * import one another's tables, and there are no database foreign keys * between module schemas. */ import type { LinkDefinition, LinkService } from "./links.js"; /** Filters applied to the underlying entity fetcher. */ export type QueryFilters = Record; /** Per-request hints threaded through cross-module reads. */ export type QueryContextValue = Record; export interface QueryPagination { skip?: number; take?: number; } /** Arguments passed to an {@link EntityFetcher}'s `list` method. */ export interface EntityFetcherArgs { filters?: QueryFilters; ids?: string[]; pagination?: QueryPagination; context?: QueryContextValue; } /** * A minimal record shape. Concrete module records can extend this with * additional fields; the query planner only requires `id` to join on. */ export type EntityRecord = Record & { id: string; }; /** * Per-entity data loader. Modules register one fetcher per entity they * want to expose to cross-module reads. * * Implementations MUST honour both the `filters`/`pagination` path * (top-level entity fetch) and the `ids` path (used to hydrate link * targets). When both are provided, `ids` takes precedence. */ export interface EntityFetcher { list(args: EntityFetcherArgs): Promise; } export interface QueryGraphConfig { /** Name of the entity to fetch. Must match a registered fetcher's key. */ entity: string; /** * Flat list of field paths to select. * * - `"id"`, `"title"` — scalar fields (ignored by the planner; honoured by the fetcher). * - `"products.*"` — traverses the `entity → products` link. * - `"organization.name"` — traverses the `entity → organization` link; only `name` is hydrated. * * Nested paths (`"products.categories.*"`) are NOT supported in the MVP. */ fields: string[]; filters?: QueryFilters; pagination?: QueryPagination; /** * Per-request runtime hints such as locale, market, actor, or pricing * context. The query planner passes this through unchanged to every * participating entity fetcher. */ context?: QueryContextValue; } export interface QueryGraphResult { data: EntityRecord[]; } /** * Callable query runtime exposed to routes and workflows. * * It wraps a fixed {@link QueryGraphContext} so callers only supply the * per-request graph config. */ export type QueryRunner = (config: QueryGraphConfig) => Promise; export interface QueryGraphContext { /** Entity name → fetcher. */ fetchers: Map; /** Known cross-module link definitions. */ links: LinkDefinition[]; /** Runtime link service (pivot table reads). */ linkService: LinkService; } /** * Build a {@link QueryGraphContext} from plain records. */ export declare function createQueryContext(fetchers: Record, links: LinkDefinition[], linkService: LinkService): QueryGraphContext; /** * Wrap a fixed {@link QueryGraphContext} in a callable runtime. */ export declare function createQueryRunner(ctx: QueryGraphContext): QueryRunner; /** * Execute a cross-module read. * * @example * ```ts * const { data } = await queryGraph(ctx, { * entity: "person", * fields: ["id", "name", "product.*", "organization.name"], * filters: { country: "FR" }, * pagination: { take: 50 }, * }) * // data[0].product === [{ id: "prod_...", ... }, ...] * // data[0].organization === { id: "org_...", name: "..." } | null * ``` */ export declare function queryGraph(ctx: QueryGraphContext, config: QueryGraphConfig): Promise; //# sourceMappingURL=query.d.ts.map