{"_id":"@data-prism/query-helpers","name":"@data-prism/query-helpers","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.1":{"name":"@data-prism/query-helpers","version":"0.1.1","deprecated":"This package has been renamed to '@spectragraph/query-helpers'. Please use '@spectragraph/query-helpers' instead.","type":"module","main":"./dist/index.cjs.js","module":"./dist/index.esm.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.esm.js","require":"./dist/index.cjs.js"}},"scripts":{"build":"npm run clean && rollup -c && cp index.d.ts dist/","clean":"rm -rf dist","format:check":"prettier --check \"{src,test}/**/*.{js,jsx,ts,tsx,json,css,md}\"","format:fix":"prettier --write \"{src,test}/**/*.{js,jsx,ts,tsx,json,css,md}\"","lint":"eslint src/ test/","lint:fix":"eslint --fix src/ test/","test":"NODE_ENV=test vitest run --coverage","test:watch":"vitest"},"keywords":[],"author":{"name":"Jake Sower"},"devDependencies":{"@rollup/plugin-commonjs":"^28.0.1","@rollup/plugin-json":"^6.1.0","@rollup/plugin-node-resolve":"^16.0.0","@vitest/coverage-istanbul":"^3.0.4","@vitest/coverage-v8":"^3.2.4","rollup":"^4.28.1","vitest":"^3.0.4"},"publishConfig":{"access":"public"},"private":false,"sideEffects":false,"dependencies":{"@data-prism/utils":"*","es-toolkit":"^1.26.0","json-expressions":"^0.2.1"},"_id":"@data-prism/query-helpers@0.1.1","gitHead":"d90da54a8b4c84ca0cde531e924f44836e9be871","description":"Utility functions for working with Data Prism queries. This package provides helper functions for query traversal, multi-API execution, and query analysis across different store implementations.","_nodeVersion":"22.18.0","_npmVersion":"10.9.3","dist":{"integrity":"sha512-okhbl3rvcAsepcMnET5ov6l9lPBr0vKptaaxicbfSlZpjDIwNXZ47zH+ejsqj+bjiI97s0DH9cp+CUEAB69ekg==","shasum":"73c010876b8822744dd9bb1f8ba76c3b40a98e6a","tarball":"https://registry.npmjs.org/@data-prism/query-helpers/-/query-helpers-0.1.1.tgz","fileCount":5,"unpackedSize":26613,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDnur/M5cvpxjCquLz9mCdubqEaqa2d9pzM0IQiLuzz4AiBojTvMj3pvT0iZ2pBnx4Gt/FxDjaKi1MXSq1TeTCAAmQ=="}]},"_npmUser":{"name":"blossomlib","email":"kind.salt4683@fastmail.com"},"directories":{},"maintainers":[{"name":"blossomlib","email":"kind.salt4683@fastmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/query-helpers_0.1.1_1757801723944_0.45770710271235515"},"_hasShrinkwrap":false}},"time":{"created":"2025-09-13T22:15:23.842Z","0.1.1":"2025-09-13T22:15:24.150Z","modified":"2025-09-13T22:15:24.468Z"},"maintainers":[{"name":"blossomlib","email":"kind.salt4683@fastmail.com"}],"description":"Utility functions for working with Data Prism queries. This package provides helper functions for query traversal, multi-API execution, and query analysis across different store implementations.","keywords":[],"author":{"name":"Jake Sower"},"readme":"# Data Prism Query Helpers\n\nUtility functions for working with Data Prism queries. This package provides helper functions for query traversal, multi-API execution, and query analysis across different store implementations.\n\n## Overview\n\nData Prism Query Helpers provides tools for:\n\n- **Query Traversal**: Flatten and iterate over nested query structures\n- **Multi-API Execution**: Coordinate multiple APIs to fulfill complex queries\n- **Query Analysis**: Inspect and manipulate query structures programmatically\n\n## Installation\n\n```bash\nnpm install @data-prism/query-helpers\n```\n\n## Core Concepts\n\n### Query Flattening\n\nQuery helpers can flatten nested queries into linear arrays of query breakdown items, making it easier to process complex relationships and analyze query structures.\n\n### Multi-API Coordination\n\nThe package provides utilities for executing queries that span multiple APIs or data sources, handling the coordination and graph merging automatically.\n\n## API Reference\n\n### Query Traversal Functions\n\n#### `flattenQuery(schema, rootQuery)`\n\nFlattens a nested query into a linear array of query breakdown items.\n\n**Parameters:**\n\n- `schema` (Schema) - The schema defining relationships\n- `rootQuery` (RootQuery) - The root query to flatten\n\n**Returns:** QueryBreakdown - Array of flattened query breakdown items\n\n```javascript\nimport { flattenQuery } from \"@data-prism/query-helpers\";\n\nconst breakdown = flattenQuery(schema, {\n\ttype: \"teams\",\n\tselect: {\n\t\tname: \"name\",\n\t\thomeMatches: {\n\t\t\tselect: {\n\t\t\t\tfield: \"field\",\n\t\t\t\tawayTeam: { select: [\"name\"] },\n\t\t\t},\n\t\t},\n\t},\n});\n\n// Returns array with separate items for teams, matches, and related teams\nconsole.log(breakdown.map((item) => item.type)); // [\"teams\", \"matches\", \"teams\"]\n```\n\n#### `flatMapQuery(schema, query, fn)`\n\nMaps over each query in a flattened query structure.\n\n**Parameters:**\n\n- `schema` (Schema) - The schema defining relationships\n- `query` (RootQuery) - The root query\n- `fn` (Function) - Mapping function `(query, info) => any`\n\n**Returns:** Array of mapped results\n\n```javascript\nimport { flatMapQuery } from \"@data-prism/query-helpers\";\n\nconst resourceTypes = flatMapQuery(schema, query, (subquery, info) => ({\n\ttype: info.type,\n\tpath: info.path,\n\thasWhere: !!subquery.where,\n}));\n```\n\n#### `forEachQuery(schema, query, fn)`\n\nIterates over each query in a flattened query structure.\n\n**Parameters:**\n\n- `schema` (Schema) - The schema defining relationships\n- `query` (RootQuery) - The root query\n- `fn` (Function) - Iteration function `(query, info) => void`\n\n```javascript\nimport { forEachQuery } from \"@data-prism/query-helpers\";\n\nforEachQuery(schema, query, (subquery, info) => {\n\tconsole.log(`Processing ${info.type} at path: ${info.path.join(\".\")}`);\n});\n```\n\n#### `someQuery(schema, query, fn)`\n\nTests whether some query in a flattened query structure matches a condition.\n\n**Parameters:**\n\n- `schema` (Schema) - The schema defining relationships\n- `query` (RootQuery) - The root query\n- `fn` (Function) - Test function `(query, info) => boolean`\n\n**Returns:** Boolean indicating if any query matches the condition\n\n```javascript\nimport { someQuery } from \"@data-prism/query-helpers\";\n\nconst hasComplexWhere = someQuery(\n\tschema,\n\tquery,\n\t(subquery, info) => subquery.where && Object.keys(subquery.where).length > 2,\n);\n```\n\n### Multi-API Functions\n\n#### `collectQueryResults(schema, rootQuery, executor, initialContext?)`\n\nCore query traversal engine with callback pattern - reusable across store types.\n\n**Parameters:**\n\n- `schema` (Schema) - The schema defining relationships\n- `rootQuery` (NormalQuery) - The normalized query to execute\n- `executor` (Function) - Async function `(query, context) => Promise<any>`\n- `initialContext` (Object, optional) - Initial context passed to executor\n\n**Returns:** Promise resolving to nested result structure\n\n```javascript\nimport { collectQueryResults } from \"@data-prism/query-helpers\";\n\nconst results = await collectQueryResults(\n\tschema,\n\tnormalizedQuery,\n\tasync (query, context) => {\n\t\t// Your custom query execution logic\n\t\treturn await myAPI.fetch(query, context);\n\t},\n\t{ userId: \"123\", permissions: [\"read\"] },\n);\n```\n\n#### `executeQueryWithAPIs(schema, rootQuery, apiRegistry, options?)`\n\nReplaces the entire loadQueryData pattern - handles traversal, API coordination, and graph building.\n\n**Parameters:**\n\n- `schema` (Schema) - The schema defining relationships\n- `rootQuery` (NormalQuery) - The normalized query to execute\n- `apiRegistry` (APIRegistry) - Maps resource types to API handlers\n- `options` (QueryExecutionOptions, optional) - Context, caching, and special handlers\n\n**Returns:** Promise<Graph> - Complete graph with all query results merged\n\n```javascript\nimport { executeQueryWithAPIs } from \"@data-prism/query-helpers\";\n\nconst apiRegistry = {\n\tteams: {\n\t\tget: async (query, context) => {\n\t\t\t// Fetch teams data\n\t\t\treturn await teamsAPI.query(query);\n\t\t},\n\t},\n\tmatches: {\n\t\tget: async (query, context) => {\n\t\t\t// Fetch matches data\n\t\t\treturn await matchesAPI.query(query);\n\t\t},\n\t},\n};\n\nconst graph = await executeQueryWithAPIs(schema, normalizedQuery, apiRegistry, {\n\tcontext: { apiKey: \"your-key\" },\n\tspecialHandlers: [\n\t\t{\n\t\t\ttest: (query, context) => query.type === \"teams\" && query.where?.archived,\n\t\t\thandler: async (query, context) => {\n\t\t\t\t// Special handling for archived teams\n\t\t\t\treturn await archivedTeamsAPI.query(query);\n\t\t\t},\n\t\t},\n\t],\n});\n```\n\n## Type Definitions\n\n### QueryBreakdownItem\n\n```typescript\ninterface QueryBreakdownItem {\n\tpath: string[]; // Path to this query level\n\tattributes: any; // Selected attributes\n\trelationships: any; // Selected relationships\n\ttype: string; // Resource type\n\tquery: Query; // The query object\n\tparent: QueryBreakdownItem | null; // Parent breakdown item if any\n\tparentQuery: Query | null; // Parent query if any\n\tparentRelationship: string | null; // Parent relationship name if any\n}\n```\n\n### APIHandler\n\n```typescript\ninterface APIHandler {\n\tget: (query: Query, context: Object) => Promise<any>;\n\tcreate?: (resource: Object, context: Object) => Promise<any>;\n\tupdate?: (resource: Object, context: Object) => Promise<any>;\n\tdelete?: (resource: Object, context: Object) => Promise<any>;\n}\n```\n\n### APIRegistry\n\n```typescript\ntype APIRegistry = {\n\t[resourceType: string]: APIHandler;\n};\n```\n\n### SpecialHandler\n\n```typescript\ninterface SpecialHandler {\n\ttest: (query: Query, context: Object) => boolean;\n\thandler: (query: Query, context: Object) => Promise<any>;\n}\n```\n\n### QueryExecutionOptions\n\n```typescript\ninterface QueryExecutionOptions {\n\tcontext?: Object; // Context passed to API handlers\n\tspecialHandlers?: SpecialHandler[]; // Array of special case handlers\n\twithCache?: (\n\t\tkey: string,\n\t\tfetcher: () => Promise<any>,\n\t\toptions?: { ttl?: number },\n\t) => Promise<any>; // Caching function\n}\n```\n\n## Examples\n\n### Basic Query Traversal\n\n```javascript\nimport { flattenQuery, forEachQuery } from \"@data-prism/query-helpers\";\n\nconst schema = {\n\tresources: {\n\t\tteams: {\n\t\t\tattributes: {\n\t\t\t\tid: { type: \"string\" },\n\t\t\t\tname: { type: \"string\" },\n\t\t\t},\n\t\t\trelationships: {\n\t\t\t\thomeMatches: {\n\t\t\t\t\ttype: \"matches\",\n\t\t\t\t\tcardinality: \"many\",\n\t\t\t\t\tinverse: \"homeTeam\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tmatches: {\n\t\t\tattributes: {\n\t\t\t\tid: { type: \"string\" },\n\t\t\t\tfield: { type: \"string\" },\n\t\t\t},\n\t\t\trelationships: {\n\t\t\t\thomeTeam: { type: \"teams\", cardinality: \"one\", inverse: \"homeMatches\" },\n\t\t\t},\n\t\t},\n\t},\n};\n\nconst query = {\n\ttype: \"teams\",\n\tselect: {\n\t\tname: \"name\",\n\t\thomeMatches: {\n\t\t\tselect: {\n\t\t\t\tfield: \"field\",\n\t\t\t\thomeTeam: { select: [\"name\"] },\n\t\t\t},\n\t\t},\n\t},\n};\n\n// Flatten the query to see all levels\nconst breakdown = flattenQuery(schema, query);\nconsole.log(\n\tbreakdown.map((item) => ({\n\t\ttype: item.type,\n\t\tpath: item.path.join(\".\"),\n\t\tattributes: item.attributes,\n\t})),\n);\n\n// Iterate over each query level\nforEachQuery(schema, query, (subquery, info) => {\n\tconsole.log(`${info.type}: ${info.attributes.join(\", \")}`);\n});\n```\n\n### Multi-API Query Execution\n\n```javascript\nimport { executeQueryWithAPIs } from \"@data-prism/query-helpers\";\n\n// Define API handlers for different resource types\nconst apiRegistry = {\n\tteams: {\n\t\tget: async (query, context) => {\n\t\t\tconst response = await fetch(`/api/teams?${buildQueryString(query)}`, {\n\t\t\t\theaders: { Authorization: `Bearer ${context.apiKey}` },\n\t\t\t});\n\t\t\treturn response.json();\n\t\t},\n\t},\n\tmatches: {\n\t\tget: async (query, context) => {\n\t\t\tconst response = await fetch(`/api/matches?${buildQueryString(query)}`, {\n\t\t\t\theaders: { Authorization: `Bearer ${context.apiKey}` },\n\t\t\t});\n\t\t\treturn response.json();\n\t\t},\n\t},\n};\n\n// Execute complex query spanning multiple APIs\nconst graph = await executeQueryWithAPIs(\n\tschema,\n\t{\n\t\ttype: \"teams\",\n\t\tselect: {\n\t\t\tname: \"name\",\n\t\t\thomeMatches: {\n\t\t\t\tselect: [\"field\", \"awayTeam\"],\n\t\t\t\twhere: { status: \"completed\" },\n\t\t\t},\n\t\t},\n\t\twhere: { active: true },\n\t},\n\tapiRegistry,\n\t{\n\t\tcontext: { apiKey: \"your-api-key\" },\n\t\tspecialHandlers: [\n\t\t\t{\n\t\t\t\ttest: (query) => query.where?.archived === true,\n\t\t\t\thandler: async (query, context) => {\n\t\t\t\t\t// Use different endpoint for archived resources\n\t\t\t\t\treturn await fetchArchivedData(query, context);\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t},\n);\n\n// Use the resulting graph with any Data Prism store\nconsole.log(graph);\n```\n\n### Query Analysis\n\n```javascript\nimport { someQuery, flatMapQuery } from \"@data-prism/query-helpers\";\n\n// Check if any subquery has complex filtering\nconst hasComplexFilters = someQuery(schema, query, (subquery) => {\n\treturn (\n\t\tsubquery.where &&\n\t\tObject.keys(subquery.where).some(\n\t\t\t(key) =>\n\t\t\t\ttypeof subquery.where[key] === \"object\" &&\n\t\t\t\t\"$and\" in subquery.where[key],\n\t\t)\n\t);\n});\n\n// Extract all resource types used in the query\nconst resourceTypes = new Set(\n\tflatMapQuery(schema, query, (_, info) => info.type),\n);\n\n// Find all queries that need special permissions\nconst restrictedQueries = flatMapQuery(schema, query, (subquery, info) => {\n\tif (subquery.where?.classified === true) {\n\t\treturn { type: info.type, path: info.path };\n\t}\n\treturn null;\n}).filter(Boolean);\n```\n\n## TypeScript Support\n\nData Prism Query Helpers includes comprehensive TypeScript definitions:\n\n```typescript\nimport type {\n\tQueryBreakdown,\n\tQueryBreakdownItem,\n\tAPIHandler,\n\tAPIRegistry,\n\tSpecialHandler,\n\tQueryExecutionOptions,\n} from \"@data-prism/query-helpers\";\n\nimport type { Schema, RootQuery, Graph } from \"@data-prism/core\";\n\nconst apiRegistry: APIRegistry = {\n\tteams: {\n\t\tget: async (query, context) => {\n\t\t\t// Type-safe API handler implementation\n\t\t\treturn await myTeamsAPI.query(query);\n\t\t},\n\t},\n};\n```\n\n## Related Packages\n\n- `@data-prism/core` - Core data structures and query execution\n- `@data-prism/memory-store` - In-memory data store implementation\n- `@data-prism/postgres-store` - PostgreSQL backend\n- `@data-prism/jsonapi-store` - JSON:API client store\n","readmeFilename":"README.md","_rev":"1-f01c009e28995b15e8d8872fc07f8f05"}