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