@digital-science-dsl/dimensions-analytics-mcp 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +61 -0
- package/README.md +152 -0
- package/bin/dimensions-analytics-mcp-http.js +2 -0
- package/bin/dimensions-analytics-mcp.js +2 -0
- package/dist/client/auth/config-loaders.d.ts +22 -0
- package/dist/client/auth/config-loaders.d.ts.map +1 -0
- package/dist/client/auth/config-loaders.js +68 -0
- package/dist/client/auth/config-loaders.js.map +1 -0
- package/dist/client/auth/decorators/index.d.ts +7 -0
- package/dist/client/auth/decorators/index.d.ts.map +1 -0
- package/dist/client/auth/decorators/index.js +6 -0
- package/dist/client/auth/decorators/index.js.map +1 -0
- package/dist/client/auth/decorators/with-caching.d.ts +81 -0
- package/dist/client/auth/decorators/with-caching.d.ts.map +1 -0
- package/dist/client/auth/decorators/with-caching.js +168 -0
- package/dist/client/auth/decorators/with-caching.js.map +1 -0
- package/dist/client/auth/factory.d.ts +13 -0
- package/dist/client/auth/factory.d.ts.map +1 -0
- package/dist/client/auth/factory.js +29 -0
- package/dist/client/auth/factory.js.map +1 -0
- package/dist/client/auth/index.d.ts +7 -0
- package/dist/client/auth/index.d.ts.map +1 -0
- package/dist/client/auth/index.js +6 -0
- package/dist/client/auth/index.js.map +1 -0
- package/dist/client/auth/jwt-utils.d.ts +17 -0
- package/dist/client/auth/jwt-utils.d.ts.map +1 -0
- package/dist/client/auth/jwt-utils.js +33 -0
- package/dist/client/auth/jwt-utils.js.map +1 -0
- package/dist/client/auth/node.d.ts +16 -0
- package/dist/client/auth/node.d.ts.map +1 -0
- package/dist/client/auth/node.js +15 -0
- package/dist/client/auth/node.js.map +1 -0
- package/dist/client/auth/providers/index.d.ts +2 -0
- package/dist/client/auth/providers/index.d.ts.map +1 -0
- package/dist/client/auth/providers/index.js +2 -0
- package/dist/client/auth/providers/index.js.map +1 -0
- package/dist/client/auth/providers/jwt-auth-provider.d.ts +70 -0
- package/dist/client/auth/providers/jwt-auth-provider.d.ts.map +1 -0
- package/dist/client/auth/providers/jwt-auth-provider.js +134 -0
- package/dist/client/auth/providers/jwt-auth-provider.js.map +1 -0
- package/dist/client/auth/schemas.d.ts +19 -0
- package/dist/client/auth/schemas.d.ts.map +1 -0
- package/dist/client/auth/schemas.js +23 -0
- package/dist/client/auth/schemas.js.map +1 -0
- package/dist/client/auth/types.d.ts +25 -0
- package/dist/client/auth/types.d.ts.map +1 -0
- package/dist/client/auth/types.js +9 -0
- package/dist/client/auth/types.js.map +1 -0
- package/dist/client/command.d.ts +44 -0
- package/dist/client/command.d.ts.map +1 -0
- package/dist/client/command.js +23 -0
- package/dist/client/command.js.map +1 -0
- package/dist/client/config/index.d.ts +11 -0
- package/dist/client/config/index.d.ts.map +1 -0
- package/dist/client/config/index.js +8 -0
- package/dist/client/config/index.js.map +1 -0
- package/dist/client/config/loader.d.ts +27 -0
- package/dist/client/config/loader.d.ts.map +1 -0
- package/dist/client/config/loader.js +128 -0
- package/dist/client/config/loader.js.map +1 -0
- package/dist/client/config/node.d.ts +18 -0
- package/dist/client/config/node.d.ts.map +1 -0
- package/dist/client/config/node.js +17 -0
- package/dist/client/config/node.js.map +1 -0
- package/dist/client/config/schemas.d.ts +23 -0
- package/dist/client/config/schemas.d.ts.map +1 -0
- package/dist/client/config/schemas.js +24 -0
- package/dist/client/config/schemas.js.map +1 -0
- package/dist/client/config/types.d.ts +37 -0
- package/dist/client/config/types.d.ts.map +1 -0
- package/dist/client/config/types.js +6 -0
- package/dist/client/config/types.js.map +1 -0
- package/dist/client/config/unified-loader.d.ts +41 -0
- package/dist/client/config/unified-loader.d.ts.map +1 -0
- package/dist/client/config/unified-loader.js +86 -0
- package/dist/client/config/unified-loader.js.map +1 -0
- package/dist/client/config.d.ts +43 -0
- package/dist/client/config.d.ts.map +1 -0
- package/dist/client/config.js +56 -0
- package/dist/client/config.js.map +1 -0
- package/dist/client/deployment-config.d.ts +36 -0
- package/dist/client/deployment-config.d.ts.map +1 -0
- package/dist/client/deployment-config.js +79 -0
- package/dist/client/deployment-config.js.map +1 -0
- package/dist/client/errors.d.ts +180 -0
- package/dist/client/errors.d.ts.map +1 -0
- package/dist/client/errors.js +253 -0
- package/dist/client/errors.js.map +1 -0
- package/dist/client/http-client.d.ts +215 -0
- package/dist/client/http-client.d.ts.map +1 -0
- package/dist/client/http-client.js +419 -0
- package/dist/client/http-client.js.map +1 -0
- package/dist/client/index.d.ts +28 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +18 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/internal-dsl-client.d.ts +30 -0
- package/dist/client/internal-dsl-client.d.ts.map +1 -0
- package/dist/client/internal-dsl-client.js +101 -0
- package/dist/client/internal-dsl-client.js.map +1 -0
- package/dist/client/rate-limiter.d.ts +79 -0
- package/dist/client/rate-limiter.d.ts.map +1 -0
- package/dist/client/rate-limiter.js +118 -0
- package/dist/client/rate-limiter.js.map +1 -0
- package/dist/client/resolve-api-key-user.d.ts +24 -0
- package/dist/client/resolve-api-key-user.d.ts.map +1 -0
- package/dist/client/resolve-api-key-user.js +80 -0
- package/dist/client/resolve-api-key-user.js.map +1 -0
- package/dist/client/types.d.ts +44 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +10 -0
- package/dist/client/types.js.map +1 -0
- package/dist/dsl/client.d.ts +330 -0
- package/dist/dsl/client.d.ts.map +1 -0
- package/dist/dsl/client.js +433 -0
- package/dist/dsl/client.js.map +1 -0
- package/dist/dsl/commands/apply-filters.d.ts +15 -0
- package/dist/dsl/commands/apply-filters.d.ts.map +1 -0
- package/dist/dsl/commands/apply-filters.js +29 -0
- package/dist/dsl/commands/apply-filters.js.map +1 -0
- package/dist/dsl/commands/facet/index.d.ts +6 -0
- package/dist/dsl/commands/facet/index.d.ts.map +1 -0
- package/dist/dsl/commands/facet/index.js +6 -0
- package/dist/dsl/commands/facet/index.js.map +1 -0
- package/dist/dsl/commands/facet/schemas.d.ts +71 -0
- package/dist/dsl/commands/facet/schemas.d.ts.map +1 -0
- package/dist/dsl/commands/facet/schemas.js +84 -0
- package/dist/dsl/commands/facet/schemas.js.map +1 -0
- package/dist/dsl/commands/functions/ClassifyCommand.d.ts +96 -0
- package/dist/dsl/commands/functions/ClassifyCommand.d.ts.map +1 -0
- package/dist/dsl/commands/functions/ClassifyCommand.js +95 -0
- package/dist/dsl/commands/functions/ClassifyCommand.js.map +1 -0
- package/dist/dsl/commands/functions/ExtractAffiliationsCommand.d.ts +86 -0
- package/dist/dsl/commands/functions/ExtractAffiliationsCommand.d.ts.map +1 -0
- package/dist/dsl/commands/functions/ExtractAffiliationsCommand.js +131 -0
- package/dist/dsl/commands/functions/ExtractAffiliationsCommand.js.map +1 -0
- package/dist/dsl/commands/functions/ExtractConceptsCommand.d.ts +73 -0
- package/dist/dsl/commands/functions/ExtractConceptsCommand.d.ts.map +1 -0
- package/dist/dsl/commands/functions/ExtractConceptsCommand.js +110 -0
- package/dist/dsl/commands/functions/ExtractConceptsCommand.js.map +1 -0
- package/dist/dsl/commands/functions/ExtractGrantsCommand.d.ts +66 -0
- package/dist/dsl/commands/functions/ExtractGrantsCommand.d.ts.map +1 -0
- package/dist/dsl/commands/functions/ExtractGrantsCommand.js +87 -0
- package/dist/dsl/commands/functions/ExtractGrantsCommand.js.map +1 -0
- package/dist/dsl/commands/functions/index.d.ts +10 -0
- package/dist/dsl/commands/functions/index.d.ts.map +1 -0
- package/dist/dsl/commands/functions/index.js +10 -0
- package/dist/dsl/commands/functions/index.js.map +1 -0
- package/dist/dsl/commands/index.d.ts +8 -0
- package/dist/dsl/commands/index.d.ts.map +1 -0
- package/dist/dsl/commands/index.js +7 -0
- package/dist/dsl/commands/index.js.map +1 -0
- package/dist/dsl/commands/validate-input.d.ts +18 -0
- package/dist/dsl/commands/validate-input.d.ts.map +1 -0
- package/dist/dsl/commands/validate-input.js +27 -0
- package/dist/dsl/commands/validate-input.js.map +1 -0
- package/dist/dsl/create-client.d.ts +32 -0
- package/dist/dsl/create-client.d.ts.map +1 -0
- package/dist/dsl/create-client.js +58 -0
- package/dist/dsl/create-client.js.map +1 -0
- package/dist/dsl/fluent-query-builder.d.ts +439 -0
- package/dist/dsl/fluent-query-builder.d.ts.map +1 -0
- package/dist/dsl/fluent-query-builder.js +534 -0
- package/dist/dsl/fluent-query-builder.js.map +1 -0
- package/dist/dsl/index.d.ts +32 -0
- package/dist/dsl/index.d.ts.map +1 -0
- package/dist/dsl/index.js +31 -0
- package/dist/dsl/index.js.map +1 -0
- package/dist/dsl/pagination.d.ts +82 -0
- package/dist/dsl/pagination.d.ts.map +1 -0
- package/dist/dsl/pagination.js +135 -0
- package/dist/dsl/pagination.js.map +1 -0
- package/dist/dsl/query-builder.d.ts +456 -0
- package/dist/dsl/query-builder.d.ts.map +1 -0
- package/dist/dsl/query-builder.js +994 -0
- package/dist/dsl/query-builder.js.map +1 -0
- package/dist/dsl/response-parser.d.ts +111 -0
- package/dist/dsl/response-parser.d.ts.map +1 -0
- package/dist/dsl/response-parser.js +210 -0
- package/dist/dsl/response-parser.js.map +1 -0
- package/dist/dsl/schema/cache.d.ts +52 -0
- package/dist/dsl/schema/cache.d.ts.map +1 -0
- package/dist/dsl/schema/cache.js +97 -0
- package/dist/dsl/schema/cache.js.map +1 -0
- package/dist/dsl/schema/extract.d.ts +18 -0
- package/dist/dsl/schema/extract.d.ts.map +1 -0
- package/dist/dsl/schema/extract.js +41 -0
- package/dist/dsl/schema/extract.js.map +1 -0
- package/dist/dsl/schema/index.d.ts +13 -0
- package/dist/dsl/schema/index.d.ts.map +1 -0
- package/dist/dsl/schema/index.js +12 -0
- package/dist/dsl/schema/index.js.map +1 -0
- package/dist/dsl/schema/load.d.ts +41 -0
- package/dist/dsl/schema/load.d.ts.map +1 -0
- package/dist/dsl/schema/load.js +119 -0
- package/dist/dsl/schema/load.js.map +1 -0
- package/dist/dsl/schema/store.d.ts +137 -0
- package/dist/dsl/schema/store.d.ts.map +1 -0
- package/dist/dsl/schema/store.js +204 -0
- package/dist/dsl/schema/store.js.map +1 -0
- package/dist/dsl/schema/structured-entities.d.ts +21 -0
- package/dist/dsl/schema/structured-entities.d.ts.map +1 -0
- package/dist/dsl/schema/structured-entities.js +39 -0
- package/dist/dsl/schema/structured-entities.js.map +1 -0
- package/dist/dsl/schema/summary.d.ts +51 -0
- package/dist/dsl/schema/summary.d.ts.map +1 -0
- package/dist/dsl/schema/summary.js +61 -0
- package/dist/dsl/schema/summary.js.map +1 -0
- package/dist/dsl/schema/types.d.ts +36 -0
- package/dist/dsl/schema/types.d.ts.map +1 -0
- package/dist/dsl/schema/types.js +6 -0
- package/dist/dsl/schema/types.js.map +1 -0
- package/dist/dsl/schema/validation.d.ts +21 -0
- package/dist/dsl/schema/validation.d.ts.map +1 -0
- package/dist/dsl/schema/validation.js +44 -0
- package/dist/dsl/schema/validation.js.map +1 -0
- package/dist/dsl/types/buckets.d.ts +18 -0
- package/dist/dsl/types/buckets.d.ts.map +1 -0
- package/dist/dsl/types/buckets.js +6 -0
- package/dist/dsl/types/buckets.js.map +1 -0
- package/dist/dsl/types/common.d.ts +91 -0
- package/dist/dsl/types/common.d.ts.map +1 -0
- package/dist/dsl/types/common.js +6 -0
- package/dist/dsl/types/common.js.map +1 -0
- package/dist/dsl/types/entities.d.ts +35 -0
- package/dist/dsl/types/entities.d.ts.map +1 -0
- package/dist/dsl/types/entities.js +11 -0
- package/dist/dsl/types/entities.js.map +1 -0
- package/dist/dsl/types/index.d.ts +12 -0
- package/dist/dsl/types/index.d.ts.map +1 -0
- package/dist/dsl/types/index.js +7 -0
- package/dist/dsl/types/index.js.map +1 -0
- package/dist/dsl/types/return-clauses.d.ts +107 -0
- package/dist/dsl/types/return-clauses.d.ts.map +1 -0
- package/dist/dsl/types/return-clauses.js +22 -0
- package/dist/dsl/types/return-clauses.js.map +1 -0
- package/dist/dsl/types/special-functions.d.ts +175 -0
- package/dist/dsl/types/special-functions.d.ts.map +1 -0
- package/dist/dsl/types/special-functions.js +25 -0
- package/dist/dsl/types/special-functions.js.map +1 -0
- package/dist/dsl/types/vocabulary.d.ts +21 -0
- package/dist/dsl/types/vocabulary.d.ts.map +1 -0
- package/dist/dsl/types/vocabulary.js +44 -0
- package/dist/dsl/types/vocabulary.js.map +1 -0
- package/dist/dsl/usage-policy.d.ts +87 -0
- package/dist/dsl/usage-policy.d.ts.map +1 -0
- package/dist/dsl/usage-policy.js +133 -0
- package/dist/dsl/usage-policy.js.map +1 -0
- package/dist/dsl/utils/escape.d.ts +24 -0
- package/dist/dsl/utils/escape.d.ts.map +1 -0
- package/dist/dsl/utils/escape.js +124 -0
- package/dist/dsl/utils/escape.js.map +1 -0
- package/dist/dsl/utils/sanitize.d.ts +13 -0
- package/dist/dsl/utils/sanitize.d.ts.map +1 -0
- package/dist/dsl/utils/sanitize.js +19 -0
- package/dist/dsl/utils/sanitize.js.map +1 -0
- package/dist/dsl/utils/string-utils.d.ts +35 -0
- package/dist/dsl/utils/string-utils.d.ts.map +1 -0
- package/dist/dsl/utils/string-utils.js +145 -0
- package/dist/dsl/utils/string-utils.js.map +1 -0
- package/dist/dsl/utils/validate-field-name.d.ts +11 -0
- package/dist/dsl/utils/validate-field-name.d.ts.map +1 -0
- package/dist/dsl/utils/validate-field-name.js +18 -0
- package/dist/dsl/utils/validate-field-name.js.map +1 -0
- package/dist/examples/dsl-examples.d.ts +11 -0
- package/dist/examples/dsl-examples.d.ts.map +1 -0
- package/dist/examples/dsl-examples.js +49 -0
- package/dist/examples/dsl-examples.js.map +1 -0
- package/dist/examples/usage-scenarios.d.ts +22 -0
- package/dist/examples/usage-scenarios.d.ts.map +1 -0
- package/dist/examples/usage-scenarios.js +173 -0
- package/dist/examples/usage-scenarios.js.map +1 -0
- package/dist/funder-org-names.d.ts +12 -0
- package/dist/funder-org-names.d.ts.map +1 -0
- package/dist/funder-org-names.js +30 -0
- package/dist/funder-org-names.js.map +1 -0
- package/dist/http-main.d.ts +7 -0
- package/dist/http-main.d.ts.map +1 -0
- package/dist/http-main.js +36 -0
- package/dist/http-main.js.map +1 -0
- package/dist/http.d.ts +29 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +173 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/kwq/build-query.d.ts +26 -0
- package/dist/kwq/build-query.d.ts.map +1 -0
- package/dist/kwq/build-query.js +37 -0
- package/dist/kwq/build-query.js.map +1 -0
- package/dist/kwq/concept-groups.d.ts +49 -0
- package/dist/kwq/concept-groups.d.ts.map +1 -0
- package/dist/kwq/concept-groups.js +55 -0
- package/dist/kwq/concept-groups.js.map +1 -0
- package/dist/kwq/dsl-assembler.d.ts +28 -0
- package/dist/kwq/dsl-assembler.d.ts.map +1 -0
- package/dist/kwq/dsl-assembler.js +124 -0
- package/dist/kwq/dsl-assembler.js.map +1 -0
- package/dist/kwq/ensemble.d.ts +38 -0
- package/dist/kwq/ensemble.d.ts.map +1 -0
- package/dist/kwq/ensemble.js +107 -0
- package/dist/kwq/ensemble.js.map +1 -0
- package/dist/kwq/index.d.ts +16 -0
- package/dist/kwq/index.d.ts.map +1 -0
- package/dist/kwq/index.js +14 -0
- package/dist/kwq/index.js.map +1 -0
- package/dist/kwq/types.d.ts +120 -0
- package/dist/kwq/types.d.ts.map +1 -0
- package/dist/kwq/types.js +11 -0
- package/dist/kwq/types.js.map +1 -0
- package/dist/lambda.d.ts +10 -0
- package/dist/lambda.d.ts.map +1 -0
- package/dist/lambda.js +4 -0
- package/dist/lambda.js.map +1 -0
- package/dist/main.d.ts +8 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +33 -0
- package/dist/main.js.map +1 -0
- package/dist/mcp/batch-fetch.d.ts +89 -0
- package/dist/mcp/batch-fetch.d.ts.map +1 -0
- package/dist/mcp/batch-fetch.js +178 -0
- package/dist/mcp/batch-fetch.js.map +1 -0
- package/dist/mcp/examples/dsl-examples.d.ts +21 -0
- package/dist/mcp/examples/dsl-examples.d.ts.map +1 -0
- package/dist/mcp/examples/dsl-examples.js +61 -0
- package/dist/mcp/examples/dsl-examples.js.map +1 -0
- package/dist/mcp/examples/usage-scenarios.d.ts +20 -0
- package/dist/mcp/examples/usage-scenarios.d.ts.map +1 -0
- package/dist/mcp/examples/usage-scenarios.js +169 -0
- package/dist/mcp/examples/usage-scenarios.js.map +1 -0
- package/dist/mcp/export-format.d.ts +43 -0
- package/dist/mcp/export-format.d.ts.map +1 -0
- package/dist/mcp/export-format.js +92 -0
- package/dist/mcp/export-format.js.map +1 -0
- package/dist/mcp/funder-org-names.d.ts +12 -0
- package/dist/mcp/funder-org-names.d.ts.map +1 -0
- package/dist/mcp/funder-org-names.js +30 -0
- package/dist/mcp/funder-org-names.js.map +1 -0
- package/dist/mcp/http-server.d.ts +20 -0
- package/dist/mcp/http-server.d.ts.map +1 -0
- package/dist/mcp/http-server.js +118 -0
- package/dist/mcp/http-server.js.map +1 -0
- package/dist/mcp/middleware/field-aliases.d.ts +97 -0
- package/dist/mcp/middleware/field-aliases.d.ts.map +1 -0
- package/dist/mcp/middleware/field-aliases.js +208 -0
- package/dist/mcp/middleware/field-aliases.js.map +1 -0
- package/dist/mcp/resources/schema.d.ts +13 -0
- package/dist/mcp/resources/schema.d.ts.map +1 -0
- package/dist/mcp/resources/schema.js +262 -0
- package/dist/mcp/resources/schema.js.map +1 -0
- package/dist/mcp/schema/context.d.ts +10 -0
- package/dist/mcp/schema/context.d.ts.map +1 -0
- package/dist/mcp/schema/context.js +6 -0
- package/dist/mcp/schema/context.js.map +1 -0
- package/dist/mcp/schema/index.d.ts +8 -0
- package/dist/mcp/schema/index.d.ts.map +1 -0
- package/dist/mcp/schema/index.js +6 -0
- package/dist/mcp/schema/index.js.map +1 -0
- package/dist/mcp/server.d.ts +56 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +168 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/shared-schema.d.ts +13 -0
- package/dist/mcp/shared-schema.d.ts.map +1 -0
- package/dist/mcp/shared-schema.js +28 -0
- package/dist/mcp/shared-schema.js.map +1 -0
- package/dist/mcp/tools/analytics-filters.d.ts +18 -0
- package/dist/mcp/tools/analytics-filters.d.ts.map +1 -0
- package/dist/mcp/tools/analytics-filters.js +35 -0
- package/dist/mcp/tools/analytics-filters.js.map +1 -0
- package/dist/mcp/tools/analytics.d.ts +16 -0
- package/dist/mcp/tools/analytics.d.ts.map +1 -0
- package/dist/mcp/tools/analytics.js +381 -0
- package/dist/mcp/tools/analytics.js.map +1 -0
- package/dist/mcp/tools/concept-profile.d.ts +14 -0
- package/dist/mcp/tools/concept-profile.d.ts.map +1 -0
- package/dist/mcp/tools/concept-profile.js +130 -0
- package/dist/mcp/tools/concept-profile.js.map +1 -0
- package/dist/mcp/tools/dataset-profile.d.ts +15 -0
- package/dist/mcp/tools/dataset-profile.d.ts.map +1 -0
- package/dist/mcp/tools/dataset-profile.js +194 -0
- package/dist/mcp/tools/dataset-profile.js.map +1 -0
- package/dist/mcp/tools/fetch-search-pages.d.ts +15 -0
- package/dist/mcp/tools/fetch-search-pages.d.ts.map +1 -0
- package/dist/mcp/tools/fetch-search-pages.js +237 -0
- package/dist/mcp/tools/fetch-search-pages.js.map +1 -0
- package/dist/mcp/tools/functions.d.ts +14 -0
- package/dist/mcp/tools/functions.d.ts.map +1 -0
- package/dist/mcp/tools/functions.js +87 -0
- package/dist/mcp/tools/functions.js.map +1 -0
- package/dist/mcp/tools/impact-chain.d.ts +15 -0
- package/dist/mcp/tools/impact-chain.d.ts.map +1 -0
- package/dist/mcp/tools/impact-chain.js +96 -0
- package/dist/mcp/tools/impact-chain.js.map +1 -0
- package/dist/mcp/tools/kwq.d.ts +19 -0
- package/dist/mcp/tools/kwq.d.ts.map +1 -0
- package/dist/mcp/tools/kwq.js +156 -0
- package/dist/mcp/tools/kwq.js.map +1 -0
- package/dist/mcp/tools/lookup.d.ts +14 -0
- package/dist/mcp/tools/lookup.d.ts.map +1 -0
- package/dist/mcp/tools/lookup.js +146 -0
- package/dist/mcp/tools/lookup.js.map +1 -0
- package/dist/mcp/tools/policy-profile.d.ts +15 -0
- package/dist/mcp/tools/policy-profile.d.ts.map +1 -0
- package/dist/mcp/tools/policy-profile.js +174 -0
- package/dist/mcp/tools/policy-profile.js.map +1 -0
- package/dist/mcp/tools/profile.d.ts +14 -0
- package/dist/mcp/tools/profile.d.ts.map +1 -0
- package/dist/mcp/tools/profile.js +349 -0
- package/dist/mcp/tools/profile.js.map +1 -0
- package/dist/mcp/tools/query.d.ts +16 -0
- package/dist/mcp/tools/query.d.ts.map +1 -0
- package/dist/mcp/tools/query.js +75 -0
- package/dist/mcp/tools/query.js.map +1 -0
- package/dist/mcp/tools/schema.d.ts +23 -0
- package/dist/mcp/tools/schema.d.ts.map +1 -0
- package/dist/mcp/tools/schema.js +124 -0
- package/dist/mcp/tools/schema.js.map +1 -0
- package/dist/mcp/tools/search-entity-metadata.d.ts +18 -0
- package/dist/mcp/tools/search-entity-metadata.d.ts.map +1 -0
- package/dist/mcp/tools/search-entity-metadata.js +221 -0
- package/dist/mcp/tools/search-entity-metadata.js.map +1 -0
- package/dist/mcp/tools/search-input.d.ts +58 -0
- package/dist/mcp/tools/search-input.d.ts.map +1 -0
- package/dist/mcp/tools/search-input.js +76 -0
- package/dist/mcp/tools/search-input.js.map +1 -0
- package/dist/mcp/tools/search.d.ts +24 -0
- package/dist/mcp/tools/search.d.ts.map +1 -0
- package/dist/mcp/tools/search.js +115 -0
- package/dist/mcp/tools/search.js.map +1 -0
- package/dist/mcp/utils.d.ts +82 -0
- package/dist/mcp/utils.d.ts.map +1 -0
- package/dist/mcp/utils.js +126 -0
- package/dist/mcp/utils.js.map +1 -0
- package/dist/middleware/field-aliases.d.ts +97 -0
- package/dist/middleware/field-aliases.d.ts.map +1 -0
- package/dist/middleware/field-aliases.js +208 -0
- package/dist/middleware/field-aliases.js.map +1 -0
- package/dist/resources/schema.d.ts +13 -0
- package/dist/resources/schema.d.ts.map +1 -0
- package/dist/resources/schema.js +204 -0
- package/dist/resources/schema.js.map +1 -0
- package/dist/schema/context.d.ts +10 -0
- package/dist/schema/context.d.ts.map +1 -0
- package/dist/schema/context.js +6 -0
- package/dist/schema/context.js.map +1 -0
- package/dist/schema/index.d.ts +9 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +6 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/load.d.ts +43 -0
- package/dist/schema/load.d.ts.map +1 -0
- package/dist/schema/load.js +139 -0
- package/dist/schema/load.js.map +1 -0
- package/dist/schema/store.d.ts +112 -0
- package/dist/schema/store.d.ts.map +1 -0
- package/dist/schema/store.js +173 -0
- package/dist/schema/store.js.map +1 -0
- package/dist/schema/structured-entities.d.ts +21 -0
- package/dist/schema/structured-entities.d.ts.map +1 -0
- package/dist/schema/structured-entities.js +39 -0
- package/dist/schema/structured-entities.js.map +1 -0
- package/dist/schema/types.d.ts +36 -0
- package/dist/schema/types.d.ts.map +1 -0
- package/dist/schema/types.js +6 -0
- package/dist/schema/types.js.map +1 -0
- package/dist/server.d.ts +57 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +144 -0
- package/dist/server.js.map +1 -0
- package/dist/telemetry.d.ts +172 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +233 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/tools/analytics-filters.d.ts +18 -0
- package/dist/tools/analytics-filters.d.ts.map +1 -0
- package/dist/tools/analytics-filters.js +35 -0
- package/dist/tools/analytics-filters.js.map +1 -0
- package/dist/tools/analytics.d.ts +16 -0
- package/dist/tools/analytics.d.ts.map +1 -0
- package/dist/tools/analytics.js +381 -0
- package/dist/tools/analytics.js.map +1 -0
- package/dist/tools/concept-profile.d.ts +14 -0
- package/dist/tools/concept-profile.d.ts.map +1 -0
- package/dist/tools/concept-profile.js +130 -0
- package/dist/tools/concept-profile.js.map +1 -0
- package/dist/tools/dataset-profile.d.ts +15 -0
- package/dist/tools/dataset-profile.d.ts.map +1 -0
- package/dist/tools/dataset-profile.js +194 -0
- package/dist/tools/dataset-profile.js.map +1 -0
- package/dist/tools/functions.d.ts +14 -0
- package/dist/tools/functions.d.ts.map +1 -0
- package/dist/tools/functions.js +294 -0
- package/dist/tools/functions.js.map +1 -0
- package/dist/tools/impact-chain.d.ts +15 -0
- package/dist/tools/impact-chain.d.ts.map +1 -0
- package/dist/tools/impact-chain.js +96 -0
- package/dist/tools/impact-chain.js.map +1 -0
- package/dist/tools/kwq.d.ts +19 -0
- package/dist/tools/kwq.d.ts.map +1 -0
- package/dist/tools/kwq.js +156 -0
- package/dist/tools/kwq.js.map +1 -0
- package/dist/tools/lookup.d.ts +14 -0
- package/dist/tools/lookup.d.ts.map +1 -0
- package/dist/tools/lookup.js +213 -0
- package/dist/tools/lookup.js.map +1 -0
- package/dist/tools/policy-profile.d.ts +15 -0
- package/dist/tools/policy-profile.d.ts.map +1 -0
- package/dist/tools/policy-profile.js +174 -0
- package/dist/tools/policy-profile.js.map +1 -0
- package/dist/tools/profile.d.ts +14 -0
- package/dist/tools/profile.d.ts.map +1 -0
- package/dist/tools/profile.js +349 -0
- package/dist/tools/profile.js.map +1 -0
- package/dist/tools/query.d.ts +16 -0
- package/dist/tools/query.d.ts.map +1 -0
- package/dist/tools/query.js +53 -0
- package/dist/tools/query.js.map +1 -0
- package/dist/tools/schema.d.ts +23 -0
- package/dist/tools/schema.d.ts.map +1 -0
- package/dist/tools/schema.js +124 -0
- package/dist/tools/schema.js.map +1 -0
- package/dist/tools/search-entity-metadata.d.ts +18 -0
- package/dist/tools/search-entity-metadata.d.ts.map +1 -0
- package/dist/tools/search-entity-metadata.js +221 -0
- package/dist/tools/search-entity-metadata.js.map +1 -0
- package/dist/tools/search.d.ts +23 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +110 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/solr-fields.d.ts +39 -0
- package/dist/tools/solr-fields.d.ts.map +1 -0
- package/dist/tools/solr-fields.js +40 -0
- package/dist/tools/solr-fields.js.map +1 -0
- package/dist/utils.d.ts +70 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +104 -0
- package/dist/utils.js.map +1 -0
- package/package.json +41 -0
- package/src/client/auth/config-loaders.ts +81 -0
- package/src/client/auth/decorators/index.ts +7 -0
- package/src/client/auth/decorators/with-caching.ts +237 -0
- package/src/client/auth/factory.ts +34 -0
- package/src/client/auth/index.ts +6 -0
- package/src/client/auth/jwt-utils.ts +36 -0
- package/src/client/auth/node.ts +16 -0
- package/src/client/auth/providers/index.ts +1 -0
- package/src/client/auth/providers/jwt-auth-provider.ts +153 -0
- package/src/client/auth/schemas.ts +25 -0
- package/src/client/auth/types.ts +30 -0
- package/src/client/command.ts +54 -0
- package/src/client/config/index.ts +15 -0
- package/src/client/config/loader.ts +155 -0
- package/src/client/config/node.ts +22 -0
- package/src/client/config/schemas.ts +28 -0
- package/src/client/config/types.ts +39 -0
- package/src/client/config/unified-loader.ts +118 -0
- package/src/client/config.ts +69 -0
- package/src/client/deployment-config.ts +98 -0
- package/src/client/errors.ts +295 -0
- package/src/client/http-client.ts +577 -0
- package/src/client/index.ts +68 -0
- package/src/client/internal-dsl-client.ts +128 -0
- package/src/client/rate-limiter.ts +139 -0
- package/src/client/resolve-api-key-user.ts +99 -0
- package/src/client/types.ts +44 -0
- package/src/dsl/client.ts +538 -0
- package/src/dsl/commands/apply-filters.ts +35 -0
- package/src/dsl/commands/facet/index.ts +12 -0
- package/src/dsl/commands/facet/schemas.ts +101 -0
- package/src/dsl/commands/functions/ClassifyCommand.ts +129 -0
- package/src/dsl/commands/functions/ExtractAffiliationsCommand.ts +163 -0
- package/src/dsl/commands/functions/ExtractConceptsCommand.ts +141 -0
- package/src/dsl/commands/functions/ExtractGrantsCommand.ts +112 -0
- package/src/dsl/commands/functions/index.ts +31 -0
- package/src/dsl/commands/index.ts +29 -0
- package/src/dsl/commands/validate-input.ts +29 -0
- package/src/dsl/create-client.ts +80 -0
- package/src/dsl/fluent-query-builder.ts +684 -0
- package/src/dsl/index.ts +206 -0
- package/src/dsl/pagination.ts +202 -0
- package/src/dsl/query-builder.ts +1120 -0
- package/src/dsl/response-parser.ts +299 -0
- package/src/dsl/schema/cache.ts +124 -0
- package/src/dsl/schema/extract.ts +44 -0
- package/src/dsl/schema/index.ts +50 -0
- package/src/dsl/schema/load.ts +160 -0
- package/src/dsl/schema/store.ts +253 -0
- package/src/dsl/schema/structured-entities.ts +44 -0
- package/src/dsl/schema/summary.ts +94 -0
- package/src/dsl/schema/types.ts +40 -0
- package/src/dsl/schema/validation.ts +56 -0
- package/src/dsl/types/buckets.ts +22 -0
- package/src/dsl/types/common.ts +99 -0
- package/src/dsl/types/entities.ts +43 -0
- package/src/dsl/types/index.ts +63 -0
- package/src/dsl/types/return-clauses.ts +147 -0
- package/src/dsl/types/special-functions.ts +220 -0
- package/src/dsl/types/vocabulary.ts +82 -0
- package/src/dsl/usage-policy.ts +219 -0
- package/src/dsl/utils/escape.ts +123 -0
- package/src/dsl/utils/sanitize.ts +21 -0
- package/src/dsl/utils/string-utils.ts +147 -0
- package/src/dsl/utils/validate-field-name.ts +19 -0
- package/src/http-main.ts +41 -0
- package/src/index.ts +14 -0
- package/src/main.ts +40 -0
- package/src/mcp/batch-fetch.ts +255 -0
- package/src/mcp/examples/dsl-examples.ts +66 -0
- package/src/mcp/examples/usage-scenarios.ts +185 -0
- package/src/mcp/export-format.ts +113 -0
- package/src/mcp/funder-org-names.ts +30 -0
- package/src/mcp/http-server.ts +148 -0
- package/src/mcp/middleware/field-aliases.ts +274 -0
- package/src/mcp/resources/schema.ts +364 -0
- package/src/mcp/schema/context.ts +11 -0
- package/src/mcp/schema/index.ts +38 -0
- package/src/mcp/server.ts +247 -0
- package/src/mcp/shared-schema.ts +34 -0
- package/src/mcp/tools/analytics-filters.ts +46 -0
- package/src/mcp/tools/analytics.ts +453 -0
- package/src/mcp/tools/fetch-search-pages.ts +329 -0
- package/src/mcp/tools/functions.ts +105 -0
- package/src/mcp/tools/lookup.ts +182 -0
- package/src/mcp/tools/query.ts +91 -0
- package/src/mcp/tools/schema.ts +147 -0
- package/src/mcp/tools/search-entity-metadata.ts +253 -0
- package/src/mcp/tools/search-input.ts +87 -0
- package/src/mcp/tools/search.ts +168 -0
- package/src/mcp/utils.ts +199 -0
- package/test/client/auth/config-loaders.test.ts +92 -0
- package/test/client/auth/decorators/with-caching.test.ts +482 -0
- package/test/client/auth/factory.test.ts +68 -0
- package/test/client/auth/providers/jwt-auth-provider.test.ts +398 -0
- package/test/client/auth/types.test.ts +18 -0
- package/test/client/command.test.ts +163 -0
- package/test/client/config/loader.test.ts +377 -0
- package/test/client/config/unified-loader.test.ts +136 -0
- package/test/client/deployment-config.test.ts +69 -0
- package/test/client/errors/index.test.ts +408 -0
- package/test/client/helpers/mock-fetch.ts +42 -0
- package/test/client/http-client.test.ts +1148 -0
- package/test/client/integration/auth-providers.integration.test.ts +186 -0
- package/test/client/internal-dsl-client.test.ts +76 -0
- package/test/client/rate-limiter.test.ts +204 -0
- package/test/client/resolve-api-key-user.test.ts +87 -0
- package/test/dsl/client.special-functions.test.ts +387 -0
- package/test/dsl/client.test.ts +457 -0
- package/test/dsl/commands/apply-filters.test.ts +147 -0
- package/test/dsl/commands/functions/ClassifyCommand.test.ts +170 -0
- package/test/dsl/commands/functions/ExtractAffiliationsCommand.test.ts +306 -0
- package/test/dsl/commands/functions/ExtractConceptsCommand.test.ts +136 -0
- package/test/dsl/commands/functions/ExtractGrantsCommand.test.ts +202 -0
- package/test/dsl/commands/search/filters.test.ts +42 -0
- package/test/dsl/fluent-query-builder.test.ts +865 -0
- package/test/dsl/integration/client.integration.test.ts +294 -0
- package/test/dsl/integration/facet-api.integration.test.ts +276 -0
- package/test/dsl/integration/field-existence.integration.test.ts +148 -0
- package/test/dsl/integration/fluent-api-docs-examples.integration.test.ts +988 -0
- package/test/dsl/integration/fluent-api.integration.test.ts +615 -0
- package/test/dsl/integration/search-helpers.ts +27 -0
- package/test/dsl/integration/special-functions.integration.test.ts +224 -0
- package/test/dsl/integration/test-config.ts +52 -0
- package/test/dsl/pagination.test.ts +86 -0
- package/test/dsl/query-builder.test.ts +1775 -0
- package/test/dsl/response-parser.test.ts +520 -0
- package/test/dsl/schema/cache.test.ts +53 -0
- package/test/dsl/schema/load.test.ts +165 -0
- package/test/dsl/schema/summary.test.ts +61 -0
- package/test/dsl/schema/validation.test.ts +46 -0
- package/test/dsl/time-series.test.ts +135 -0
- package/test/dsl/unnest.test.ts +151 -0
- package/test/dsl/usage-policy.test.ts +100 -0
- package/test/dsl/utils/escape.property.test.ts +109 -0
- package/test/dsl/utils/escape.test.ts +140 -0
- package/test/dsl/utils/validate-field-name.property.test.ts +99 -0
- package/test/dsl/utils/validate-field-name.test.ts +55 -0
- package/test/examples/dsl-examples.test.ts +29 -0
- package/test/examples/usage-scenarios.test.ts +90 -0
- package/test/fixtures/describe-schema.json +4000 -0
- package/test/funder-org-names.test.ts +20 -0
- package/test/helpers/schema-fixture.ts +18 -0
- package/test/helpers/tool-test-harness.ts +114 -0
- package/test/integration/assertions.ts +263 -0
- package/test/integration/env.ts +108 -0
- package/test/integration/harness.ts +307 -0
- package/test/integration/hosted-client.ts +56 -0
- package/test/integration/hosted-mocks.ts +81 -0
- package/test/integration/hosted-run.ts +86 -0
- package/test/integration/hosted.e2e.test.ts +101 -0
- package/test/integration/reporter.ts +100 -0
- package/test/integration/run.ts +74 -0
- package/test/integration/suites/analytics.integration.ts +72 -0
- package/test/integration/suites/functions.integration.ts +37 -0
- package/test/integration/suites/hosted-smoke.integration.ts +38 -0
- package/test/integration/suites/index.ts +22 -0
- package/test/integration/suites/lookup.integration.ts +57 -0
- package/test/integration/suites/query.integration.ts +49 -0
- package/test/integration/suites/resources.integration.ts +68 -0
- package/test/integration/suites/search.integration.ts +80 -0
- package/test/integration/types.ts +92 -0
- package/test/integration/verify-usage-scenarios.ts +162 -0
- package/test/mcp/export-format.test.ts +67 -0
- package/test/mcp/http-server.test.ts +80 -0
- package/test/middleware/field-aliases.test.ts +287 -0
- package/test/resources/schema.test.ts +28 -0
- package/test/schema/describe-contract.test.ts +24 -0
- package/test/schema/store.test.ts +45 -0
- package/test/server.test.ts +170 -0
- package/test/tools/analytics-filters.test.ts +35 -0
- package/test/tools/analytics.test.ts +419 -0
- package/test/tools/fetch-search-pages.test.ts +200 -0
- package/test/tools/functions.test.ts +153 -0
- package/test/tools/lookup.test.ts +296 -0
- package/test/tools/query.test.ts +100 -0
- package/test/tools/schema.test.ts +37 -0
- package/test/tools/search.test.ts +415 -0
- package/test/utils.test.ts +45 -0
- package/tsconfig.json +9 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,1120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query builder for constructing Dimensions DSL queries programmatically.
|
|
3
|
+
* @module query-builder
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ValidationError } from "../client/index.js";
|
|
7
|
+
import type { SchemaStore } from "./schema/store.js";
|
|
8
|
+
import { assertValidEntity, assertValidSearchIndex } from "./schema/validation.js";
|
|
9
|
+
import type {
|
|
10
|
+
AggregatedFacetReturnClause,
|
|
11
|
+
Currency,
|
|
12
|
+
FacetClause,
|
|
13
|
+
FacetReturnClause,
|
|
14
|
+
GroupedReturnClause,
|
|
15
|
+
TimeSeriesReturnClause,
|
|
16
|
+
} from "./types/return-clauses.js";
|
|
17
|
+
import type { EntityType, SearchIndex, SortOrder, WhereOperator } from "./types/vocabulary.js";
|
|
18
|
+
import { VALID_OPERATORS } from "./types/vocabulary.js";
|
|
19
|
+
import { escapeDslString } from "./utils/escape.js";
|
|
20
|
+
import { MAX_SEARCH_TEXT_LENGTH, sanitizeInput } from "./utils/sanitize.js";
|
|
21
|
+
import { validateFieldName } from "./utils/validate-field-name.js";
|
|
22
|
+
|
|
23
|
+
// Re-export types for backwards compatibility
|
|
24
|
+
export type { EntityType, SearchIndex, SortOrder, WhereOperator };
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Boolean connector between conditions.
|
|
28
|
+
*/
|
|
29
|
+
type BooleanConnector = "and" | "or" | "not";
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Represents a node in the boolean expression tree.
|
|
33
|
+
*/
|
|
34
|
+
type ExpressionNode =
|
|
35
|
+
| { readonly type: "condition"; readonly condition: string }
|
|
36
|
+
| { readonly type: "connector"; readonly connector: BooleanConnector }
|
|
37
|
+
| { readonly type: "group_start" }
|
|
38
|
+
| { readonly type: "group_end" };
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Fluent builder for constructing Dimensions DSL queries.
|
|
42
|
+
* Provides a type-safe way to build search queries with conditions, sorting, and pagination.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* const query = new QueryBuilder()
|
|
47
|
+
* .search("publications")
|
|
48
|
+
* .for("machine learning")
|
|
49
|
+
* .where("year", ">=", 2020)
|
|
50
|
+
* .fields(["id", "title", "doi"])
|
|
51
|
+
* .sort("times_cited", "desc")
|
|
52
|
+
* .limit(100)
|
|
53
|
+
* .build();
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export class QueryBuilder {
|
|
57
|
+
private readonly schemaStore: SchemaStore | undefined;
|
|
58
|
+
private entity: string | null = null;
|
|
59
|
+
private searchIndex: string | null = null;
|
|
60
|
+
private searchTerms: string | null = null;
|
|
61
|
+
private similarText: string | null = null;
|
|
62
|
+
private complexPhrase: string | null = null;
|
|
63
|
+
private complexMaxDist: number | null = null;
|
|
64
|
+
private minShouldMatchPhrase: string | null = null;
|
|
65
|
+
private minShouldMatchMin: number | null = null;
|
|
66
|
+
private expressionNodes: ExpressionNode[] = [];
|
|
67
|
+
private groupDepth: number = 0;
|
|
68
|
+
private pendingConnector: BooleanConnector | null = null;
|
|
69
|
+
private returnFields: string[] = [];
|
|
70
|
+
private unnestFields: string[] = [];
|
|
71
|
+
private sortField: string | null = null;
|
|
72
|
+
private sortOrder: SortOrder = "asc";
|
|
73
|
+
private skipValue: number | null = null;
|
|
74
|
+
private limitValue: number | null = null;
|
|
75
|
+
private facetClauses: FacetClause[] = [];
|
|
76
|
+
private timeSeriesClauses: TimeSeriesReturnClause[] = [];
|
|
77
|
+
private groupedClauses: GroupedReturnClause[] = [];
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @param schemaStore - Optional describe schema for entity/index validation
|
|
81
|
+
*/
|
|
82
|
+
constructor(schemaStore?: SchemaStore) {
|
|
83
|
+
this.schemaStore = schemaStore;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Adds a condition node to the expression tree.
|
|
88
|
+
* Handles automatic AND connector insertion.
|
|
89
|
+
* @param condition - The condition string to add
|
|
90
|
+
*/
|
|
91
|
+
private addConditionNode(condition: string): void {
|
|
92
|
+
// Add pending connector if exists
|
|
93
|
+
if (this.pendingConnector) {
|
|
94
|
+
this.expressionNodes.push({
|
|
95
|
+
type: "connector",
|
|
96
|
+
connector: this.pendingConnector,
|
|
97
|
+
});
|
|
98
|
+
this.pendingConnector = null;
|
|
99
|
+
} else if (this.expressionNodes.length > 0) {
|
|
100
|
+
// Default to AND if no connector specified
|
|
101
|
+
const lastNode = this.expressionNodes[this.expressionNodes.length - 1];
|
|
102
|
+
if (lastNode?.type === "condition" || lastNode?.type === "group_end") {
|
|
103
|
+
this.expressionNodes.push({ type: "connector", connector: "and" });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
this.expressionNodes.push({ type: "condition", condition });
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Determines if a space should be added before an expression node.
|
|
111
|
+
* Handles spacing rules for parentheses in boolean expressions.
|
|
112
|
+
* @param node - The current expression node
|
|
113
|
+
* @param prevNode - The previous expression node (or null if first)
|
|
114
|
+
* @returns True if a space should be added before the node
|
|
115
|
+
*/
|
|
116
|
+
private shouldAddSpaceBefore(node: ExpressionNode, prevNode: ExpressionNode | null): boolean {
|
|
117
|
+
if (prevNode === null) return false;
|
|
118
|
+
if (prevNode.type === "group_start") return false;
|
|
119
|
+
if (node.type === "group_end") return false;
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Sets the entity type to search.
|
|
125
|
+
* @param entity - The entity type to search (publications, grants, etc.)
|
|
126
|
+
* @returns This builder for chaining
|
|
127
|
+
* @throws {ValidationError} If entity type is invalid
|
|
128
|
+
*/
|
|
129
|
+
search(entity: EntityType | string): this {
|
|
130
|
+
assertValidEntity(this.schemaStore, entity);
|
|
131
|
+
this.entity = entity;
|
|
132
|
+
return this;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Sets the search index for full-text search.
|
|
137
|
+
* Requires search terms via {@link for} — building without search terms will throw.
|
|
138
|
+
* @param index - The search index to use
|
|
139
|
+
* @returns This builder for chaining
|
|
140
|
+
* @throws {ValidationError} If index is invalid
|
|
141
|
+
* @throws {ValidationError} If used without search terms at build time
|
|
142
|
+
*/
|
|
143
|
+
in(index: SearchIndex | string): this {
|
|
144
|
+
assertValidSearchIndex(this.schemaStore, this.entity, index);
|
|
145
|
+
this.searchIndex = index;
|
|
146
|
+
return this;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Sets the search terms for full-text search.
|
|
151
|
+
*
|
|
152
|
+
* **Note:** `"*"` is **not** a wildcard in the Dimensions DSL — it is treated as a literal
|
|
153
|
+
* string. To search all records without a text filter, simply omit the `for()` call and
|
|
154
|
+
* use `where()` conditions instead.
|
|
155
|
+
*
|
|
156
|
+
* @param terms - Search terms to look for
|
|
157
|
+
* @returns This builder for chaining
|
|
158
|
+
*/
|
|
159
|
+
for(terms: string): this {
|
|
160
|
+
const sanitized = sanitizeInput(terms);
|
|
161
|
+
if (sanitized.length > MAX_SEARCH_TEXT_LENGTH) {
|
|
162
|
+
throw new ValidationError(
|
|
163
|
+
`Search text exceeds maximum length of ${MAX_SEARCH_TEXT_LENGTH} characters`,
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
this.searchTerms = sanitized;
|
|
167
|
+
return this;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Sets the search to find semantically similar documents based on text.
|
|
172
|
+
* Uses the similar_documents() DSL function.
|
|
173
|
+
* @param text - The text (abstract, description) to find similar documents for
|
|
174
|
+
* @returns This builder for chaining
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```typescript
|
|
178
|
+
* const query = new QueryBuilder()
|
|
179
|
+
* .search("publications")
|
|
180
|
+
* .forSimilar("After spinal cord injury, macrophages infiltrate...")
|
|
181
|
+
* .where("year", ">", 2015)
|
|
182
|
+
* .limit(10)
|
|
183
|
+
* .build();
|
|
184
|
+
* // Generates: search publications for similar_documents("...") where year > 2015 ...
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
forSimilar(text: string): this {
|
|
188
|
+
const sanitized = sanitizeInput(text);
|
|
189
|
+
if (sanitized.length > MAX_SEARCH_TEXT_LENGTH) {
|
|
190
|
+
throw new ValidationError(
|
|
191
|
+
`Search text exceeds maximum length of ${MAX_SEARCH_TEXT_LENGTH} characters`,
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
this.similarText = sanitized;
|
|
195
|
+
return this;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Sets the search to use proximity matching via the complex() DSL function.
|
|
200
|
+
* Finds documents where search terms appear within a maximum distance of each other.
|
|
201
|
+
* @param phrase - The search phrase
|
|
202
|
+
* @param maxDist - Maximum distance between terms (must be >= 1)
|
|
203
|
+
* @returns This builder for chaining
|
|
204
|
+
* @throws {ValidationError} If maxDist is less than 1
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```typescript
|
|
208
|
+
* const query = new QueryBuilder()
|
|
209
|
+
* .search("publications")
|
|
210
|
+
* .forComplex("quantum networking", 3)
|
|
211
|
+
* .build();
|
|
212
|
+
* // Generates: search publications for complex("quantum networking", 3)
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
215
|
+
forComplex(phrase: string, maxDist: number): this {
|
|
216
|
+
if (maxDist < 1) {
|
|
217
|
+
throw new ValidationError("maxDist must be >= 1");
|
|
218
|
+
}
|
|
219
|
+
const sanitized = sanitizeInput(phrase);
|
|
220
|
+
if (sanitized.length > MAX_SEARCH_TEXT_LENGTH) {
|
|
221
|
+
throw new ValidationError(
|
|
222
|
+
`Search text exceeds maximum length of ${MAX_SEARCH_TEXT_LENGTH} characters`,
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
this.complexPhrase = sanitized;
|
|
226
|
+
this.complexMaxDist = maxDist;
|
|
227
|
+
return this;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Sets the search to use minimum term matching via the min_should_match() DSL function.
|
|
232
|
+
* Finds documents matching at least `min` of the terms in the phrase.
|
|
233
|
+
* @param phrase - The search phrase
|
|
234
|
+
* @param min - Minimum number of terms that must match (must be >= 1)
|
|
235
|
+
* @returns This builder for chaining
|
|
236
|
+
* @throws {ValidationError} If min is less than 1
|
|
237
|
+
*
|
|
238
|
+
* @example
|
|
239
|
+
* ```typescript
|
|
240
|
+
* const query = new QueryBuilder()
|
|
241
|
+
* .search("publications")
|
|
242
|
+
* .forMinShouldMatch("quantum OR optical networking", 2)
|
|
243
|
+
* .build();
|
|
244
|
+
* // Generates: search publications for min_should_match("quantum OR optical networking", 2)
|
|
245
|
+
* ```
|
|
246
|
+
*/
|
|
247
|
+
forMinShouldMatch(phrase: string, min: number): this {
|
|
248
|
+
if (min < 1) {
|
|
249
|
+
throw new ValidationError("min must be >= 1");
|
|
250
|
+
}
|
|
251
|
+
const sanitized = sanitizeInput(phrase);
|
|
252
|
+
if (sanitized.length > MAX_SEARCH_TEXT_LENGTH) {
|
|
253
|
+
throw new ValidationError(
|
|
254
|
+
`Search text exceeds maximum length of ${MAX_SEARCH_TEXT_LENGTH} characters`,
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
this.minShouldMatchPhrase = sanitized;
|
|
258
|
+
this.minShouldMatchMin = min;
|
|
259
|
+
return this;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Adds a where clause condition.
|
|
264
|
+
* @param field - Field name to filter on
|
|
265
|
+
* @param operator - Comparison operator
|
|
266
|
+
* @param value - Value to compare against
|
|
267
|
+
* @returns This builder for chaining
|
|
268
|
+
* @throws {ValidationError} If operator is invalid
|
|
269
|
+
*/
|
|
270
|
+
where(field: string, operator: WhereOperator, value: string | number | boolean): this {
|
|
271
|
+
validateFieldName(field);
|
|
272
|
+
if (!VALID_OPERATORS.includes(operator)) {
|
|
273
|
+
throw new ValidationError(`Invalid operator: ${operator}`);
|
|
274
|
+
}
|
|
275
|
+
const formattedValue = typeof value === "string" ? `"${escapeDslString(value)}"` : value;
|
|
276
|
+
this.addConditionNode(`${field} ${operator} ${formattedValue}`);
|
|
277
|
+
return this;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Adds a condition checking if a field is empty.
|
|
282
|
+
* @param field - Field name to check
|
|
283
|
+
* @returns This builder for chaining
|
|
284
|
+
*/
|
|
285
|
+
whereEmpty(field: string): this {
|
|
286
|
+
validateFieldName(field);
|
|
287
|
+
this.addConditionNode(`${field} is empty`);
|
|
288
|
+
return this;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Adds a condition checking if a field is not empty.
|
|
293
|
+
* @param field - Field name to check
|
|
294
|
+
* @returns This builder for chaining
|
|
295
|
+
*/
|
|
296
|
+
whereNotEmpty(field: string): this {
|
|
297
|
+
validateFieldName(field);
|
|
298
|
+
this.addConditionNode(`${field} is not empty`);
|
|
299
|
+
return this;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Adds a list filter condition (field in ["a", "b", "c"]).
|
|
304
|
+
* @param field - Field name to filter on
|
|
305
|
+
* @param values - Array of values to match
|
|
306
|
+
* @returns This builder for chaining
|
|
307
|
+
* @throws {ValidationError} If values array is empty
|
|
308
|
+
* @throws {ValidationError} If values array exceeds 400 items (DSL limit)
|
|
309
|
+
*/
|
|
310
|
+
whereIn(field: string, values: readonly (string | number)[]): this {
|
|
311
|
+
validateFieldName(field);
|
|
312
|
+
if (values.length === 0) {
|
|
313
|
+
throw new ValidationError("List filter must have at least one value");
|
|
314
|
+
}
|
|
315
|
+
if (values.length > 400) {
|
|
316
|
+
throw new ValidationError("List filter cannot exceed 400 items");
|
|
317
|
+
}
|
|
318
|
+
const formattedValues = values
|
|
319
|
+
.map((v) => (typeof v === "string" ? `"${escapeDslString(v)}"` : v))
|
|
320
|
+
.join(", ");
|
|
321
|
+
this.addConditionNode(`${field} in [${formattedValues}]`);
|
|
322
|
+
return this;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Adds a range filter condition (field in [start:end]).
|
|
327
|
+
* @param field - Field name to filter on
|
|
328
|
+
* @param start - Start of range (inclusive)
|
|
329
|
+
* @param end - End of range (inclusive)
|
|
330
|
+
* @returns This builder for chaining
|
|
331
|
+
* @throws {ValidationError} If numeric start is greater than numeric end
|
|
332
|
+
*/
|
|
333
|
+
whereRange(field: string, start: string | number, end: string | number): this {
|
|
334
|
+
validateFieldName(field);
|
|
335
|
+
if (typeof start === "number" && typeof end === "number" && start > end) {
|
|
336
|
+
throw new ValidationError("Range start must not be greater than end");
|
|
337
|
+
}
|
|
338
|
+
const formattedStart = typeof start === "string" ? `"${escapeDslString(start)}"` : start;
|
|
339
|
+
const formattedEnd = typeof end === "string" ? `"${escapeDslString(end)}"` : end;
|
|
340
|
+
this.addConditionNode(`${field} in [${formattedStart}:${formattedEnd}]`);
|
|
341
|
+
return this;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Sets the next connector to OR.
|
|
346
|
+
* @returns This builder for chaining
|
|
347
|
+
*/
|
|
348
|
+
or(): this {
|
|
349
|
+
this.pendingConnector = "or";
|
|
350
|
+
return this;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Sets the next connector to NOT.
|
|
355
|
+
* @returns This builder for chaining
|
|
356
|
+
*/
|
|
357
|
+
not(): this {
|
|
358
|
+
this.pendingConnector = "not";
|
|
359
|
+
return this;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Sets the next connector to AND explicitly.
|
|
364
|
+
* Note: AND is the default connector between conditions, but this method
|
|
365
|
+
* provides API symmetry with or() and not().
|
|
366
|
+
* @returns This builder for chaining
|
|
367
|
+
*/
|
|
368
|
+
and(): this {
|
|
369
|
+
this.pendingConnector = "and";
|
|
370
|
+
return this;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Opens a parenthesized group.
|
|
375
|
+
* @returns This builder for chaining
|
|
376
|
+
*/
|
|
377
|
+
openGroup(): this {
|
|
378
|
+
// Add pending connector if exists
|
|
379
|
+
if (this.pendingConnector) {
|
|
380
|
+
this.expressionNodes.push({
|
|
381
|
+
type: "connector",
|
|
382
|
+
connector: this.pendingConnector,
|
|
383
|
+
});
|
|
384
|
+
this.pendingConnector = null;
|
|
385
|
+
} else if (this.expressionNodes.length > 0) {
|
|
386
|
+
const lastNode = this.expressionNodes[this.expressionNodes.length - 1];
|
|
387
|
+
if (lastNode?.type === "condition" || lastNode?.type === "group_end") {
|
|
388
|
+
this.expressionNodes.push({ type: "connector", connector: "and" });
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
this.expressionNodes.push({ type: "group_start" });
|
|
392
|
+
this.groupDepth++;
|
|
393
|
+
return this;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Closes a parenthesized group.
|
|
398
|
+
* @returns This builder for chaining
|
|
399
|
+
* @throws {ValidationError} If no group is open
|
|
400
|
+
*/
|
|
401
|
+
closeGroup(): this {
|
|
402
|
+
if (this.groupDepth === 0) {
|
|
403
|
+
throw new ValidationError("No group to close");
|
|
404
|
+
}
|
|
405
|
+
this.expressionNodes.push({ type: "group_end" });
|
|
406
|
+
this.groupDepth--;
|
|
407
|
+
return this;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Adds a count filter condition (count(field) op value).
|
|
412
|
+
* @param field - Multi-value field name to count
|
|
413
|
+
* @param operator - Comparison operator
|
|
414
|
+
* @param value - Count to compare against
|
|
415
|
+
* @returns This builder for chaining
|
|
416
|
+
*/
|
|
417
|
+
whereCount(field: string, operator: "=" | "!=" | ">" | "<" | ">=" | "<=", value: number): this {
|
|
418
|
+
validateFieldName(field);
|
|
419
|
+
this.addConditionNode(`count(${field}) ${operator} ${value}`);
|
|
420
|
+
return this;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Sets the fields to return.
|
|
425
|
+
* @param fieldList - Array of field names to return
|
|
426
|
+
* @returns This builder for chaining
|
|
427
|
+
*/
|
|
428
|
+
fields(fieldList: string[]): this {
|
|
429
|
+
for (const field of fieldList) {
|
|
430
|
+
validateFieldName(field);
|
|
431
|
+
}
|
|
432
|
+
this.returnFields = [...fieldList];
|
|
433
|
+
return this;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Sets the fields to return including unnest operations.
|
|
438
|
+
* Unnest flattens nested arrays into separate rows (Cartesian product).
|
|
439
|
+
* DSL: return publications[id+title+unnest(researchers)+unnest(category_for)]
|
|
440
|
+
*
|
|
441
|
+
* @param fieldList - Array of regular field names to return
|
|
442
|
+
* @param unnestFieldList - Array of field names to unnest
|
|
443
|
+
* @returns This builder for chaining
|
|
444
|
+
* @throws {ValidationError} If any unnest field name is empty or whitespace-only
|
|
445
|
+
*
|
|
446
|
+
* @example
|
|
447
|
+
* ```typescript
|
|
448
|
+
* const query = new QueryBuilder()
|
|
449
|
+
* .search("publications")
|
|
450
|
+
* .for("machine learning")
|
|
451
|
+
* .fieldsWithUnnest(["id", "title"], ["researchers", "category_for"])
|
|
452
|
+
* .build();
|
|
453
|
+
* // Returns flattened rows - one row per researcher × category combination
|
|
454
|
+
* ```
|
|
455
|
+
*/
|
|
456
|
+
fieldsWithUnnest(fieldList: readonly string[], unnestFieldList: readonly string[]): this {
|
|
457
|
+
for (const field of fieldList) {
|
|
458
|
+
validateFieldName(field);
|
|
459
|
+
}
|
|
460
|
+
for (const field of unnestFieldList) {
|
|
461
|
+
validateFieldName(field);
|
|
462
|
+
}
|
|
463
|
+
this.returnFields = [...fieldList];
|
|
464
|
+
this.unnestFields = [...unnestFieldList];
|
|
465
|
+
return this;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Adds an unnest field to the return clause.
|
|
470
|
+
* Can be chained with fields() to add unnest operations.
|
|
471
|
+
* DSL: return publications[id+title+unnest(researchers)]
|
|
472
|
+
*
|
|
473
|
+
* @param field - Field name to unnest
|
|
474
|
+
* @returns This builder for chaining
|
|
475
|
+
* @throws {ValidationError} If field name is empty or whitespace-only
|
|
476
|
+
*
|
|
477
|
+
* @example
|
|
478
|
+
* ```typescript
|
|
479
|
+
* const query = new QueryBuilder()
|
|
480
|
+
* .search("publications")
|
|
481
|
+
* .for("test")
|
|
482
|
+
* .fields(["id", "title"])
|
|
483
|
+
* .addUnnest("researchers")
|
|
484
|
+
* .addUnnest("category_for")
|
|
485
|
+
* .build();
|
|
486
|
+
* ```
|
|
487
|
+
*/
|
|
488
|
+
addUnnest(field: string): this {
|
|
489
|
+
validateFieldName(field);
|
|
490
|
+
this.unnestFields.push(field);
|
|
491
|
+
return this;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Sets the sort field and order.
|
|
496
|
+
* @param field - Field name to sort by
|
|
497
|
+
* @param order - Sort direction (asc or desc)
|
|
498
|
+
* @returns This builder for chaining
|
|
499
|
+
*/
|
|
500
|
+
sort(field: string, order: SortOrder = "asc"): this {
|
|
501
|
+
validateFieldName(field);
|
|
502
|
+
this.sortField = field;
|
|
503
|
+
this.sortOrder = order;
|
|
504
|
+
return this;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Sets the number of results to skip (for pagination).
|
|
509
|
+
* @param count - Number of results to skip
|
|
510
|
+
* @returns This builder for chaining
|
|
511
|
+
* @throws {ValidationError} If count is negative
|
|
512
|
+
*/
|
|
513
|
+
skip(count: number): this {
|
|
514
|
+
if (count < 0) {
|
|
515
|
+
throw new ValidationError("Skip must be non-negative");
|
|
516
|
+
}
|
|
517
|
+
this.skipValue = count;
|
|
518
|
+
return this;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* Sets the maximum number of results to return.
|
|
523
|
+
* @param count - Maximum number of results
|
|
524
|
+
* @returns This builder for chaining
|
|
525
|
+
* @throws {ValidationError} If count is negative
|
|
526
|
+
*/
|
|
527
|
+
limit(count: number): this {
|
|
528
|
+
if (count < 0) {
|
|
529
|
+
throw new ValidationError("Limit must be non-negative");
|
|
530
|
+
}
|
|
531
|
+
this.limitValue = count;
|
|
532
|
+
return this;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Adds a facet return clause.
|
|
537
|
+
* DSL: return <field> [limit <n>]
|
|
538
|
+
* @param field - Facet field name
|
|
539
|
+
* @param options - Optional limit for facet results
|
|
540
|
+
* @returns This builder for chaining
|
|
541
|
+
* @throws {ValidationError} If field is empty or whitespace-only
|
|
542
|
+
* @throws {ValidationError} If limit is negative
|
|
543
|
+
*/
|
|
544
|
+
returnFacet(field: string, options?: { limit?: number }): this {
|
|
545
|
+
validateFieldName(field);
|
|
546
|
+
if (options?.limit !== undefined && options.limit < 0) {
|
|
547
|
+
throw new ValidationError("Facet limit must be non-negative", {
|
|
548
|
+
limit: options.limit,
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
const clause: FacetReturnClause = {
|
|
552
|
+
type: "facet",
|
|
553
|
+
field,
|
|
554
|
+
limit: options?.limit,
|
|
555
|
+
};
|
|
556
|
+
this.facetClauses.push(clause);
|
|
557
|
+
return this;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Adds an aggregated facet return clause.
|
|
562
|
+
* DSL: return <field> aggregate <indicators> [sort by <indicator> <order>] [limit <n>]
|
|
563
|
+
* @param field - Facet field name
|
|
564
|
+
* @param indicators - Array of indicator names to aggregate
|
|
565
|
+
* @param options - Optional sort and limit options
|
|
566
|
+
* @returns This builder for chaining
|
|
567
|
+
* @throws {ValidationError} If field is empty or whitespace-only
|
|
568
|
+
* @throws {ValidationError} If indicators array is empty
|
|
569
|
+
* @throws {ValidationError} If any indicator is empty or whitespace-only
|
|
570
|
+
* @throws {ValidationError} If limit is negative
|
|
571
|
+
* @throws {ValidationError} If sortBy is not one of indicators or "count"
|
|
572
|
+
*/
|
|
573
|
+
returnAggregate(
|
|
574
|
+
field: string,
|
|
575
|
+
indicators: readonly string[],
|
|
576
|
+
options?: {
|
|
577
|
+
sortBy?: string;
|
|
578
|
+
sortOrder?: SortOrder;
|
|
579
|
+
limit?: number;
|
|
580
|
+
},
|
|
581
|
+
): this {
|
|
582
|
+
validateFieldName(field);
|
|
583
|
+
if (indicators.length === 0) {
|
|
584
|
+
throw new ValidationError("Aggregate must have at least one indicator", {
|
|
585
|
+
field,
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
for (const indicator of indicators) {
|
|
589
|
+
if (!indicator || indicator.trim().length === 0) {
|
|
590
|
+
throw new ValidationError("Indicator names must be non-empty strings", {
|
|
591
|
+
field,
|
|
592
|
+
indicator,
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
if (options?.limit !== undefined && options.limit < 0) {
|
|
597
|
+
throw new ValidationError("Facet limit must be non-negative", {
|
|
598
|
+
field,
|
|
599
|
+
limit: options.limit,
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
if (options?.sortBy) {
|
|
603
|
+
const validSortTargets = [...indicators, "count"];
|
|
604
|
+
if (!validSortTargets.includes(options.sortBy)) {
|
|
605
|
+
throw new ValidationError(
|
|
606
|
+
`sortBy must be one of [${validSortTargets.join(", ")}], got "${options.sortBy}"`,
|
|
607
|
+
{ field, sortBy: options.sortBy, validSortTargets },
|
|
608
|
+
);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
const clause: AggregatedFacetReturnClause = {
|
|
612
|
+
type: "aggregated_facet",
|
|
613
|
+
field,
|
|
614
|
+
indicators,
|
|
615
|
+
sortBy: options?.sortBy,
|
|
616
|
+
sortOrder: options?.sortOrder ?? "desc",
|
|
617
|
+
limit: options?.limit,
|
|
618
|
+
};
|
|
619
|
+
this.facetClauses.push(clause);
|
|
620
|
+
return this;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* Adds a citations_per_year time-series return clause.
|
|
625
|
+
* Returns citation counts per year for the specified range.
|
|
626
|
+
* DSL: return citations_per_year(2010, 2023)
|
|
627
|
+
*
|
|
628
|
+
* @param startYear - Start year for the time series (inclusive)
|
|
629
|
+
* @param endYear - End year for the time series (inclusive)
|
|
630
|
+
* @returns This builder for chaining
|
|
631
|
+
* @throws {ValidationError} If startYear is greater than endYear
|
|
632
|
+
*
|
|
633
|
+
* @example
|
|
634
|
+
* ```typescript
|
|
635
|
+
* const query = new QueryBuilder()
|
|
636
|
+
* .search("publications")
|
|
637
|
+
* .for("machine learning")
|
|
638
|
+
* .returnCitationsPerYear(2010, 2023)
|
|
639
|
+
* .build();
|
|
640
|
+
* // "search publications for ... return citations_per_year(2010, 2023)"
|
|
641
|
+
* ```
|
|
642
|
+
*/
|
|
643
|
+
returnCitationsPerYear(startYear: number, endYear: number): this {
|
|
644
|
+
if (startYear > endYear) {
|
|
645
|
+
throw new ValidationError("startYear must not be greater than endYear", {
|
|
646
|
+
startYear,
|
|
647
|
+
endYear,
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
this.timeSeriesClauses.push({
|
|
651
|
+
type: "time_series",
|
|
652
|
+
function: "citations_per_year",
|
|
653
|
+
startYear,
|
|
654
|
+
endYear,
|
|
655
|
+
});
|
|
656
|
+
return this;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* Adds a funding_per_year time-series return clause.
|
|
661
|
+
* Returns funding amounts per year for the specified range.
|
|
662
|
+
* DSL: return funding_per_year(2015, 2023, "USD")
|
|
663
|
+
*
|
|
664
|
+
* @param startYear - Start year for the time series (inclusive)
|
|
665
|
+
* @param endYear - End year for the time series (inclusive)
|
|
666
|
+
* @param currency - Currency for the funding amounts (default: "USD")
|
|
667
|
+
* @returns This builder for chaining
|
|
668
|
+
* @throws {ValidationError} If startYear is greater than endYear
|
|
669
|
+
*
|
|
670
|
+
* @example
|
|
671
|
+
* ```typescript
|
|
672
|
+
* const query = new QueryBuilder()
|
|
673
|
+
* .search("grants")
|
|
674
|
+
* .for("cancer research")
|
|
675
|
+
* .returnFundingPerYear(2015, 2023, "EUR")
|
|
676
|
+
* .build();
|
|
677
|
+
* // "search grants for ... return funding_per_year(2015, 2023, "EUR")"
|
|
678
|
+
* ```
|
|
679
|
+
*/
|
|
680
|
+
returnFundingPerYear(startYear: number, endYear: number, currency: Currency = "USD"): this {
|
|
681
|
+
if (startYear > endYear) {
|
|
682
|
+
throw new ValidationError("startYear must not be greater than endYear", {
|
|
683
|
+
startYear,
|
|
684
|
+
endYear,
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
this.timeSeriesClauses.push({
|
|
688
|
+
type: "time_series",
|
|
689
|
+
function: "funding_per_year",
|
|
690
|
+
startYear,
|
|
691
|
+
endYear,
|
|
692
|
+
currency,
|
|
693
|
+
});
|
|
694
|
+
return this;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* Adds a grouped entity return clause.
|
|
699
|
+
* DSL: return in "docs" publications[id + title]
|
|
700
|
+
*
|
|
701
|
+
* @param groupName - Name for the result group
|
|
702
|
+
* @param options - Entity return options (fields, limit, skip, sort)
|
|
703
|
+
* @returns This builder for chaining
|
|
704
|
+
* @throws {ValidationError} If groupName is empty or whitespace-only
|
|
705
|
+
*
|
|
706
|
+
* @example
|
|
707
|
+
* ```typescript
|
|
708
|
+
* const query = new QueryBuilder()
|
|
709
|
+
* .search("publications")
|
|
710
|
+
* .for("test")
|
|
711
|
+
* .returnGrouped("docs", { fields: ["id", "title"], limit: 10 })
|
|
712
|
+
* .build();
|
|
713
|
+
* // "... return in "docs" publications[id+title] limit 10"
|
|
714
|
+
* ```
|
|
715
|
+
*/
|
|
716
|
+
returnGrouped(
|
|
717
|
+
groupName: string,
|
|
718
|
+
options?: {
|
|
719
|
+
fields?: readonly string[];
|
|
720
|
+
limit?: number;
|
|
721
|
+
skip?: number;
|
|
722
|
+
sortField?: string;
|
|
723
|
+
sortOrder?: SortOrder;
|
|
724
|
+
},
|
|
725
|
+
): this {
|
|
726
|
+
if (!groupName || groupName.trim().length === 0) {
|
|
727
|
+
throw new ValidationError("Group name must be non-empty", { groupName });
|
|
728
|
+
}
|
|
729
|
+
if (options?.fields) {
|
|
730
|
+
for (const field of options.fields) {
|
|
731
|
+
validateFieldName(field);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
if (options?.sortField) {
|
|
735
|
+
validateFieldName(options.sortField);
|
|
736
|
+
}
|
|
737
|
+
this.groupedClauses.push({
|
|
738
|
+
type: "grouped",
|
|
739
|
+
groupName,
|
|
740
|
+
entityOrFacet: {
|
|
741
|
+
type: "entity",
|
|
742
|
+
fields: options?.fields,
|
|
743
|
+
limit: options?.limit,
|
|
744
|
+
skip: options?.skip,
|
|
745
|
+
sortField: options?.sortField,
|
|
746
|
+
sortOrder: options?.sortOrder,
|
|
747
|
+
},
|
|
748
|
+
});
|
|
749
|
+
return this;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* Adds a grouped facet return clause (simple facet).
|
|
754
|
+
* DSL: return in "facets" year limit 10
|
|
755
|
+
*
|
|
756
|
+
* @param groupName - Name for the result group
|
|
757
|
+
* @param field - Facet field name
|
|
758
|
+
* @param options - Optional limit for facet results
|
|
759
|
+
* @returns This builder for chaining
|
|
760
|
+
* @throws {ValidationError} If groupName or field is empty
|
|
761
|
+
*
|
|
762
|
+
* @example
|
|
763
|
+
* ```typescript
|
|
764
|
+
* const query = new QueryBuilder()
|
|
765
|
+
* .search("publications")
|
|
766
|
+
* .for("test")
|
|
767
|
+
* .returnGroupedFacet("years", "year", { limit: 20 })
|
|
768
|
+
* .build();
|
|
769
|
+
* // "... return in "years" year limit 20"
|
|
770
|
+
* ```
|
|
771
|
+
*/
|
|
772
|
+
returnGroupedFacet(groupName: string, field: string, options?: { limit?: number }): this {
|
|
773
|
+
if (!groupName || groupName.trim().length === 0) {
|
|
774
|
+
throw new ValidationError("Group name must be non-empty", { groupName });
|
|
775
|
+
}
|
|
776
|
+
validateFieldName(field);
|
|
777
|
+
this.groupedClauses.push({
|
|
778
|
+
type: "grouped",
|
|
779
|
+
groupName,
|
|
780
|
+
entityOrFacet: {
|
|
781
|
+
type: "facet",
|
|
782
|
+
field,
|
|
783
|
+
limit: options?.limit,
|
|
784
|
+
},
|
|
785
|
+
});
|
|
786
|
+
return this;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
/**
|
|
790
|
+
* Adds a grouped aggregated facet return clause.
|
|
791
|
+
* DSL: return in "metrics" funders aggregate rcr_avg, funding_usd sort by rcr_avg desc
|
|
792
|
+
*
|
|
793
|
+
* @param groupName - Name for the result group
|
|
794
|
+
* @param field - Facet field name
|
|
795
|
+
* @param indicators - Array of indicator names to aggregate
|
|
796
|
+
* @param options - Optional sort and limit options
|
|
797
|
+
* @returns This builder for chaining
|
|
798
|
+
* @throws {ValidationError} If groupName, field, or indicators are invalid
|
|
799
|
+
*
|
|
800
|
+
* @example
|
|
801
|
+
* ```typescript
|
|
802
|
+
* const query = new QueryBuilder()
|
|
803
|
+
* .search("publications")
|
|
804
|
+
* .for("test")
|
|
805
|
+
* .returnGroupedAggregate("metrics", "funders", ["rcr_avg"], { sortBy: "rcr_avg" })
|
|
806
|
+
* .build();
|
|
807
|
+
* // "... return in "metrics" funders aggregate rcr_avg sort by rcr_avg desc"
|
|
808
|
+
* ```
|
|
809
|
+
*/
|
|
810
|
+
returnGroupedAggregate(
|
|
811
|
+
groupName: string,
|
|
812
|
+
field: string,
|
|
813
|
+
indicators: readonly string[],
|
|
814
|
+
options?: {
|
|
815
|
+
sortBy?: string;
|
|
816
|
+
sortOrder?: SortOrder;
|
|
817
|
+
limit?: number;
|
|
818
|
+
},
|
|
819
|
+
): this {
|
|
820
|
+
if (!groupName || groupName.trim().length === 0) {
|
|
821
|
+
throw new ValidationError("Group name must be non-empty", { groupName });
|
|
822
|
+
}
|
|
823
|
+
validateFieldName(field);
|
|
824
|
+
if (indicators.length === 0) {
|
|
825
|
+
throw new ValidationError("Aggregate must have at least one indicator", {
|
|
826
|
+
field,
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
this.groupedClauses.push({
|
|
830
|
+
type: "grouped",
|
|
831
|
+
groupName,
|
|
832
|
+
entityOrFacet: {
|
|
833
|
+
type: "aggregated_facet",
|
|
834
|
+
field,
|
|
835
|
+
indicators,
|
|
836
|
+
sortBy: options?.sortBy,
|
|
837
|
+
sortOrder: options?.sortOrder ?? "desc",
|
|
838
|
+
limit: options?.limit,
|
|
839
|
+
},
|
|
840
|
+
});
|
|
841
|
+
return this;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
/**
|
|
845
|
+
* Builds the DSL query string.
|
|
846
|
+
* @returns The constructed DSL query
|
|
847
|
+
* @throws {ValidationError} If entity type is not set
|
|
848
|
+
*/
|
|
849
|
+
build(): string {
|
|
850
|
+
if (!this.entity) {
|
|
851
|
+
throw new ValidationError("Entity type must be specified");
|
|
852
|
+
}
|
|
853
|
+
const parts: string[] = [];
|
|
854
|
+
const searchTerms = this.searchTerms;
|
|
855
|
+
|
|
856
|
+
// search <entity> [in <index>] for "<terms>" OR function expression search
|
|
857
|
+
if (this.similarText) {
|
|
858
|
+
const escapedText = escapeDslString(this.similarText);
|
|
859
|
+
parts.push(`search ${this.entity} for similar_documents("${escapedText}")`);
|
|
860
|
+
} else if (this.complexPhrase !== null) {
|
|
861
|
+
const escapedPhrase = escapeDslString(this.complexPhrase);
|
|
862
|
+
const indexPart =
|
|
863
|
+
this.searchIndex && this.searchIndex !== "full_data" ? ` in ${this.searchIndex}` : "";
|
|
864
|
+
parts.push(
|
|
865
|
+
`search ${this.entity}${indexPart} for complex("${escapedPhrase}", ${this.complexMaxDist})`,
|
|
866
|
+
);
|
|
867
|
+
} else if (this.minShouldMatchPhrase !== null) {
|
|
868
|
+
const escapedPhrase = escapeDslString(this.minShouldMatchPhrase);
|
|
869
|
+
const indexPart =
|
|
870
|
+
this.searchIndex && this.searchIndex !== "full_data" ? ` in ${this.searchIndex}` : "";
|
|
871
|
+
parts.push(
|
|
872
|
+
`search ${this.entity}${indexPart} for min_should_match("${escapedPhrase}", ${this.minShouldMatchMin})`,
|
|
873
|
+
);
|
|
874
|
+
} else if (searchTerms && this.searchIndex && this.searchIndex !== "full_data") {
|
|
875
|
+
parts.push(
|
|
876
|
+
`search ${this.entity} in ${this.searchIndex} for "${escapeDslString(searchTerms)}"`,
|
|
877
|
+
);
|
|
878
|
+
} else if (searchTerms) {
|
|
879
|
+
parts.push(`search ${this.entity} for "${escapeDslString(searchTerms)}"`);
|
|
880
|
+
} else {
|
|
881
|
+
if (this.searchIndex && this.searchIndex !== "full_data") {
|
|
882
|
+
throw new ValidationError("Search index requires search terms: call for() before in()");
|
|
883
|
+
}
|
|
884
|
+
parts.push(`search ${this.entity}`);
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
// Check for unbalanced parentheses
|
|
888
|
+
if (this.groupDepth !== 0) {
|
|
889
|
+
throw new ValidationError("Unbalanced parentheses: unclosed group");
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
// where <conditions> - build from expression tree
|
|
893
|
+
if (this.expressionNodes.length > 0) {
|
|
894
|
+
let whereStr = "";
|
|
895
|
+
for (let i = 0; i < this.expressionNodes.length; i++) {
|
|
896
|
+
const node = this.expressionNodes[i];
|
|
897
|
+
const prevNode = i > 0 ? this.expressionNodes[i - 1] : null;
|
|
898
|
+
|
|
899
|
+
if (this.shouldAddSpaceBefore(node, prevNode)) {
|
|
900
|
+
whereStr += " ";
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
switch (node.type) {
|
|
904
|
+
case "condition":
|
|
905
|
+
whereStr += node.condition;
|
|
906
|
+
break;
|
|
907
|
+
case "connector":
|
|
908
|
+
whereStr += node.connector;
|
|
909
|
+
break;
|
|
910
|
+
case "group_start":
|
|
911
|
+
whereStr += "(";
|
|
912
|
+
break;
|
|
913
|
+
case "group_end":
|
|
914
|
+
whereStr += ")";
|
|
915
|
+
break;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
parts.push(`where ${whereStr}`);
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
// return <entity>[<fields>] or return <entity>
|
|
922
|
+
// Note: return clause is required before limit/skip/sort modifiers
|
|
923
|
+
// Note: fields must be separated with '+' not ','
|
|
924
|
+
// Note: unnest() wraps fields that should be flattened
|
|
925
|
+
const hasFields = this.returnFields.length > 0 || this.unnestFields.length > 0;
|
|
926
|
+
const hasOtherReturnClauses =
|
|
927
|
+
this.facetClauses.length > 0 ||
|
|
928
|
+
this.timeSeriesClauses.length > 0 ||
|
|
929
|
+
this.groupedClauses.length > 0;
|
|
930
|
+
|
|
931
|
+
// Validate limit(0) usage - the Dimensions API rejects "return <entity> limit 0"
|
|
932
|
+
if (this.limitValue === 0) {
|
|
933
|
+
if (!hasOtherReturnClauses) {
|
|
934
|
+
throw new ValidationError(
|
|
935
|
+
"limit(0) requires at least one facet, time-series, or grouped return clause. " +
|
|
936
|
+
"The Dimensions API does not support 'return <entity> limit 0'. " +
|
|
937
|
+
"Use returnFacet(), returnCitationsPerYear(), or similar to get facet-only results.",
|
|
938
|
+
{ limit: 0 },
|
|
939
|
+
);
|
|
940
|
+
}
|
|
941
|
+
if (hasFields) {
|
|
942
|
+
throw new ValidationError(
|
|
943
|
+
"limit(0) cannot be used with fields(). " +
|
|
944
|
+
"The Dimensions API does not support 'return <entity>[fields] limit 0'. " +
|
|
945
|
+
"Either remove fields() to get facet-only results, or use limit > 0.",
|
|
946
|
+
{ limit: 0, fields: this.returnFields },
|
|
947
|
+
);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
// When limit=0 with facets/time-series/grouped returns and no fields,
|
|
952
|
+
// skip the entire entity return section (return clause + modifiers).
|
|
953
|
+
// User intent: "I don't want entity results, only facet results."
|
|
954
|
+
const skipEntityReturn = this.limitValue === 0 && hasOtherReturnClauses && !hasFields;
|
|
955
|
+
|
|
956
|
+
if (hasFields) {
|
|
957
|
+
const allFieldParts: string[] = [];
|
|
958
|
+
// Add regular fields
|
|
959
|
+
for (const field of this.returnFields) {
|
|
960
|
+
allFieldParts.push(field);
|
|
961
|
+
}
|
|
962
|
+
// Add unnested fields
|
|
963
|
+
for (const field of this.unnestFields) {
|
|
964
|
+
allFieldParts.push(`unnest(${field})`);
|
|
965
|
+
}
|
|
966
|
+
parts.push(`return ${this.entity}[${allFieldParts.join("+")}]`);
|
|
967
|
+
} else if (
|
|
968
|
+
!skipEntityReturn &&
|
|
969
|
+
(this.sortField !== null || this.skipValue !== null || this.limitValue !== null)
|
|
970
|
+
) {
|
|
971
|
+
// API requires return clause when using modifiers
|
|
972
|
+
parts.push(`return ${this.entity}`);
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
// sort by <field> <order>
|
|
976
|
+
// Skip when suppressing entity return (sort only applies to entity results)
|
|
977
|
+
if (this.sortField && !skipEntityReturn) {
|
|
978
|
+
parts.push(`sort by ${this.sortField} ${this.sortOrder}`);
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
// limit <n> (must come before skip)
|
|
982
|
+
// Skip when suppressing entity return
|
|
983
|
+
if (this.limitValue !== null && !skipEntityReturn) {
|
|
984
|
+
parts.push(`limit ${this.limitValue}`);
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
// skip <n> (must come after limit)
|
|
988
|
+
// Skip when suppressing entity return
|
|
989
|
+
if (this.skipValue !== null && !skipEntityReturn) {
|
|
990
|
+
parts.push(`skip ${this.skipValue}`);
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
// Facet return clauses
|
|
994
|
+
for (const clause of this.facetClauses) {
|
|
995
|
+
let facetDsl = `return ${clause.field}`;
|
|
996
|
+
|
|
997
|
+
if (clause.type === "aggregated_facet" && clause.indicators.length > 0) {
|
|
998
|
+
facetDsl += ` aggregate ${clause.indicators.join(", ")}`;
|
|
999
|
+
if (clause.sortBy) {
|
|
1000
|
+
facetDsl += ` sort by ${clause.sortBy} ${clause.sortOrder}`;
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
if (clause.limit !== undefined) {
|
|
1005
|
+
facetDsl += ` limit ${clause.limit}`;
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
parts.push(facetDsl);
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
// Time-series return clauses
|
|
1012
|
+
for (const clause of this.timeSeriesClauses) {
|
|
1013
|
+
if (clause.function === "citations_per_year") {
|
|
1014
|
+
parts.push(`return citations_per_year(${clause.startYear}, ${clause.endYear})`);
|
|
1015
|
+
} else if (clause.function === "funding_per_year") {
|
|
1016
|
+
parts.push(
|
|
1017
|
+
`return funding_per_year(${clause.startYear}, ${clause.endYear}, "${clause.currency}")`,
|
|
1018
|
+
);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
// Grouped return clauses
|
|
1023
|
+
for (const clause of this.groupedClauses) {
|
|
1024
|
+
const inner = clause.entityOrFacet;
|
|
1025
|
+
let groupedDsl = `return in "${escapeDslString(clause.groupName)}"`;
|
|
1026
|
+
|
|
1027
|
+
if (inner.type === "entity") {
|
|
1028
|
+
if (inner.fields && inner.fields.length > 0) {
|
|
1029
|
+
groupedDsl += ` ${this.entity}[${inner.fields.join("+")}]`;
|
|
1030
|
+
} else {
|
|
1031
|
+
groupedDsl += ` ${this.entity}`;
|
|
1032
|
+
}
|
|
1033
|
+
if (inner.sortField) {
|
|
1034
|
+
groupedDsl += ` sort by ${inner.sortField} ${inner.sortOrder ?? "asc"}`;
|
|
1035
|
+
}
|
|
1036
|
+
if (inner.limit !== undefined) {
|
|
1037
|
+
groupedDsl += ` limit ${inner.limit}`;
|
|
1038
|
+
}
|
|
1039
|
+
if (inner.skip !== undefined) {
|
|
1040
|
+
groupedDsl += ` skip ${inner.skip}`;
|
|
1041
|
+
}
|
|
1042
|
+
} else if (inner.type === "facet") {
|
|
1043
|
+
groupedDsl += ` ${inner.field}`;
|
|
1044
|
+
if (inner.limit !== undefined) {
|
|
1045
|
+
groupedDsl += ` limit ${inner.limit}`;
|
|
1046
|
+
}
|
|
1047
|
+
} else if (inner.type === "aggregated_facet") {
|
|
1048
|
+
groupedDsl += ` ${inner.field} aggregate ${inner.indicators.join(", ")}`;
|
|
1049
|
+
if (inner.sortBy) {
|
|
1050
|
+
groupedDsl += ` sort by ${inner.sortBy} ${inner.sortOrder ?? "desc"}`;
|
|
1051
|
+
}
|
|
1052
|
+
if (inner.limit !== undefined) {
|
|
1053
|
+
groupedDsl += ` limit ${inner.limit}`;
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
parts.push(groupedDsl);
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
return parts.join(" ");
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
/**
|
|
1064
|
+
* Creates a deep copy of this builder.
|
|
1065
|
+
* Useful when branching queries (e.g. adding different facets from a shared base).
|
|
1066
|
+
* @returns A new QueryBuilder with the same state
|
|
1067
|
+
*/
|
|
1068
|
+
clone(): QueryBuilder {
|
|
1069
|
+
const copy = new QueryBuilder(this.schemaStore);
|
|
1070
|
+
copy.entity = this.entity;
|
|
1071
|
+
copy.searchIndex = this.searchIndex;
|
|
1072
|
+
copy.searchTerms = this.searchTerms;
|
|
1073
|
+
copy.similarText = this.similarText;
|
|
1074
|
+
copy.complexPhrase = this.complexPhrase;
|
|
1075
|
+
copy.complexMaxDist = this.complexMaxDist;
|
|
1076
|
+
copy.minShouldMatchPhrase = this.minShouldMatchPhrase;
|
|
1077
|
+
copy.minShouldMatchMin = this.minShouldMatchMin;
|
|
1078
|
+
copy.expressionNodes = [...this.expressionNodes];
|
|
1079
|
+
copy.groupDepth = this.groupDepth;
|
|
1080
|
+
copy.pendingConnector = this.pendingConnector;
|
|
1081
|
+
copy.returnFields = [...this.returnFields];
|
|
1082
|
+
copy.unnestFields = [...this.unnestFields];
|
|
1083
|
+
copy.sortField = this.sortField;
|
|
1084
|
+
copy.sortOrder = this.sortOrder;
|
|
1085
|
+
copy.skipValue = this.skipValue;
|
|
1086
|
+
copy.limitValue = this.limitValue;
|
|
1087
|
+
copy.facetClauses = [...this.facetClauses];
|
|
1088
|
+
copy.timeSeriesClauses = [...this.timeSeriesClauses];
|
|
1089
|
+
copy.groupedClauses = [...this.groupedClauses];
|
|
1090
|
+
return copy;
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
/**
|
|
1094
|
+
* Resets the builder to its initial state.
|
|
1095
|
+
* @returns This builder for chaining
|
|
1096
|
+
*/
|
|
1097
|
+
reset(): this {
|
|
1098
|
+
this.entity = null;
|
|
1099
|
+
this.searchIndex = null;
|
|
1100
|
+
this.searchTerms = null;
|
|
1101
|
+
this.similarText = null;
|
|
1102
|
+
this.complexPhrase = null;
|
|
1103
|
+
this.complexMaxDist = null;
|
|
1104
|
+
this.minShouldMatchPhrase = null;
|
|
1105
|
+
this.minShouldMatchMin = null;
|
|
1106
|
+
this.expressionNodes = [];
|
|
1107
|
+
this.groupDepth = 0;
|
|
1108
|
+
this.pendingConnector = null;
|
|
1109
|
+
this.returnFields = [];
|
|
1110
|
+
this.unnestFields = [];
|
|
1111
|
+
this.sortField = null;
|
|
1112
|
+
this.sortOrder = "asc";
|
|
1113
|
+
this.skipValue = null;
|
|
1114
|
+
this.limitValue = null;
|
|
1115
|
+
this.facetClauses = [];
|
|
1116
|
+
this.timeSeriesClauses = [];
|
|
1117
|
+
this.groupedClauses = [];
|
|
1118
|
+
return this;
|
|
1119
|
+
}
|
|
1120
|
+
}
|