@mistriwork/engine 0.0.0-stage → 1.0.0-rc.10

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 (546) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +17 -2
  3. package/dist/adapters/adapter.d.ts +693 -0
  4. package/dist/adapters/adapter.js +444 -0
  5. package/dist/adapters/cache/cacheStore.d.ts +75 -0
  6. package/dist/adapters/cache/cacheStore.js +160 -0
  7. package/dist/adapters/cache/resp.d.ts +52 -0
  8. package/dist/adapters/cache/resp.js +237 -0
  9. package/dist/adapters/commands/canonicalJson.d.ts +19 -0
  10. package/dist/adapters/commands/canonicalJson.js +154 -0
  11. package/dist/adapters/connect.d.ts +29 -0
  12. package/dist/adapters/connect.js +40 -0
  13. package/dist/adapters/connectionBudget.d.ts +101 -0
  14. package/dist/adapters/connectionBudget.js +128 -0
  15. package/dist/adapters/dbLatency.d.ts +35 -0
  16. package/dist/adapters/dbLatency.js +79 -0
  17. package/dist/adapters/epochCache.d.ts +50 -0
  18. package/dist/adapters/epochCache.js +85 -0
  19. package/dist/adapters/http/egress.d.ts +48 -0
  20. package/dist/adapters/http/egress.js +175 -0
  21. package/dist/adapters/http/httpAdapter.d.ts +71 -0
  22. package/dist/adapters/http/httpAdapter.js +512 -0
  23. package/dist/adapters/http/httpDescription.d.ts +32 -0
  24. package/dist/adapters/http/httpDescription.js +246 -0
  25. package/dist/adapters/http/openapi.d.ts +98 -0
  26. package/dist/adapters/http/openapi.js +487 -0
  27. package/dist/adapters/layoutRefusal.d.ts +24 -0
  28. package/dist/adapters/layoutRefusal.js +35 -0
  29. package/dist/adapters/net/networkPolicy.d.ts +44 -0
  30. package/dist/adapters/net/networkPolicy.js +123 -0
  31. package/dist/adapters/net/untrustedDatabase.d.ts +18 -0
  32. package/dist/adapters/net/untrustedDatabase.js +120 -0
  33. package/dist/adapters/poolAdmission.d.ts +43 -0
  34. package/dist/adapters/poolAdmission.js +184 -0
  35. package/dist/adapters/poolMetrics.d.ts +121 -0
  36. package/dist/adapters/poolMetrics.js +185 -0
  37. package/dist/adapters/postgres.d.ts +436 -0
  38. package/dist/adapters/postgres.js +1890 -0
  39. package/dist/adapters/postgresCatalog.d.ts +96 -0
  40. package/dist/adapters/postgresCatalog.js +387 -0
  41. package/dist/adapters/postgresCatalogDigest.d.ts +30 -0
  42. package/dist/adapters/postgresCatalogDigest.js +87 -0
  43. package/dist/adapters/postgresCatalogRows.d.ts +62 -0
  44. package/dist/adapters/postgresCatalogRows.js +37 -0
  45. package/dist/adapters/postgresDates.d.ts +1 -0
  46. package/dist/adapters/postgresDates.js +39 -0
  47. package/dist/adapters/postgresMaintenance.d.ts +33 -0
  48. package/dist/adapters/postgresMaintenance.js +179 -0
  49. package/dist/adapters/postgresPool.d.ts +255 -0
  50. package/dist/adapters/postgresPool.js +838 -0
  51. package/dist/adapters/postgresPooler.d.ts +28 -0
  52. package/dist/adapters/postgresPooler.js +267 -0
  53. package/dist/adapters/postgresReadCatalog.d.ts +31 -0
  54. package/dist/adapters/postgresReadCatalog.js +226 -0
  55. package/dist/adapters/postgresReadSnapshot.d.ts +46 -0
  56. package/dist/adapters/postgresReadSnapshot.js +133 -0
  57. package/dist/adapters/postgresSchemaEpoch.d.ts +24 -0
  58. package/dist/adapters/postgresSchemaEpoch.js +149 -0
  59. package/dist/adapters/postgresTransactionHandle.d.ts +173 -0
  60. package/dist/adapters/postgresTransactionHandle.js +524 -0
  61. package/dist/adapters/postgresValues.d.ts +30 -0
  62. package/dist/adapters/postgresValues.js +75 -0
  63. package/dist/adapters/replicas.d.ts +70 -0
  64. package/dist/adapters/replicas.js +208 -0
  65. package/dist/adapters/reservedSql.d.ts +38 -0
  66. package/dist/adapters/reservedSql.js +264 -0
  67. package/dist/adapters/rolePrivileges.d.ts +17 -0
  68. package/dist/adapters/rolePrivileges.js +22 -0
  69. package/dist/adapters/scoped/keyRows.d.ts +65 -0
  70. package/dist/adapters/scoped/keyRows.js +173 -0
  71. package/dist/adapters/scoped/postgresScopeCatalog.d.ts +16 -0
  72. package/dist/adapters/scoped/postgresScopeCatalog.js +117 -0
  73. package/dist/adapters/scoped/scopedCommandOperations.d.ts +5 -0
  74. package/dist/adapters/scoped/scopedCommandOperations.js +48 -0
  75. package/dist/adapters/scoped/scopedReads.d.ts +20 -0
  76. package/dist/adapters/scoped/scopedReads.js +174 -0
  77. package/dist/adapters/scoped/scopedTransaction.d.ts +89 -0
  78. package/dist/adapters/scoped/scopedTransaction.js +303 -0
  79. package/dist/adapters/scoped/sqliteScopeCatalog.d.ts +16 -0
  80. package/dist/adapters/scoped/sqliteScopeCatalog.js +241 -0
  81. package/dist/adapters/scoped/updateGuard.d.ts +3 -0
  82. package/dist/adapters/scoped/updateGuard.js +40 -0
  83. package/dist/adapters/serverSettings.d.ts +45 -0
  84. package/dist/adapters/serverSettings.js +46 -0
  85. package/dist/adapters/sqlite.d.ts +262 -0
  86. package/dist/adapters/sqlite.js +1434 -0
  87. package/dist/adapters/sqliteCostlyReads.d.ts +33 -0
  88. package/dist/adapters/sqliteCostlyReads.js +49 -0
  89. package/dist/adapters/sqliteDecimals.d.ts +22 -0
  90. package/dist/adapters/sqliteDecimals.js +57 -0
  91. package/dist/adapters/sqliteHandles.d.ts +43 -0
  92. package/dist/adapters/sqliteHandles.js +143 -0
  93. package/dist/adapters/sqliteStatementProcess.d.ts +29 -0
  94. package/dist/adapters/sqliteStatementProcess.js +131 -0
  95. package/dist/adapters/statementControl.d.ts +34 -0
  96. package/dist/adapters/statementControl.js +90 -0
  97. package/dist/adapters/storeHost.d.ts +130 -0
  98. package/dist/adapters/storeHost.js +13 -0
  99. package/dist/adapters/telemetry/drivers.d.ts +21 -0
  100. package/dist/adapters/telemetry/drivers.js +321 -0
  101. package/dist/adapters/telemetry/metrics.d.ts +63 -0
  102. package/dist/adapters/telemetry/metrics.js +122 -0
  103. package/dist/adapters/telemetry/otlp.d.ts +12 -0
  104. package/dist/adapters/telemetry/otlp.js +320 -0
  105. package/dist/adapters/telemetry/otlpEncode.d.ts +48 -0
  106. package/dist/adapters/telemetry/otlpEncode.js +366 -0
  107. package/dist/adapters/telemetry/otlpEnv.d.ts +1 -0
  108. package/dist/adapters/telemetry/otlpEnv.js +12 -0
  109. package/dist/adapters/telemetry/serverTiming.d.ts +83 -0
  110. package/dist/adapters/telemetry/serverTiming.js +503 -0
  111. package/dist/adapters/telemetry/start.d.ts +10 -0
  112. package/dist/adapters/telemetry/start.js +25 -0
  113. package/dist/adapters/telemetry/statement.d.ts +16 -0
  114. package/dist/adapters/telemetry/statement.js +134 -0
  115. package/dist/adapters/telemetry/trace.d.ts +127 -0
  116. package/dist/adapters/telemetry/trace.js +295 -0
  117. package/dist/adapters/writeAhead.d.ts +27 -0
  118. package/dist/adapters/writeAhead.js +46 -0
  119. package/dist/adapters/writeAttribution.d.ts +18 -0
  120. package/dist/adapters/writeAttribution.js +23 -0
  121. package/dist/adapters/writeCapture.d.ts +73 -0
  122. package/dist/adapters/writeCapture.js +20 -0
  123. package/dist/adapters/writeLanes.d.ts +94 -0
  124. package/dist/adapters/writeLanes.js +232 -0
  125. package/dist/engine.d.ts +15 -0
  126. package/dist/engine.js +13 -0
  127. package/dist/server/auth/credentials.d.ts +61 -0
  128. package/dist/server/auth/credentials.js +260 -0
  129. package/dist/server/cacheService.d.ts +50 -0
  130. package/dist/server/cacheService.js +110 -0
  131. package/dist/server/cli/args.d.ts +176 -0
  132. package/dist/server/cli/args.js +342 -0
  133. package/dist/server/cli/bin.d.ts +5 -0
  134. package/dist/server/cli/bin.js +66 -0
  135. package/dist/server/cli/browser.d.ts +15 -0
  136. package/dist/server/cli/browser.js +37 -0
  137. package/dist/server/cli/config.d.ts +50 -0
  138. package/dist/server/cli/config.js +206 -0
  139. package/dist/server/cli/startup.d.ts +36 -0
  140. package/dist/server/cli/startup.js +128 -0
  141. package/dist/server/cli/startupOptions.d.ts +63 -0
  142. package/dist/server/cli/startupOptions.js +143 -0
  143. package/dist/server/cli/subcommand.d.ts +28 -0
  144. package/dist/server/cli/subcommand.js +32 -0
  145. package/dist/server/cli/usage.d.ts +13 -0
  146. package/dist/server/cli/usage.js +31 -0
  147. package/dist/server/clientHttp.d.ts +184 -0
  148. package/dist/server/clientHttp.js +700 -0
  149. package/dist/server/clientSurface.d.ts +128 -0
  150. package/dist/server/clientSurface.js +182 -0
  151. package/dist/server/columnGrants.d.ts +103 -0
  152. package/dist/server/columnGrants.js +730 -0
  153. package/dist/server/compileCache.d.ts +1 -0
  154. package/dist/server/compileCache.js +30 -0
  155. package/dist/server/config/locations.d.ts +1 -0
  156. package/dist/server/config/locations.js +15 -0
  157. package/dist/server/configPaths.d.ts +7 -0
  158. package/dist/server/configPaths.js +34 -0
  159. package/dist/server/configSections.d.ts +64 -0
  160. package/dist/server/configSections.js +72 -0
  161. package/dist/server/connectionRedaction.d.ts +30 -0
  162. package/dist/server/connectionRedaction.js +77 -0
  163. package/dist/server/connections.d.ts +353 -0
  164. package/dist/server/connections.js +978 -0
  165. package/dist/server/constraints.d.ts +82 -0
  166. package/dist/server/constraints.js +169 -0
  167. package/dist/server/demo.d.ts +9 -0
  168. package/dist/server/demo.js +554 -0
  169. package/dist/server/devclient.d.ts +108 -0
  170. package/dist/server/devclient.js +361 -0
  171. package/dist/server/evidence.d.ts +55 -0
  172. package/dist/server/evidence.js +323 -0
  173. package/dist/server/hiddenColumns.d.ts +32 -0
  174. package/dist/server/hiddenColumns.js +238 -0
  175. package/dist/server/http/baselineHeaders.d.ts +24 -0
  176. package/dist/server/http/baselineHeaders.js +12 -0
  177. package/dist/server/http/captured.d.ts +35 -0
  178. package/dist/server/http/captured.js +73 -0
  179. package/dist/server/http/clock.d.ts +1 -0
  180. package/dist/server/http/clock.js +14 -0
  181. package/dist/server/http/connectionSource.d.ts +4 -0
  182. package/dist/server/http/connectionSource.js +48 -0
  183. package/dist/server/http/context.d.ts +189 -0
  184. package/dist/server/http/context.js +11 -0
  185. package/dist/server/http/crawlerText.d.ts +15 -0
  186. package/dist/server/http/crawlerText.js +32 -0
  187. package/dist/server/http/dataRoutes.d.ts +88 -0
  188. package/dist/server/http/dataRoutes.js +137 -0
  189. package/dist/server/http/door.d.ts +57 -0
  190. package/dist/server/http/door.js +39 -0
  191. package/dist/server/http/exportRoute.d.ts +15 -0
  192. package/dist/server/http/exportRoute.js +320 -0
  193. package/dist/server/http/firstPaint.d.ts +108 -0
  194. package/dist/server/http/firstPaint.js +262 -0
  195. package/dist/server/http/httpOperationRoutes.d.ts +11 -0
  196. package/dist/server/http/httpOperationRoutes.js +50 -0
  197. package/dist/server/http/pageReads.d.ts +20 -0
  198. package/dist/server/http/pageReads.js +205 -0
  199. package/dist/server/http/pageRoutes.d.ts +39 -0
  200. package/dist/server/http/pageRoutes.js +291 -0
  201. package/dist/server/http/probes.d.ts +22 -0
  202. package/dist/server/http/probes.js +27 -0
  203. package/dist/server/http/rateLimit.d.ts +131 -0
  204. package/dist/server/http/rateLimit.js +351 -0
  205. package/dist/server/http/readRoutes.d.ts +9 -0
  206. package/dist/server/http/readRoutes.js +131 -0
  207. package/dist/server/http/readRouting.d.ts +20 -0
  208. package/dist/server/http/readRouting.js +80 -0
  209. package/dist/server/http/recordCompose.d.ts +67 -0
  210. package/dist/server/http/recordCompose.js +167 -0
  211. package/dist/server/http/recordWrites.d.ts +89 -0
  212. package/dist/server/http/recordWrites.js +298 -0
  213. package/dist/server/http/refusalReport.d.ts +38 -0
  214. package/dist/server/http/refusalReport.js +63 -0
  215. package/dist/server/http/reply.d.ts +130 -0
  216. package/dist/server/http/reply.js +394 -0
  217. package/dist/server/http/requestOrigin.d.ts +11 -0
  218. package/dist/server/http/requestOrigin.js +8 -0
  219. package/dist/server/http/router.d.ts +45 -0
  220. package/dist/server/http/router.js +22 -0
  221. package/dist/server/http/serverCore.d.ts +68 -0
  222. package/dist/server/http/serverCore.js +177 -0
  223. package/dist/server/http/traceRequest.d.ts +30 -0
  224. package/dist/server/http/traceRequest.js +224 -0
  225. package/dist/server/http/trust.d.ts +261 -0
  226. package/dist/server/http/trust.js +472 -0
  227. package/dist/server/http/writeRefusal.d.ts +33 -0
  228. package/dist/server/http/writeRefusal.js +24 -0
  229. package/dist/server/httpConnection.d.ts +49 -0
  230. package/dist/server/httpConnection.js +170 -0
  231. package/dist/server/impact.d.ts +55 -0
  232. package/dist/server/impact.js +47 -0
  233. package/dist/server/journal.d.ts +134 -0
  234. package/dist/server/journal.js +398 -0
  235. package/dist/server/keysetReadHttp.d.ts +52 -0
  236. package/dist/server/keysetReadHttp.js +85 -0
  237. package/dist/server/layouts.d.ts +49 -0
  238. package/dist/server/layouts.js +192 -0
  239. package/dist/server/migrate/cli.d.ts +55 -0
  240. package/dist/server/migrate/cli.js +517 -0
  241. package/dist/server/migrate/database.d.ts +37 -0
  242. package/dist/server/migrate/database.js +247 -0
  243. package/dist/server/migrate/desired.d.ts +76 -0
  244. package/dist/server/migrate/desired.js +292 -0
  245. package/dist/server/migrate/files.d.ts +34 -0
  246. package/dist/server/migrate/files.js +141 -0
  247. package/dist/server/migrate/flyway.d.ts +7 -0
  248. package/dist/server/migrate/flyway.js +69 -0
  249. package/dist/server/migrate/history.d.ts +70 -0
  250. package/dist/server/migrate/history.js +211 -0
  251. package/dist/server/migrate/runner.d.ts +100 -0
  252. package/dist/server/migrate/runner.js +409 -0
  253. package/dist/server/migrate/snapshot.d.ts +30 -0
  254. package/dist/server/migrate/snapshot.js +239 -0
  255. package/dist/server/migrate/target.d.ts +33 -0
  256. package/dist/server/migrate/target.js +82 -0
  257. package/dist/server/openapiDraft.d.ts +25 -0
  258. package/dist/server/openapiDraft.js +171 -0
  259. package/dist/server/operations/diagnostics.d.ts +101 -0
  260. package/dist/server/operations/diagnostics.js +284 -0
  261. package/dist/server/operations/requestMetrics.d.ts +33 -0
  262. package/dist/server/operations/requestMetrics.js +94 -0
  263. package/dist/server/packageVersion.d.ts +1 -0
  264. package/dist/server/packageVersion.js +11 -0
  265. package/dist/server/poolConfig.d.ts +34 -0
  266. package/dist/server/poolConfig.js +114 -0
  267. package/dist/server/product.d.ts +20 -0
  268. package/dist/server/product.js +12 -0
  269. package/dist/server/recordHistoryOperations.d.ts +39 -0
  270. package/dist/server/recordHistoryOperations.js +43 -0
  271. package/dist/server/recordWriteOperations.d.ts +111 -0
  272. package/dist/server/recordWriteOperations.js +329 -0
  273. package/dist/server/resourceReadHttp.d.ts +81 -0
  274. package/dist/server/resourceReadHttp.js +606 -0
  275. package/dist/server/resourceReadOperations.d.ts +147 -0
  276. package/dist/server/resourceReadOperations.js +452 -0
  277. package/dist/server/scaffoldMachine.d.ts +54 -0
  278. package/dist/server/scaffoldMachine.js +184 -0
  279. package/dist/server/seed/cli.d.ts +20 -0
  280. package/dist/server/seed/cli.js +164 -0
  281. package/dist/server/seed/lexicon.d.ts +26 -0
  282. package/dist/server/seed/lexicon.js +585 -0
  283. package/dist/server/seed/seed.d.ts +70 -0
  284. package/dist/server/seed/seed.js +779 -0
  285. package/dist/server/seed/words.d.ts +21 -0
  286. package/dist/server/seed/words.js +164 -0
  287. package/dist/server/serverRequests.d.ts +6 -0
  288. package/dist/server/serverRequests.js +33 -0
  289. package/dist/server/serverTimeouts.d.ts +33 -0
  290. package/dist/server/serverTimeouts.js +32 -0
  291. package/dist/server/shapeonly.d.ts +32 -0
  292. package/dist/server/shapeonly.js +110 -0
  293. package/dist/server/startupWarnings.d.ts +32 -0
  294. package/dist/server/startupWarnings.js +92 -0
  295. package/dist/shared/addressParams.d.ts +28 -0
  296. package/dist/shared/addressParams.js +47 -0
  297. package/dist/shared/appCards.d.ts +123 -0
  298. package/dist/shared/appCards.js +385 -0
  299. package/dist/shared/appComponents.d.ts +177 -0
  300. package/dist/shared/appComponents.js +422 -0
  301. package/dist/shared/appDocuments.d.ts +43 -0
  302. package/dist/shared/appDocuments.js +131 -0
  303. package/dist/shared/appEmbeds.d.ts +21 -0
  304. package/dist/shared/appEmbeds.js +24 -0
  305. package/dist/shared/appIcons.d.ts +28 -0
  306. package/dist/shared/appIcons.js +223 -0
  307. package/dist/shared/appLinks.d.ts +17 -0
  308. package/dist/shared/appLinks.js +124 -0
  309. package/dist/shared/appListColumns.d.ts +3 -0
  310. package/dist/shared/appListColumns.js +66 -0
  311. package/dist/shared/appLocale.d.ts +36 -0
  312. package/dist/shared/appLocale.js +86 -0
  313. package/dist/shared/appMessages.d.ts +44 -0
  314. package/dist/shared/appMessages.js +78 -0
  315. package/dist/shared/appNoun.d.ts +21 -0
  316. package/dist/shared/appNoun.js +32 -0
  317. package/dist/shared/autoBucket.d.ts +98 -0
  318. package/dist/shared/autoBucket.js +305 -0
  319. package/dist/shared/autoValues.d.ts +25 -0
  320. package/dist/shared/autoValues.js +25 -0
  321. package/dist/shared/breakdown.d.ts +228 -0
  322. package/dist/shared/breakdown.js +557 -0
  323. package/dist/shared/breakdowntext.d.ts +41 -0
  324. package/dist/shared/breakdowntext.js +400 -0
  325. package/dist/shared/builtInThemes.d.ts +2 -0
  326. package/dist/shared/builtInThemes.js +771 -0
  327. package/dist/shared/chartSeparation.d.ts +11 -0
  328. package/dist/shared/chartSeparation.js +58 -0
  329. package/dist/shared/clauses.d.ts +22 -0
  330. package/dist/shared/clauses.js +97 -0
  331. package/dist/shared/columnCaption.d.ts +16 -0
  332. package/dist/shared/columnCaption.js +90 -0
  333. package/dist/shared/commandFieldPath.d.ts +2 -0
  334. package/dist/shared/commandFieldPath.js +7 -0
  335. package/dist/shared/commandWire.d.ts +26 -0
  336. package/dist/shared/commandWire.js +41 -0
  337. package/dist/shared/computed.d.ts +161 -0
  338. package/dist/shared/computed.js +378 -0
  339. package/dist/shared/computedParse.d.ts +13 -0
  340. package/dist/shared/computedParse.js +278 -0
  341. package/dist/shared/computedValue.d.ts +47 -0
  342. package/dist/shared/computedValue.js +191 -0
  343. package/dist/shared/connection.d.ts +30 -0
  344. package/dist/shared/connection.js +1 -0
  345. package/dist/shared/csv.d.ts +20 -0
  346. package/dist/shared/csv.js +63 -0
  347. package/dist/shared/dashLayout.d.ts +30 -0
  348. package/dist/shared/dashLayout.js +132 -0
  349. package/dist/shared/dashboardAsks.d.ts +93 -0
  350. package/dist/shared/dashboardAsks.js +129 -0
  351. package/dist/shared/dashboardTrend.d.ts +20 -0
  352. package/dist/shared/dashboardTrend.js +50 -0
  353. package/dist/shared/declaredReferences.d.ts +50 -0
  354. package/dist/shared/declaredReferences.js +202 -0
  355. package/dist/shared/definedFields.d.ts +63 -0
  356. package/dist/shared/definedFields.js +103 -0
  357. package/dist/shared/definedValues.d.ts +63 -0
  358. package/dist/shared/definedValues.js +184 -0
  359. package/dist/shared/displayDefaults.d.ts +135 -0
  360. package/dist/shared/displayDefaults.js +529 -0
  361. package/dist/shared/dueDate.d.ts +6 -0
  362. package/dist/shared/dueDate.js +6 -0
  363. package/dist/shared/duration.d.ts +4 -0
  364. package/dist/shared/duration.js +23 -0
  365. package/dist/shared/fileBounds.d.ts +9 -0
  366. package/dist/shared/fileBounds.js +9 -0
  367. package/dist/shared/filter.d.ts +217 -0
  368. package/dist/shared/filter.js +305 -0
  369. package/dist/shared/firstPaint.d.ts +24 -0
  370. package/dist/shared/firstPaint.js +33 -0
  371. package/dist/shared/form.d.ts +21 -0
  372. package/dist/shared/form.js +25 -0
  373. package/dist/shared/formValues.d.ts +104 -0
  374. package/dist/shared/formValues.js +352 -0
  375. package/dist/shared/funnel.d.ts +45 -0
  376. package/dist/shared/funnel.js +108 -0
  377. package/dist/shared/httpOperations.d.ts +48 -0
  378. package/dist/shared/httpOperations.js +9 -0
  379. package/dist/shared/iconGlyphs.d.ts +4 -0
  380. package/dist/shared/iconGlyphs.js +151 -0
  381. package/dist/shared/iconWeights.d.ts +3 -0
  382. package/dist/shared/iconWeights.js +162 -0
  383. package/dist/shared/imageWidths.d.ts +32 -0
  384. package/dist/shared/imageWidths.js +38 -0
  385. package/dist/shared/keysetPage.d.ts +64 -0
  386. package/dist/shared/keysetPage.js +161 -0
  387. package/dist/shared/like.d.ts +20 -0
  388. package/dist/shared/like.js +29 -0
  389. package/dist/shared/listEmpty.d.ts +12 -0
  390. package/dist/shared/listEmpty.js +36 -0
  391. package/dist/shared/listFilters.d.ts +28 -0
  392. package/dist/shared/listFilters.js +84 -0
  393. package/dist/shared/listPresentations.d.ts +199 -0
  394. package/dist/shared/listPresentations.js +7 -0
  395. package/dist/shared/listQuestion.d.ts +52 -0
  396. package/dist/shared/listQuestion.js +137 -0
  397. package/dist/shared/lookPalettes.d.ts +62 -0
  398. package/dist/shared/lookPalettes.js +306 -0
  399. package/dist/shared/maskQuoted.d.ts +24 -0
  400. package/dist/shared/maskQuoted.js +48 -0
  401. package/dist/shared/mentionLabel.d.ts +19 -0
  402. package/dist/shared/mentionLabel.js +38 -0
  403. package/dist/shared/mentionLookup.d.ts +17 -0
  404. package/dist/shared/mentionLookup.js +64 -0
  405. package/dist/shared/menuCounts.d.ts +16 -0
  406. package/dist/shared/menuCounts.js +74 -0
  407. package/dist/shared/model.d.ts +79 -0
  408. package/dist/shared/model.js +153 -0
  409. package/dist/shared/money.d.ts +44 -0
  410. package/dist/shared/money.js +81 -0
  411. package/dist/shared/moneyEntry.d.ts +7 -0
  412. package/dist/shared/moneyEntry.js +27 -0
  413. package/dist/shared/mount.d.ts +118 -0
  414. package/dist/shared/mount.js +248 -0
  415. package/dist/shared/niceTicks.d.ts +26 -0
  416. package/dist/shared/niceTicks.js +50 -0
  417. package/dist/shared/order.d.ts +59 -0
  418. package/dist/shared/order.js +133 -0
  419. package/dist/shared/page.d.ts +135 -0
  420. package/dist/shared/page.js +1187 -0
  421. package/dist/shared/pageAnatomy.d.ts +99 -0
  422. package/dist/shared/pageAnatomy.js +370 -0
  423. package/dist/shared/pageConfig.d.ts +25 -0
  424. package/dist/shared/pageConfig.js +1308 -0
  425. package/dist/shared/pageEmptyActions.d.ts +12 -0
  426. package/dist/shared/pageEmptyActions.js +20 -0
  427. package/dist/shared/pageLayouts.d.ts +72 -0
  428. package/dist/shared/pageLayouts.js +205 -0
  429. package/dist/shared/pageModel.d.ts +785 -0
  430. package/dist/shared/pageModel.js +121 -0
  431. package/dist/shared/pagePaths.d.ts +180 -0
  432. package/dist/shared/pagePaths.js +869 -0
  433. package/dist/shared/pagePlans.d.ts +52 -0
  434. package/dist/shared/pagePlans.js +108 -0
  435. package/dist/shared/pageRoutes.d.ts +9 -0
  436. package/dist/shared/pageRoutes.js +9 -0
  437. package/dist/shared/query.d.ts +166 -0
  438. package/dist/shared/query.js +1302 -0
  439. package/dist/shared/queryDates.d.ts +12 -0
  440. package/dist/shared/queryDates.js +101 -0
  441. package/dist/shared/queryOperands.d.ts +99 -0
  442. package/dist/shared/queryOperands.js +131 -0
  443. package/dist/shared/reads.d.ts +103 -0
  444. package/dist/shared/reads.js +154 -0
  445. package/dist/shared/recordLabel.d.ts +51 -0
  446. package/dist/shared/recordLabel.js +123 -0
  447. package/dist/shared/recordReadKeys.d.ts +30 -0
  448. package/dist/shared/recordReadKeys.js +51 -0
  449. package/dist/shared/recordReads.d.ts +268 -0
  450. package/dist/shared/recordReads.js +368 -0
  451. package/dist/shared/recordview.d.ts +198 -0
  452. package/dist/shared/recordview.js +356 -0
  453. package/dist/shared/referenceModel.d.ts +58 -0
  454. package/dist/shared/referenceModel.js +194 -0
  455. package/dist/shared/refusal.d.ts +64 -0
  456. package/dist/shared/refusal.js +144 -0
  457. package/dist/shared/relatedCreate.d.ts +30 -0
  458. package/dist/shared/relatedCreate.js +162 -0
  459. package/dist/shared/resourceHttp.d.ts +464 -0
  460. package/dist/shared/resourceHttp.js +1 -0
  461. package/dist/shared/richText.d.ts +85 -0
  462. package/dist/shared/richText.js +305 -0
  463. package/dist/shared/rollups.d.ts +143 -0
  464. package/dist/shared/rollups.js +64 -0
  465. package/dist/shared/rowScope.d.ts +72 -0
  466. package/dist/shared/rowScope.js +376 -0
  467. package/dist/shared/runtimeTables.d.ts +44 -0
  468. package/dist/shared/runtimeTables.js +79 -0
  469. package/dist/shared/schema.d.ts +523 -0
  470. package/dist/shared/schema.js +627 -0
  471. package/dist/shared/schematext.d.ts +38 -0
  472. package/dist/shared/schematext.js +101 -0
  473. package/dist/shared/scopeCatalog.d.ts +29 -0
  474. package/dist/shared/scopeCatalog.js +468 -0
  475. package/dist/shared/servedApp.d.ts +681 -0
  476. package/dist/shared/servedApp.js +45 -0
  477. package/dist/shared/sessionLease.d.ts +34 -0
  478. package/dist/shared/sessionLease.js +3 -0
  479. package/dist/shared/shape.d.ts +55 -0
  480. package/dist/shared/shape.js +168 -0
  481. package/dist/shared/slug.d.ts +1 -0
  482. package/dist/shared/slug.js +12 -0
  483. package/dist/shared/sortText.d.ts +14 -0
  484. package/dist/shared/sortText.js +26 -0
  485. package/dist/shared/sqlRelation.d.ts +4 -0
  486. package/dist/shared/sqlRelation.js +8 -0
  487. package/dist/shared/sqlsaved.d.ts +44 -0
  488. package/dist/shared/sqlsaved.js +63 -0
  489. package/dist/shared/stitchedPaths.d.ts +27 -0
  490. package/dist/shared/stitchedPaths.js +38 -0
  491. package/dist/shared/structuredFilter.d.ts +22 -0
  492. package/dist/shared/structuredFilter.js +1 -0
  493. package/dist/shared/subtitlePath.d.ts +20 -0
  494. package/dist/shared/subtitlePath.js +24 -0
  495. package/dist/shared/suggest.d.ts +18 -0
  496. package/dist/shared/suggest.js +59 -0
  497. package/dist/shared/tableSizing.d.ts +4 -0
  498. package/dist/shared/tableSizing.js +9 -0
  499. package/dist/shared/tagLists.d.ts +57 -0
  500. package/dist/shared/tagLists.js +34 -0
  501. package/dist/shared/textRules.d.ts +54 -0
  502. package/dist/shared/textRules.js +133 -0
  503. package/dist/shared/theme.d.ts +94 -0
  504. package/dist/shared/theme.js +800 -0
  505. package/dist/shared/themeColor.d.ts +34 -0
  506. package/dist/shared/themeColor.js +109 -0
  507. package/dist/shared/themeFaces.d.ts +30 -0
  508. package/dist/shared/themeFaces.js +42 -0
  509. package/dist/shared/themeInk.d.ts +20 -0
  510. package/dist/shared/themeInk.js +52 -0
  511. package/dist/shared/themeLooks.d.ts +9 -0
  512. package/dist/shared/themeLooks.js +572 -0
  513. package/dist/shared/themeParts.d.ts +26 -0
  514. package/dist/shared/themeParts.js +71 -0
  515. package/dist/shared/themePartsCheck.d.ts +21 -0
  516. package/dist/shared/themePartsCheck.js +91 -0
  517. package/dist/shared/themePresets.d.ts +85 -0
  518. package/dist/shared/themePresets.js +139 -0
  519. package/dist/shared/themeRecipeWords.d.ts +156 -0
  520. package/dist/shared/themeRecipeWords.js +156 -0
  521. package/dist/shared/themeRecipes.d.ts +213 -0
  522. package/dist/shared/themeRecipes.js +234 -0
  523. package/dist/shared/themeResolve.d.ts +55 -0
  524. package/dist/shared/themeResolve.js +52 -0
  525. package/dist/shared/themeTokens.d.ts +107 -0
  526. package/dist/shared/themeTokens.js +116 -0
  527. package/dist/shared/themeType.d.ts +38 -0
  528. package/dist/shared/themeType.js +205 -0
  529. package/dist/shared/unitWord.d.ts +4 -0
  530. package/dist/shared/unitWord.js +37 -0
  531. package/dist/shared/view.d.ts +195 -0
  532. package/dist/shared/view.js +987 -0
  533. package/dist/shared/viewLabels.d.ts +47 -0
  534. package/dist/shared/viewLabels.js +459 -0
  535. package/dist/shared/viewPaths.d.ts +248 -0
  536. package/dist/shared/viewPaths.js +294 -0
  537. package/dist/shared/viewtext.d.ts +57 -0
  538. package/dist/shared/viewtext.js +282 -0
  539. package/dist/shared/vocabulary.d.ts +71 -0
  540. package/dist/shared/vocabulary.js +249 -0
  541. package/dist/shared/weekStart.d.ts +7 -0
  542. package/dist/shared/weekStart.js +36 -0
  543. package/mark.svg +1 -0
  544. package/package.json +261 -4
  545. package/schema/model.d.ts +298 -0
  546. package/schema/theme.d.ts +587 -0
@@ -0,0 +1,557 @@
1
+ /**
2
+ * Counting things by something: GROUP BY, as a shape rather than as text.
3
+ *
4
+ * This was the last real hole in the query language. "How many invoices per
5
+ * month", "which countries have the most customers", "what does each status
6
+ * add up to" are the questions anybody asks of a database in the first ten
7
+ * minutes, and until now the only way to ask them here was to drop into `sql`
8
+ * — which means an agent leaves the checked path exactly where the question
9
+ * gets interesting, and a person leaves the tool.
10
+ *
11
+ * A breakdown is deliberately *not* a view with a `groupBy` bolted on. A view
12
+ * promises one row per base record, and every part of it — the correlated
13
+ * aggregates, the LEFT JOIN rule, the row-click that opens a record — leans on
14
+ * that promise. Grouping breaks it: the rows that come back are not records
15
+ * and cannot be opened, and a column that is neither a key nor an aggregate is
16
+ * a bug on two engines and a silent wrong answer on the third. So it is a
17
+ * sibling type with its own compiler, sharing the parts that are genuinely the
18
+ * same: path resolution, the join planner, and `buildWhere`.
19
+ *
20
+ * invoice count by status
21
+ * invoice sum total by month invoice_date
22
+ * invoice count, avg total by customer_id.country_code.name sort count desc
23
+ *
24
+ * Two rules the shape enforces, both of which SQL leaves to the author:
25
+ *
26
+ * - **Every selected expression is a key or a measure.** There is nowhere to
27
+ * put a third thing, so `SELECT status, name, COUNT(*) … GROUP BY status`
28
+ * — which a lenient engine would answer with an arbitrary `name` — cannot be
29
+ * written.
30
+ * - **The result is bounded like every other read.** A breakdown over a
31
+ * high-cardinality column is a million-row answer, and `sort count desc
32
+ * limit 20` is what somebody meant anyway.
33
+ */
34
+ import { buildWhere } from './filter.js';
35
+ import { clampLimit, clampOffset, countStatement } from './reads.js';
36
+ import { aggregateInput, columnKind, findTable, labelPath } from './schema.js';
37
+ import { JoinPlan, PathError, sqlLiteral } from './view.js';
38
+ import { ScopedRelations } from './rowScope.js';
39
+ import { readsOf } from './query.js';
40
+ import { isFixedScopeCatalog } from './scopeCatalog.js';
41
+ import { viewPaths, withViewComputed } from './viewLabels.js';
42
+ import { tableAtPrefix, tryResolvePath } from './viewPaths.js';
43
+ import { withViewReferences } from './declaredReferences.js';
44
+ import { LABEL_SEGMENT, labelPrefix } from './recordLabel.js';
45
+ export const MEASURE_FUNCTIONS = ['count', 'sum', 'avg', 'min', 'max', 'median'];
46
+ export const MEASURE_OPS = ['+', '-', '*', '/'];
47
+ /** Why a dialect cannot answer a measure function, or undefined when it can. */
48
+ export function measureRefusal(fn, dialect) {
49
+ if (fn !== 'median')
50
+ return undefined;
51
+ if (dialect === 'sqlite')
52
+ return '`median` is not available on SQLite: it has no median aggregate (no percentile_cont). Use `avg`, or a PostgreSQL source.';
53
+ return undefined;
54
+ }
55
+ /** The periods a date key can be cut into. */
56
+ export const DATE_UNITS = ['day', 'week', 'month', 'quarter', 'year', 'weekday', 'hour'];
57
+ const termText = (t) => typeof t === 'number'
58
+ ? String(t)
59
+ : [t.fn, ...(t.distinct ? ['distinct'] : []), ...(t.path ? [t.path] : []), ...(t.when ? ['when', `[${t.when}]`] : [])].join(' ');
60
+ /** A measure as it is written: `sum paid / sum total as rate`. */
61
+ export function measureToText(m) {
62
+ return [termText(m), ...(m.steps ?? []).flatMap(({ op, term }) => [op, termText(term)]), ...(m.alias ? ['as', m.alias] : [])].join(' ');
63
+ }
64
+ const termName = (t, path = typeof t === 'number' ? undefined : t.path) => typeof t === 'number' ? String(t) : t.fn === 'count' ? (path ? `count(${path})` : 'count') : `${t.fn}(${path ?? ''})`;
65
+ /** The name a measure answers under when it has no alias: `sum(total)`, `sum(paid) / sum(total)`. */
66
+ export function measureName(m, path = m.path) {
67
+ return m.alias?.trim() || [termName(m, path), ...(m.steps ?? []).flatMap(({ op, term }) => [op, termName(term)])].join(' ');
68
+ }
69
+ /** Every column a measure reads. */
70
+ export function measurePaths(m) {
71
+ return [m, ...(m.steps ?? []).map(({ term }) => term)].flatMap((t) => (typeof t !== 'number' && t.path ? [t.path] : []));
72
+ }
73
+ /** Every `when` among a breakdown's measures, in order: what a reader's grants and the stitched-read check must also hold. */
74
+ export const measureConditions = (measures) => (measures ?? []).flatMap((m) => (m.where?.groups.length ? [m.where] : []));
75
+ /** The paths a filter's conditions walk, and the paths they compare against. */
76
+ export const filterPaths = (filter) => (filter?.groups ?? []).flatMap((group) => group.flatMap((c) => [c.path, ...(c.other === undefined ? [] : [c.other])]));
77
+ /** How many group keys are worth having. */
78
+ const MAX_KEYS = 3;
79
+ /**
80
+ * Is this column something a date bucket can be taken of?
81
+ *
82
+ * Read off the declared type rather than the values, because the answer has
83
+ * to be the same before and after the table has any rows in it. SQLite's
84
+ * `DATE` is a convention rather than a type, which is exactly why the check is
85
+ * on the declaration: a column somebody called `DATE` is one they intend to
86
+ * hold dates, and `strftime` over text that is not one returns null — a group
87
+ * of its own rather than an error, which is the honest outcome.
88
+ */
89
+ const isDateish = (type) => /date|time/i.test(type ?? '');
90
+ /**
91
+ * Compile a breakdown to one parameterised SELECT.
92
+ *
93
+ * The order of work matches `compileView`'s and for the same reason: keys,
94
+ * then measures, then the filter, then the sort — so aliases are handed out in
95
+ * first-use order and the same breakdown always compiles to the same text.
96
+ */
97
+ export function compileBreakdown(schema, def, style, offset = 0, scope) {
98
+ /* A breakdown compiles to the same statement against the same catalog, and an App's enter asks for each of its
99
+ rail's and dashboard's breakdowns several times — against the reader's pruned catalog and the full one for
100
+ the access check (columnGrants.ts), under the reader's scope to run it, and again for the SQL pane — each a
101
+ full compile (a field report: a large tenant App spent a twelfth of an enter's CPU here). Kept only against a catalog nothing can change (fixedCatalog, below), for a definition
102
+ whose text says all of it (breakdownText), and only where compiling read neither the clock nor the reader
103
+ (query.ts readsOf): a statement that wrote a request's instant, day or email is that request's, and is never
104
+ handed to another. */
105
+ const text = typeof offset === 'number' && fixedCatalog(schema) ? breakdownText(def) : undefined;
106
+ if (text === undefined) {
107
+ breakdownsCompiled++;
108
+ return compileBreakdownFresh(schema, def, style, offset, scope);
109
+ }
110
+ let byStyle = breakdownsKept.get(schema);
111
+ if (!byStyle)
112
+ breakdownsKept.set(schema, (byStyle = new WeakMap()));
113
+ let kept = byStyle.get(style);
114
+ if (!kept)
115
+ byStyle.set(style, (kept = new Map()));
116
+ const key = `${scope ? scopeOrdinal(scope) : 0}\0${offset}\0${text}`;
117
+ let found = kept.get(key);
118
+ if (found) {
119
+ kept.delete(key);
120
+ kept.set(key, found);
121
+ }
122
+ else {
123
+ breakdownsCompiled++;
124
+ const read = readsOf(() => compileBreakdownFresh(schema, def, style, offset, scope));
125
+ if (read.clock !== 0 || read.reader)
126
+ return read.value;
127
+ found = read.value;
128
+ kept.set(key, found);
129
+ if (kept.size > BREAKDOWNS_KEPT)
130
+ kept.delete(kept.keys().next().value);
131
+ }
132
+ // Each caller's own arrays: a driver or a caller may add to what it is handed.
133
+ return { ...found, params: [...found.params], columns: found.columns.map((column) => ({ ...column })) };
134
+ }
135
+ /* A catalog nothing can change: a captured scope catalog (scopeCatalog.ts), or whatever the server says it froze
136
+ all the way down (evidence.ts captureTenantData, which registers itself here: a shared module cannot import it). */
137
+ let alsoFixed = () => false;
138
+ /** Who says a catalog cannot change, beside the scope catalog's own captures. */
139
+ export function keepBreakdownsAgainst(fixed) {
140
+ alsoFixed = fixed;
141
+ }
142
+ const fixedCatalog = (schema) => isFixedScopeCatalog(schema) || alsoFixed(schema);
143
+ /* A definition's text, where the text says all of it: plain records, arrays, strings, booleans and finite numbers.
144
+ A property left undefined (a key with no `bucket`, a list with no `orderBy` — most of them, as a reader's snapshot
145
+ carries them) is said as one, never dropped, so the text of a definition that has the key and one that does not
146
+ still differ; anything else JSON would say alike — an undefined in a list, a non-finite number, an object that is
147
+ not a plain record, a function, a symbol or a BigInt — is no text, and is compiled afresh. */
148
+ const UNDEFINED = Object.freeze({ '\u0000': 'undefined' });
149
+ function breakdownText(def) {
150
+ let plain = true;
151
+ const text = JSON.stringify(def, function (key, item) {
152
+ // The value as held, not as its toJSON says it: a Date is said as text, and is not the text it says.
153
+ const held = this[key];
154
+ if (held === undefined) {
155
+ if (Array.isArray(this))
156
+ plain = false;
157
+ return UNDEFINED;
158
+ }
159
+ // JSON drops a function or symbol (two definitions apart only by one would share a text) and throws on a BigInt.
160
+ if (typeof held === 'function' || typeof held === 'symbol' || typeof held === 'bigint') {
161
+ plain = false;
162
+ return null;
163
+ }
164
+ if ((typeof held === 'number' && !Number.isFinite(held)) ||
165
+ (held !== null && typeof held === 'object' && !Array.isArray(held) && ![null, Object.prototype].includes(Object.getPrototypeOf(held))))
166
+ plain = false;
167
+ return item;
168
+ });
169
+ return plain ? text : undefined;
170
+ }
171
+ const breakdownsKept = new WeakMap();
172
+ const BREAKDOWNS_KEPT = 256;
173
+ let breakdownsCompiled = 0;
174
+ /** For tests: how many breakdowns were compiled rather than found. */
175
+ export function breakdownsCompiledSoFar() {
176
+ return breakdownsCompiled;
177
+ }
178
+ const scopeOrdinals = new WeakMap();
179
+ let scopesSeen = 0;
180
+ const scopeOrdinal = (scope) => {
181
+ let ordinal = scopeOrdinals.get(scope);
182
+ if (ordinal === undefined)
183
+ scopeOrdinals.set(scope, (ordinal = ++scopesSeen));
184
+ return ordinal;
185
+ };
186
+ function compileBreakdownFresh(schema, def, style, offset, scope) {
187
+ // The App's soft keys, where this catalog is the database's own (declaredReferences.ts).
188
+ schema = withViewReferences(schema, def.references);
189
+ const base = findTable(schema, def.base);
190
+ if (!base) {
191
+ throw new PathError(`No table called "${def.base}" in this database, so there is nothing to break down.`, def.base, def.base, 0);
192
+ }
193
+ /* No `by` is one group: the whole answer as a single row —
194
+ "invoice sum total" is a number, not a mistake. The app home's metric
195
+ cards ride on exactly this, and it reads the same in the workbench. */
196
+ if (def.by.length > MAX_KEYS) {
197
+ /* A cap rather than a warning. Three keys is already a table nobody reads
198
+ across; the fourth is how a breakdown becomes the base table again, one
199
+ row per record, with the count column always saying 1. */
200
+ throw new PathError(`A breakdown groups by at most ${MAX_KEYS} things; this one names ${def.by.length}.`, def.by[MAX_KEYS].path, def.by[MAX_KEYS].path, 0);
201
+ }
202
+ if (!def.measures?.length) {
203
+ throw new PathError('A breakdown needs something to measure — `count`, or `sum total`.', '', '', 0);
204
+ }
205
+ const relations = new ScopedRelations(schema, style, scope);
206
+ const baseRelation = relations.table(base.id);
207
+ const plan = new JoinPlan(schema, base, style, relations.table);
208
+ /* The view compiler's paths, so a rollup — the base's or through a
209
+ reference — is the same correlated subquery here as in a list, its
210
+ child rows read through this statement's relations (a row scope's
211
+ CTE). A key, a measure and a condition may each name one. */
212
+ const paths = viewPaths(schema, {
213
+ id: '',
214
+ name: '',
215
+ base: def.base,
216
+ ...(def.computed ? { computed: def.computed } : {}),
217
+ ...(def.expressions ? { expressions: def.expressions } : {}),
218
+ ...(def.tagged ? { tagged: def.tagged } : {}),
219
+ ...(def.labels ? { labels: def.labels } : {}),
220
+ }, plan, style, relations);
221
+ const qualify = (path) => paths.qualify(path);
222
+ const membership = paths.membership;
223
+ const exists = paths.exists;
224
+ const seen = new Map();
225
+ /** Output names are unique or the result set loses a column silently. */
226
+ const nameFor = (wanted) => {
227
+ const count = seen.get(wanted) ?? 0;
228
+ seen.set(wanted, count + 1);
229
+ return count ? `${wanted}_${count + 1}` : wanted;
230
+ };
231
+ const columns = [];
232
+ const select = [];
233
+ const grouping = [];
234
+ for (const key of def.by ?? []) {
235
+ const resolved = paths.resolve(key.path);
236
+ let sql = qualify(key.path);
237
+ if (key.bucket) {
238
+ // A request's word, looked up in the dialect's own table: one of the four, never anything else.
239
+ if (!DATE_UNITS.includes(key.bucket)) {
240
+ throw new PathError(`"${String(key.bucket).slice(0, 40)}" is not a period. Use one of: ${DATE_UNITS.join(', ')}.`, key.path, key.path, 0);
241
+ }
242
+ if (!isDateish(resolved.column.type) && !def.dateColumns?.includes(`${resolved.table.id}.${resolved.column.name}`)) {
243
+ throw new PathError(`"${key.path}" is ${resolved.column.type || 'untyped'}, so it cannot be grouped by ${key.bucket}. ` +
244
+ 'Group by it directly, or pick a date column.', key.path, key.path, resolved.hops.length);
245
+ }
246
+ sql = style.dateBucket(sql, key.bucket, def.weekStart);
247
+ }
248
+ const name = nameFor(key.alias?.trim() || (key.bucket ? `${key.bucket}(${resolved.path})` : resolved.path));
249
+ select.push(`${sql} AS ${style.quote(name)}`);
250
+ /* Grouped by the *expression*, not by the output name. Postgres
251
+ would take the alias; SQLite would too — but a bucketed key aliased to
252
+ `month(invoice_date)` and grouped by that name is one identifier away
253
+ from grouping by a column that happens to share it. The expression is
254
+ never ambiguous.
255
+
256
+ A rollup is the exception: its expression is a correlated subquery,
257
+ and an engine can fail to see two copies of one as
258
+ the same thing, so it refuses the SELECT list's copy as ungrouped.
259
+ Grouped by its position in the SELECT list instead — the one place it
260
+ is written, which every engine groups by and nothing can shadow. */
261
+ grouping.push(def.computed && Object.hasOwn(def.computed, key.path) ? String(select.length) : sql);
262
+ columns.push({
263
+ name,
264
+ kind: 'key',
265
+ path: resolved.path,
266
+ /* A bucket makes text out of whatever it was, and the interface should
267
+ render `2026-08` as the label it is rather than as a date it is not. */
268
+ type: key.bucket ? 'text' : resolved.column.type,
269
+ bucket: key.bucket,
270
+ });
271
+ }
272
+ /* One aggregate's SQL, and what its values are. */
273
+ const termSql = (term) => {
274
+ /* The function is written into the statement as a word, so it is one of
275
+ the words: a structured def arrives from a request (`/api/breakdown`
276
+ `def`), and anything else there would be SQL of the caller's own,
277
+ outside every scope and grant this statement reads through. */
278
+ if (typeof term !== 'object' || term === null || !MEASURE_FUNCTIONS.includes(term.fn)) {
279
+ throw new PathError(`"${String(term?.fn).slice(0, 40)}" is not a measure. Use one of: ${MEASURE_FUNCTIONS.join(', ')}.`, '', '', 0);
280
+ }
281
+ if (term.fn === 'count') {
282
+ if (term.distinct && !term.path) {
283
+ throw new PathError('`count distinct` needs a column to count distinct values of.', '', '', 0);
284
+ }
285
+ /* COUNT(*) rather than COUNT(column) when no column is named: a column
286
+ count skips nulls, which turns "how many invoices" into "how many
287
+ invoices have a total" without saying so. Naming a column is how you
288
+ ask the other question, and then the skipping is the point. */
289
+ return {
290
+ sql: term.path ? `COUNT(${term.distinct ? 'DISTINCT ' : ''}${qualify(term.path)})` : 'COUNT(*)',
291
+ path: term.path,
292
+ type: 'integer',
293
+ };
294
+ }
295
+ if (!term.path) {
296
+ throw new PathError(`\`${term.fn}\` needs a column: \`${term.fn} total\`.`, '', '', 0);
297
+ }
298
+ if (term.distinct) {
299
+ throw new PathError(`\`distinct\` only means something with \`count\`, not with \`${term.fn}\`.`, term.path, term.path, 0);
300
+ }
301
+ const refused = measureRefusal(term.fn, style.dialect);
302
+ if (refused)
303
+ throw new PathError(refused, term.path, term.path, 0);
304
+ const resolved = paths.resolve(term.path);
305
+ const read = aggregateInput(qualify(term.path), resolved.column.type, style.dialect);
306
+ return {
307
+ sql: term.fn === 'median' ? `percentile_cont(0.5) WITHIN GROUP (ORDER BY ${read})` : `${term.fn.toUpperCase()}(${read})`,
308
+ path: resolved.path,
309
+ /* `avg` and `median` are fractions of whatever they read — an average
310
+ of integers is not an integer, and saying otherwise makes the
311
+ interface round a number the database did not. */
312
+ type: term.fn === 'avg' || term.fn === 'median'
313
+ ? 'numeric'
314
+ : term.fn === 'sum' && columnKind(resolved.column.type) === 'boolean'
315
+ ? 'integer'
316
+ : resolved.column.type,
317
+ };
318
+ };
319
+ /* A measure that counts only some rows (`count when [...]`) is written once the statement's own parameters are
320
+ counted, below: its values are bound after the scope's and before the filter's, in the order the text reads. */
321
+ const whens = [];
322
+ const asFilter = (filter) => filter?.groups.length
323
+ ? {
324
+ groups: filter.groups.map((group) => group.map((c) => c.any
325
+ ? { column: c.path, op: c.op, any: c.any }
326
+ : c.other === undefined
327
+ ? { column: c.path, op: c.op, value: c.value }
328
+ : { column: c.path, op: c.op, other: c.other })),
329
+ }
330
+ : undefined;
331
+ /* Every path a condition names is planned (its joins, its tags) before the scope prefix is frozen. */
332
+ const planPaths = (conditions) => {
333
+ for (const group of conditions?.groups ?? []) {
334
+ for (const condition of group) {
335
+ /* A tags condition (`has`) plans its link and tag relations here too, before the scope
336
+ prefix is frozen, as a view's does: its EXISTS reads them through it. */
337
+ if (condition.any) {
338
+ exists(condition.any);
339
+ continue;
340
+ }
341
+ qualify(condition.column);
342
+ if (condition.other !== undefined)
343
+ qualify(condition.other);
344
+ }
345
+ }
346
+ };
347
+ for (const measure of def.measures) {
348
+ if (measure.where !== undefined || measure.when !== undefined) {
349
+ if (measure.fn !== 'count' || measure.path || measure.distinct || measure.steps?.length || !measure.where) {
350
+ throw new PathError('`when` only goes with a bare `count`: `count when [status = open]`.', '', '', 0);
351
+ }
352
+ const conditions = asFilter(measure.where);
353
+ if (conditions) {
354
+ planPaths(conditions);
355
+ const name = nameFor(measureName(measure, undefined));
356
+ whens.push({ at: select.length, name, where: measure.where });
357
+ select.push('');
358
+ columns.push({ name, kind: 'measure', fn: 'count', type: 'integer' });
359
+ continue;
360
+ }
361
+ }
362
+ const head = termSql(measure);
363
+ if (!measure.steps?.length) {
364
+ const name = nameFor(measureName(measure, head.path));
365
+ select.push(`${head.sql} AS ${style.quote(name)}`);
366
+ columns.push({ name, kind: 'measure', fn: measure.fn, path: head.path, type: head.type });
367
+ continue;
368
+ }
369
+ /* A computed measure is written out in its own order: SQL's precedence
370
+ is the grammar's. A divisor is made a decimal, so integer counts do
371
+ not divide to zero on PostgreSQL and SQLite, and NULLIF makes a zero
372
+ one an empty answer instead of an error. */
373
+ const pieces = [head.sql];
374
+ for (const { op, term } of measure.steps) {
375
+ if (!MEASURE_OPS.includes(op))
376
+ throw new PathError(`"${op}" is not arithmetic a measure joins with: + - * or /.`, '', '', 0);
377
+ if (typeof term === 'number' && !Number.isFinite(term))
378
+ throw new PathError("A computed measure's number must be finite.", '', '', 0);
379
+ const sql = typeof term === 'number' ? String(term) : termSql(term).sql;
380
+ pieces.push(op, op === '/' ? `NULLIF(1.0 * ${sql}, 0)` : sql);
381
+ }
382
+ const name = nameFor(measureName(measure, head.path));
383
+ select.push(`(${pieces.join(' ')}) AS ${style.quote(name)}`);
384
+ columns.push({ name, kind: 'measure', type: 'numeric' });
385
+ }
386
+ /* A key that is a reference is said by its record's name, as a grid's cell
387
+ is: the name through the same join the key's path walks, read through
388
+ this statement's relations, so a record this reader's scope does not
389
+ admit has no name and the group stays its key. Last, after the
390
+ measures, so a reader that takes the key and the measure by position
391
+ reads what it always did; grouped by position, since the key decides it. */
392
+ for (const [index, key] of (def.by ?? []).entries()) {
393
+ if (key.bucket || !def.names || !Object.hasOwn(def.names, key.path))
394
+ continue;
395
+ const path = def.names[key.path];
396
+ const name = nameFor(`${columns[index].name}.${LABEL_SEGMENT}`);
397
+ select.push(`${qualify(path)} AS ${style.quote(name)}`);
398
+ grouping.push(String(select.length));
399
+ columns.push({ name, kind: 'label', of: columns[index].name, path, type: 'text' });
400
+ }
401
+ const conditions = asFilter(def.filter);
402
+ planPaths(conditions);
403
+ const joins = plan.clauses();
404
+ const prefix = relations.finish();
405
+ const whenParams = [];
406
+ for (const { at, name, where: held } of whens) {
407
+ const built = buildWhere(asFilter(held), style, prefix.params.length + whenParams.length + 1, qualify, qualify, membership, exists);
408
+ whenParams.push(...built.params);
409
+ /* COUNT, not SUM: a count of no rows is 0, where a sum of none is null. */
410
+ select[at] = `COUNT(CASE WHEN ${built.text.replace(/^ WHERE /, '')} THEN 1 END) AS ${style.quote(name)}`;
411
+ }
412
+ const where = buildWhere(conditions, style, prefix.params.length + whenParams.length + 1, qualify, qualify, membership, exists);
413
+ /* Sorted by output name, and only by output name.
414
+
415
+ Every column of a breakdown is either a key or a measure, and both are in
416
+ the SELECT list under a name — so there is nothing else it could sort by,
417
+ and ORDER BY runs late enough to see the aliases on all three engines.
418
+ Sorting by an expression instead would let `sort total desc` mean the
419
+ ungrouped column on a statement where that column no longer exists. */
420
+ const names = new Set(columns.map((c) => c.name));
421
+ const order = (def.orderBy ?? []).map((o) => {
422
+ if (!names.has(o.name)) {
423
+ throw new PathError(`Nothing called "${o.name}" is in this breakdown. It shows: ${[...names].join(', ')}.`, o.name, o.name, 0);
424
+ }
425
+ if (o.emptyLast)
426
+ return `(${style.quote(o.name)} IS NULL) ASC`;
427
+ return `${style.quote(o.name)} ${o.direction === 'desc' ? 'DESC' : 'ASC'}`;
428
+ });
429
+ const limit = clampLimit(def.limit);
430
+ const skip = clampOffset(offset);
431
+ const n = prefix.params.length + whenParams.length + where.params.length;
432
+ const lines = [`SELECT ${select.join(',\n ')}`, ` FROM ${baseRelation} ${style.quote(plan.baseAlias)}`, ...joins];
433
+ if (where.text)
434
+ lines.push(where.text);
435
+ if (grouping.length)
436
+ lines.push(` GROUP BY ${grouping.join(', ')}`);
437
+ if (order.length)
438
+ lines.push(` ORDER BY ${order.join(', ')}`);
439
+ lines.push(` LIMIT ${style.placeholder(n + 1)} OFFSET ${style.placeholder(n + 2)}`);
440
+ return { text: prefix.text + lines.join('\n'), params: [...prefix.params, ...whenParams, ...where.params, limit, skip], columns, limit };
441
+ }
442
+ /**
443
+ * The breakdown with the rollups its paths name, read from a catalog that
444
+ * serves them (an App's) — and with any it arrived with dropped, as
445
+ * withViewComputed does for a view: which rows a number sums is the
446
+ * catalog's to say, never a request's.
447
+ */
448
+ export function withBreakdownComputed(schema, def) {
449
+ // A request's declared dates and names are dropped with its rollups: all are the catalog's to carry (appResources.ts).
450
+ const { computed: _given, expressions: _written, tagged: _tagged, dateColumns: _dated, names: _names, labels: _labels, ...rest } = def;
451
+ /* A key that is a reference to a record with a name: its groups are said
452
+ by that name (compileBreakdown), the one a grid's cell reads (labelPath),
453
+ through the same reference. */
454
+ const names = {};
455
+ const labels = {};
456
+ for (const key of def.by ?? []) {
457
+ if (typeof key?.path !== 'string' || key.bucket || Object.hasOwn(names, key.path))
458
+ continue;
459
+ const target = tableAtPrefix(schema, def.base, key.path);
460
+ const resolved = target && tryResolvePath(schema, def.base, key.path).resolved;
461
+ if (!target || !resolved || resolved.rollup)
462
+ continue;
463
+ const naming = labelPath(schema, target);
464
+ if (!naming)
465
+ continue;
466
+ names[key.path] = `${key.path}.${naming}`;
467
+ const prefix = labelPrefix(names[key.path]);
468
+ if (prefix !== undefined && target.labelTemplate)
469
+ labels[prefix] = target.labelTemplate;
470
+ }
471
+ const named = Object.keys(names).length ? { ...rest, names, ...(Object.keys(labels).length ? { labels } : {}) } : rest;
472
+ const paths = [
473
+ ...(def.by ?? []).map((key) => key.path),
474
+ ...(def.measures ?? []).flatMap(measurePaths),
475
+ ...filterPaths(def.filter),
476
+ ...measureConditions(def.measures).flatMap(filterPaths),
477
+ ];
478
+ /* The rollups and computed columns its paths name, as a view's are (withViewComputed). */
479
+ const pinned = withViewComputed(schema, {
480
+ id: '',
481
+ name: '',
482
+ base: def.base,
483
+ columns: paths.filter((path) => typeof path === 'string').map((path) => ({ path })),
484
+ });
485
+ return {
486
+ ...named,
487
+ ...(pinned.computed ? { computed: pinned.computed } : {}),
488
+ ...(pinned.expressions ? { expressions: pinned.expressions } : {}),
489
+ ...(pinned.tagged ? { tagged: pinned.tagged } : {}),
490
+ };
491
+ }
492
+ /**
493
+ * How many groups there are, ignoring the page.
494
+ *
495
+ * `SELECT COUNT(*) FROM (the grouped statement)` — the only honest way to
496
+ * count groups, because the number is a property of the grouping rather than
497
+ * of the base table. Without the limit and offset, which is the whole point of
498
+ * asking.
499
+ */
500
+ export function compileBreakdownCount(schema, def, style, scope, limit) {
501
+ const inner = compileBreakdown(schema, def, style, 0, scope);
502
+ /* The LIMIT/OFFSET line is the last one and carries the last two
503
+ parameters. Dropped by rebuilding rather than by string surgery would be
504
+ nicer; it is the last line by construction, and the test says so. */
505
+ const lines = inner.text.split('\n');
506
+ const body = lines.slice(0, -1).join('\n');
507
+ return {
508
+ /* With a bound, at most `limit` groups are counted (countStatement). The
509
+ grouping itself still reads what it groups; the bound keeps the count's
510
+ answer, not the scan, from growing with the data. */
511
+ text: limit === undefined ? `SELECT COUNT(*) AS n FROM (\n${body}\n) AS grouped` : countStatement(`(\n${body}\n) AS grouped`, limit),
512
+ params: inner.params.slice(0, -2),
513
+ };
514
+ }
515
+ /**
516
+ * Render a breakdown as the SQL it will become, values inline.
517
+ *
518
+ * The exact counterpart of `explainView`, and here for the same reason: the
519
+ * SQL pane is how somebody learns what a line of the language did on their
520
+ * behalf, and a statement full of `?` teaches nothing about the filter that
521
+ * produced it. It also has to be a statement that runs, because the pane
522
+ * offers to open it in the SQL editor.
523
+ */
524
+ export function explainBreakdown(schema, def, style, offset = 0) {
525
+ const compiled = compileBreakdown(schema, def, style, offset);
526
+ let i = 0;
527
+ return compiled.text.replace(/\$\d+|\?/g, () => sqlLiteral(compiled.params[i++]));
528
+ }
529
+ /**
530
+ * The answer as its readers take it — the keys first and the measures after,
531
+ * by position — with each reference key's names (compileBreakdown's `label`
532
+ * columns) lifted out beside it: a chart reads its key and measure by index,
533
+ * a board its count last, and a name among them would be read as either.
534
+ */
535
+ export function withGroupNames(result) {
536
+ const labels = result.resolved.filter((column) => column.kind === 'label' && column.of);
537
+ if (!labels.length)
538
+ return result;
539
+ const names = {};
540
+ for (const label of labels) {
541
+ const said = {};
542
+ for (const row of result.rows) {
543
+ const key = row[label.of], name = row[label.name];
544
+ if (key !== null && key !== undefined && typeof name === 'string' && name !== '')
545
+ said[String(key)] = name;
546
+ }
547
+ names[label.of] = said;
548
+ }
549
+ const hidden = new Set(labels.map((label) => label.name));
550
+ return {
551
+ ...result,
552
+ columns: result.columns.filter((name) => !hidden.has(name)),
553
+ resolved: result.resolved.filter((column) => !hidden.has(column.name)),
554
+ rows: result.rows.map((row) => Object.fromEntries(Object.entries(row).filter(([name]) => !hidden.has(name)))),
555
+ names,
556
+ };
557
+ }
@@ -0,0 +1,41 @@
1
+ import { type DatabaseSchema } from './schema.js';
2
+ import type { QueryError, QueryPerson } from './query.js';
3
+ import { type BreakdownDef } from './breakdown.js';
4
+ interface ParsedBreakdownText {
5
+ breakdown?: BreakdownDef;
6
+ /** The conditions half of the line, exactly as typed — everything
7
+ before the measures. The section emitter's whole reason to exist
8
+ here: only the parser knows where that boundary fell. */
9
+ conditions?: string;
10
+ errors: QueryError[];
11
+ }
12
+ /** Whether a line is asking for a breakdown at all. */
13
+ export declare function looksLikeBreakdown(text: string): boolean;
14
+ export declare function textToBreakdown(schema: DatabaseSchema, text: string, options?: {
15
+ now?: Date;
16
+ me?: QueryPerson | null;
17
+ }): ParsedBreakdownText;
18
+ /**
19
+ * The line as an authored dashboard section, or null when it is not one:
20
+ * the workbench-to-config bridge. Compose in the query bar, copy the
21
+ * section, paste it into a dashboard — the kind is read off the shape
22
+ * (two keys cross a matrix, a bucketed key draws a chart, one plain key
23
+ * ranks a breakdown, none is a metric), and the conditions half survives
24
+ * exactly as typed, because only this parser knows where it ended.
25
+ */
26
+ export declare function sectionFromText(schema: DatabaseSchema, text: string): {
27
+ kind: "breakdown" | "chart" | "matrix" | "metric";
28
+ table: string;
29
+ query?: string | undefined;
30
+ measure?: string | undefined;
31
+ by?: string | undefined;
32
+ } | null;
33
+ /**
34
+ * Render a breakdown as text — the inverse, and the round trip is tested.
35
+ *
36
+ * One line, unlike a view. A breakdown is a phrase: two measures and a key is
37
+ * the normal size of one, and the whole point of the form is that it fits in
38
+ * a query bar.
39
+ */
40
+ export declare function breakdownToText(schema: DatabaseSchema, def: BreakdownDef): string;
41
+ export {};