ultimabase 0.0.0-stage → 0.1.0

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 (411) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +4 -2
  3. package/dist/access.d.ts +62 -0
  4. package/dist/access.d.ts.map +1 -0
  5. package/dist/access.js +258 -0
  6. package/dist/adapter-errors.d.ts +43 -0
  7. package/dist/adapter-errors.d.ts.map +1 -0
  8. package/dist/adapter-errors.js +72 -0
  9. package/dist/adapter-json.d.ts +20 -0
  10. package/dist/adapter-json.d.ts.map +1 -0
  11. package/dist/adapter-json.js +2 -0
  12. package/dist/adapter-migrations.d.ts +90 -0
  13. package/dist/adapter-migrations.d.ts.map +1 -0
  14. package/dist/adapter-migrations.js +1 -0
  15. package/dist/adapter.d.ts +333 -0
  16. package/dist/adapter.d.ts.map +1 -0
  17. package/dist/adapter.js +5 -0
  18. package/dist/aggregate.d.ts +31 -0
  19. package/dist/aggregate.d.ts.map +1 -0
  20. package/dist/aggregate.js +99 -0
  21. package/dist/app-internals.d.ts +10 -0
  22. package/dist/app-internals.d.ts.map +1 -0
  23. package/dist/app-internals.js +12 -0
  24. package/dist/app-options.d.ts +22 -0
  25. package/dist/app-options.d.ts.map +1 -0
  26. package/dist/app-options.js +3 -0
  27. package/dist/cascade.d.ts +47 -0
  28. package/dist/cascade.d.ts.map +1 -0
  29. package/dist/cascade.js +209 -0
  30. package/dist/cli-config.d.ts +6 -0
  31. package/dist/cli-config.d.ts.map +1 -0
  32. package/dist/cli-config.js +45 -0
  33. package/dist/cli-deploy.d.ts +14 -0
  34. package/dist/cli-deploy.d.ts.map +1 -0
  35. package/dist/cli-deploy.js +193 -0
  36. package/dist/cli-main.d.ts +16 -0
  37. package/dist/cli-main.d.ts.map +1 -0
  38. package/dist/cli-main.js +151 -0
  39. package/dist/cli-migrate.d.ts +20 -0
  40. package/dist/cli-migrate.d.ts.map +1 -0
  41. package/dist/cli-migrate.js +105 -0
  42. package/dist/cli.d.ts +3 -0
  43. package/dist/cli.d.ts.map +1 -0
  44. package/dist/cli.js +4 -0
  45. package/dist/complete.d.ts +13 -0
  46. package/dist/complete.d.ts.map +1 -0
  47. package/dist/complete.js +60 -0
  48. package/dist/console-logger.d.ts +3 -0
  49. package/dist/console-logger.d.ts.map +1 -0
  50. package/dist/console-logger.js +62 -0
  51. package/dist/create-many.d.ts +7 -0
  52. package/dist/create-many.d.ts.map +1 -0
  53. package/dist/create-many.js +88 -0
  54. package/dist/decimal.d.ts +23 -0
  55. package/dist/decimal.d.ts.map +1 -0
  56. package/dist/decimal.js +50 -0
  57. package/dist/define-app.d.ts +59 -0
  58. package/dist/define-app.d.ts.map +1 -0
  59. package/dist/define-app.js +5 -0
  60. package/dist/define-enum.d.ts +6 -0
  61. package/dist/define-enum.d.ts.map +1 -0
  62. package/dist/define-enum.js +18 -0
  63. package/dist/define-function.d.ts +25 -0
  64. package/dist/define-function.d.ts.map +1 -0
  65. package/dist/define-function.js +111 -0
  66. package/dist/define-model.d.ts +48 -0
  67. package/dist/define-model.d.ts.map +1 -0
  68. package/dist/define-model.js +85 -0
  69. package/dist/definition.d.ts +179 -0
  70. package/dist/definition.d.ts.map +1 -0
  71. package/dist/definition.js +165 -0
  72. package/dist/delete-many.d.ts +13 -0
  73. package/dist/delete-many.d.ts.map +1 -0
  74. package/dist/delete-many.js +58 -0
  75. package/dist/engine.d.ts +16 -0
  76. package/dist/engine.d.ts.map +1 -0
  77. package/dist/engine.js +174 -0
  78. package/dist/errors.d.ts +50 -0
  79. package/dist/errors.d.ts.map +1 -0
  80. package/dist/errors.js +43 -0
  81. package/dist/exact.d.ts +20 -0
  82. package/dist/exact.d.ts.map +1 -0
  83. package/dist/exact.js +1 -0
  84. package/dist/feed.d.ts +6 -0
  85. package/dist/feed.d.ts.map +1 -0
  86. package/dist/feed.js +33 -0
  87. package/dist/field-codec.d.ts +11 -0
  88. package/dist/field-codec.d.ts.map +1 -0
  89. package/dist/field-codec.js +48 -0
  90. package/dist/field-rules.d.ts +57 -0
  91. package/dist/field-rules.d.ts.map +1 -0
  92. package/dist/field-rules.js +1 -0
  93. package/dist/field-type.d.ts +51 -0
  94. package/dist/field-type.d.ts.map +1 -0
  95. package/dist/field-type.js +106 -0
  96. package/dist/fields.d.ts +295 -0
  97. package/dist/fields.d.ts.map +1 -0
  98. package/dist/fields.js +1 -0
  99. package/dist/function.d.ts +126 -0
  100. package/dist/function.d.ts.map +1 -0
  101. package/dist/function.js +1 -0
  102. package/dist/functions.d.ts +18 -0
  103. package/dist/functions.d.ts.map +1 -0
  104. package/dist/functions.js +99 -0
  105. package/dist/group-by.d.ts +10 -0
  106. package/dist/group-by.d.ts.map +1 -0
  107. package/dist/group-by.js +145 -0
  108. package/dist/group-having.d.ts +8 -0
  109. package/dist/group-having.d.ts.map +1 -0
  110. package/dist/group-having.js +97 -0
  111. package/dist/hooks.d.ts +41 -0
  112. package/dist/hooks.d.ts.map +1 -0
  113. package/dist/hooks.js +149 -0
  114. package/dist/hosts.d.ts +3 -0
  115. package/dist/hosts.d.ts.map +1 -0
  116. package/dist/hosts.js +8 -0
  117. package/dist/identify.d.ts +15 -0
  118. package/dist/identify.d.ts.map +1 -0
  119. package/dist/identify.js +71 -0
  120. package/dist/index.d.ts +25 -0
  121. package/dist/index.d.ts.map +1 -0
  122. package/dist/index.js +12 -0
  123. package/dist/internal.d.ts +28 -0
  124. package/dist/internal.d.ts.map +1 -0
  125. package/dist/internal.js +39 -0
  126. package/dist/lifecycle.d.ts +21 -0
  127. package/dist/lifecycle.d.ts.map +1 -0
  128. package/dist/lifecycle.js +149 -0
  129. package/dist/list-update.d.ts +12 -0
  130. package/dist/list-update.d.ts.map +1 -0
  131. package/dist/list-update.js +52 -0
  132. package/dist/live.d.ts +37 -0
  133. package/dist/live.d.ts.map +1 -0
  134. package/dist/live.js +139 -0
  135. package/dist/manifest.d.ts +11 -0
  136. package/dist/manifest.d.ts.map +1 -0
  137. package/dist/manifest.js +60 -0
  138. package/dist/memory-aggregate.d.ts +7 -0
  139. package/dist/memory-aggregate.d.ts.map +1 -0
  140. package/dist/memory-aggregate.js +107 -0
  141. package/dist/memory-conditions.d.ts +8 -0
  142. package/dist/memory-conditions.d.ts.map +1 -0
  143. package/dist/memory-conditions.js +82 -0
  144. package/dist/memory-draft.d.ts +34 -0
  145. package/dist/memory-draft.d.ts.map +1 -0
  146. package/dist/memory-draft.js +255 -0
  147. package/dist/memory-json.d.ts +6 -0
  148. package/dist/memory-json.d.ts.map +1 -0
  149. package/dist/memory-json.js +86 -0
  150. package/dist/memory-read.d.ts +45 -0
  151. package/dist/memory-read.d.ts.map +1 -0
  152. package/dist/memory-read.js +244 -0
  153. package/dist/memory-search.d.ts +16 -0
  154. package/dist/memory-search.d.ts.map +1 -0
  155. package/dist/memory-search.js +110 -0
  156. package/dist/memory-values.d.ts +23 -0
  157. package/dist/memory-values.d.ts.map +1 -0
  158. package/dist/memory-values.js +82 -0
  159. package/dist/memory.d.ts +4 -0
  160. package/dist/memory.d.ts.map +1 -0
  161. package/dist/memory.js +157 -0
  162. package/dist/migrate.d.ts +22 -0
  163. package/dist/migrate.d.ts.map +1 -0
  164. package/dist/migrate.js +131 -0
  165. package/dist/model.d.ts +239 -0
  166. package/dist/model.d.ts.map +1 -0
  167. package/dist/model.js +1 -0
  168. package/dist/nested-write.d.ts +64 -0
  169. package/dist/nested-write.d.ts.map +1 -0
  170. package/dist/nested-write.js +274 -0
  171. package/dist/number-update.d.ts +18 -0
  172. package/dist/number-update.d.ts.map +1 -0
  173. package/dist/number-update.js +96 -0
  174. package/dist/plugin-app.d.ts +48 -0
  175. package/dist/plugin-app.d.ts.map +1 -0
  176. package/dist/plugin-app.js +230 -0
  177. package/dist/plugin-code.d.ts +17 -0
  178. package/dist/plugin-code.d.ts.map +1 -0
  179. package/dist/plugin-code.js +125 -0
  180. package/dist/plugin-use.d.ts +22 -0
  181. package/dist/plugin-use.d.ts.map +1 -0
  182. package/dist/plugin-use.js +161 -0
  183. package/dist/plugin.d.ts +357 -0
  184. package/dist/plugin.d.ts.map +1 -0
  185. package/dist/plugin.js +17 -0
  186. package/dist/query-aggregate.d.ts +82 -0
  187. package/dist/query-aggregate.d.ts.map +1 -0
  188. package/dist/query-aggregate.js +1 -0
  189. package/dist/query-args.d.ts +41 -0
  190. package/dist/query-args.d.ts.map +1 -0
  191. package/dist/query-args.js +263 -0
  192. package/dist/query-bulk.d.ts +35 -0
  193. package/dist/query-bulk.d.ts.map +1 -0
  194. package/dist/query-bulk.js +1 -0
  195. package/dist/query-conditions.d.ts +9 -0
  196. package/dist/query-conditions.d.ts.map +1 -0
  197. package/dist/query-conditions.js +46 -0
  198. package/dist/query-context.d.ts +32 -0
  199. package/dist/query-context.d.ts.map +1 -0
  200. package/dist/query-context.js +55 -0
  201. package/dist/query-filter.d.ts +46 -0
  202. package/dist/query-filter.d.ts.map +1 -0
  203. package/dist/query-filter.js +1 -0
  204. package/dist/query-group.d.ts +82 -0
  205. package/dist/query-group.d.ts.map +1 -0
  206. package/dist/query-group.js +1 -0
  207. package/dist/query-json.d.ts +9 -0
  208. package/dist/query-json.d.ts.map +1 -0
  209. package/dist/query-json.js +66 -0
  210. package/dist/query-order.d.ts +15 -0
  211. package/dist/query-order.d.ts.map +1 -0
  212. package/dist/query-order.js +115 -0
  213. package/dist/query-project.d.ts +15 -0
  214. package/dist/query-project.d.ts.map +1 -0
  215. package/dist/query-project.js +45 -0
  216. package/dist/query-search.d.ts +24 -0
  217. package/dist/query-search.d.ts.map +1 -0
  218. package/dist/query-search.js +2 -0
  219. package/dist/query-values.d.ts +28 -0
  220. package/dist/query-values.d.ts.map +1 -0
  221. package/dist/query-values.js +91 -0
  222. package/dist/query-where.d.ts +46 -0
  223. package/dist/query-where.d.ts.map +1 -0
  224. package/dist/query-where.js +200 -0
  225. package/dist/query-write.d.ts +14 -0
  226. package/dist/query-write.d.ts.map +1 -0
  227. package/dist/query-write.js +260 -0
  228. package/dist/query.d.ts +254 -0
  229. package/dist/query.d.ts.map +1 -0
  230. package/dist/query.js +1 -0
  231. package/dist/record.d.ts +257 -0
  232. package/dist/record.d.ts.map +1 -0
  233. package/dist/record.js +1 -0
  234. package/dist/recorder.d.ts +32 -0
  235. package/dist/recorder.d.ts.map +1 -0
  236. package/dist/recorder.js +152 -0
  237. package/dist/relation-write.d.ts +41 -0
  238. package/dist/relation-write.d.ts.map +1 -0
  239. package/dist/relation-write.js +112 -0
  240. package/dist/relations.d.ts +42 -0
  241. package/dist/relations.d.ts.map +1 -0
  242. package/dist/relations.js +119 -0
  243. package/dist/rules.d.ts +97 -0
  244. package/dist/rules.d.ts.map +1 -0
  245. package/dist/rules.js +71 -0
  246. package/dist/running.d.ts +29 -0
  247. package/dist/running.d.ts.map +1 -0
  248. package/dist/running.js +39 -0
  249. package/dist/schema-indexes.d.ts +11 -0
  250. package/dist/schema-indexes.d.ts.map +1 -0
  251. package/dist/schema-indexes.js +59 -0
  252. package/dist/schema-virtuals.d.ts +19 -0
  253. package/dist/schema-virtuals.d.ts.map +1 -0
  254. package/dist/schema-virtuals.js +100 -0
  255. package/dist/schema.d.ts +35 -0
  256. package/dist/schema.d.ts.map +1 -0
  257. package/dist/schema.js +267 -0
  258. package/dist/scope.d.ts +46 -0
  259. package/dist/scope.d.ts.map +1 -0
  260. package/dist/scope.js +82 -0
  261. package/dist/scratch.d.ts +14 -0
  262. package/dist/scratch.d.ts.map +1 -0
  263. package/dist/scratch.js +10 -0
  264. package/dist/serve.d.ts +2 -0
  265. package/dist/serve.d.ts.map +1 -0
  266. package/dist/serve.js +4 -0
  267. package/dist/symbols.d.ts +10 -0
  268. package/dist/symbols.d.ts.map +1 -0
  269. package/dist/symbols.js +1 -0
  270. package/dist/transaction.d.ts +28 -0
  271. package/dist/transaction.d.ts.map +1 -0
  272. package/dist/transaction.js +156 -0
  273. package/dist/types.d.ts +58 -0
  274. package/dist/types.d.ts.map +1 -0
  275. package/dist/types.js +1 -0
  276. package/dist/update-many.d.ts +7 -0
  277. package/dist/update-many.d.ts.map +1 -0
  278. package/dist/update-many.js +182 -0
  279. package/dist/uuid.d.ts +7 -0
  280. package/dist/uuid.d.ts.map +1 -0
  281. package/dist/uuid.js +48 -0
  282. package/dist/validation.d.ts +24 -0
  283. package/dist/validation.d.ts.map +1 -0
  284. package/dist/validation.js +72 -0
  285. package/dist/virtual-read.d.ts +9 -0
  286. package/dist/virtual-read.d.ts.map +1 -0
  287. package/dist/virtual-read.js +145 -0
  288. package/dist/virtual.d.ts +142 -0
  289. package/dist/virtual.d.ts.map +1 -0
  290. package/dist/virtual.js +1 -0
  291. package/dist/write-context.d.ts +46 -0
  292. package/dist/write-context.d.ts.map +1 -0
  293. package/dist/write-context.js +102 -0
  294. package/dist/write-data.d.ts +26 -0
  295. package/dist/write-data.d.ts.map +1 -0
  296. package/dist/write-data.js +144 -0
  297. package/dist/write-plan.d.ts +107 -0
  298. package/dist/write-plan.d.ts.map +1 -0
  299. package/dist/write-plan.js +170 -0
  300. package/dist/write-target.d.ts +17 -0
  301. package/dist/write-target.d.ts.map +1 -0
  302. package/dist/write-target.js +59 -0
  303. package/dist/writes.d.ts +23 -0
  304. package/dist/writes.d.ts.map +1 -0
  305. package/dist/writes.js +246 -0
  306. package/dist/writing.d.ts +10 -0
  307. package/dist/writing.d.ts.map +1 -0
  308. package/dist/writing.js +66 -0
  309. package/package.json +42 -3
  310. package/src/access.ts +329 -0
  311. package/src/adapter-errors.ts +89 -0
  312. package/src/adapter-json.ts +21 -0
  313. package/src/adapter-migrations.ts +98 -0
  314. package/src/adapter.ts +363 -0
  315. package/src/aggregate.ts +136 -0
  316. package/src/app-internals.ts +26 -0
  317. package/src/app-options.ts +24 -0
  318. package/src/cascade.ts +297 -0
  319. package/src/cli-config.ts +45 -0
  320. package/src/cli-deploy.ts +235 -0
  321. package/src/cli-main.ts +165 -0
  322. package/src/cli-migrate.ts +143 -0
  323. package/src/cli.ts +5 -0
  324. package/src/complete.ts +73 -0
  325. package/src/console-logger.ts +87 -0
  326. package/src/create-many.ts +126 -0
  327. package/src/decimal.ts +74 -0
  328. package/src/define-app.ts +108 -0
  329. package/src/define-enum.ts +26 -0
  330. package/src/define-function.ts +188 -0
  331. package/src/define-model.ts +220 -0
  332. package/src/definition.ts +352 -0
  333. package/src/delete-many.ts +76 -0
  334. package/src/engine.ts +281 -0
  335. package/src/errors.ts +97 -0
  336. package/src/exact.ts +49 -0
  337. package/src/feed.ts +39 -0
  338. package/src/field-codec.ts +72 -0
  339. package/src/field-rules.ts +77 -0
  340. package/src/field-type.ts +219 -0
  341. package/src/fields.ts +383 -0
  342. package/src/function.ts +143 -0
  343. package/src/functions.ts +154 -0
  344. package/src/group-by.ts +186 -0
  345. package/src/group-having.ts +143 -0
  346. package/src/hooks.ts +215 -0
  347. package/src/hosts.ts +11 -0
  348. package/src/identify.ts +95 -0
  349. package/src/index.ts +125 -0
  350. package/src/internal.ts +68 -0
  351. package/src/lifecycle.ts +214 -0
  352. package/src/list-update.ts +71 -0
  353. package/src/live.ts +199 -0
  354. package/src/manifest.ts +71 -0
  355. package/src/memory-aggregate.ts +162 -0
  356. package/src/memory-conditions.ts +88 -0
  357. package/src/memory-draft.ts +319 -0
  358. package/src/memory-json.ts +91 -0
  359. package/src/memory-read.ts +311 -0
  360. package/src/memory-search.ts +149 -0
  361. package/src/memory-values.ts +106 -0
  362. package/src/memory.ts +173 -0
  363. package/src/migrate.ts +152 -0
  364. package/src/model.ts +312 -0
  365. package/src/nested-write.ts +390 -0
  366. package/src/number-update.ts +142 -0
  367. package/src/plugin-app.ts +308 -0
  368. package/src/plugin-code.ts +158 -0
  369. package/src/plugin-use.ts +217 -0
  370. package/src/plugin.ts +400 -0
  371. package/src/query-aggregate.ts +96 -0
  372. package/src/query-args.ts +375 -0
  373. package/src/query-bulk.ts +53 -0
  374. package/src/query-conditions.ts +53 -0
  375. package/src/query-context.ts +104 -0
  376. package/src/query-filter.ts +54 -0
  377. package/src/query-group.ts +137 -0
  378. package/src/query-json.ts +90 -0
  379. package/src/query-order.ts +158 -0
  380. package/src/query-project.ts +73 -0
  381. package/src/query-search.ts +31 -0
  382. package/src/query-values.ts +131 -0
  383. package/src/query-where.ts +318 -0
  384. package/src/query-write.ts +360 -0
  385. package/src/query.ts +400 -0
  386. package/src/record.ts +379 -0
  387. package/src/recorder.ts +212 -0
  388. package/src/relation-write.ts +176 -0
  389. package/src/relations.ts +165 -0
  390. package/src/rules.ts +188 -0
  391. package/src/running.ts +62 -0
  392. package/src/schema-indexes.ts +88 -0
  393. package/src/schema-virtuals.ts +134 -0
  394. package/src/schema.ts +367 -0
  395. package/src/scope.ts +123 -0
  396. package/src/scratch.ts +28 -0
  397. package/src/serve.ts +5 -0
  398. package/src/symbols.ts +11 -0
  399. package/src/transaction.ts +211 -0
  400. package/src/types.ts +79 -0
  401. package/src/update-many.ts +268 -0
  402. package/src/uuid.ts +51 -0
  403. package/src/validation.ts +107 -0
  404. package/src/virtual-read.ts +198 -0
  405. package/src/virtual.ts +187 -0
  406. package/src/write-context.ts +170 -0
  407. package/src/write-data.ts +188 -0
  408. package/src/write-plan.ts +273 -0
  409. package/src/write-target.ts +92 -0
  410. package/src/writes.ts +361 -0
  411. package/src/writing.ts +93 -0
@@ -0,0 +1,108 @@
1
+ // `defineApp` (D-24, D-59): the application's models and plugins, checked
2
+ // together on its line, and its `start` and `stop` (D-91).
3
+ import type { Adapter } from './adapter.ts'
4
+ import { remember } from './app-internals.ts'
5
+ import type { Logger, MasterKey } from './app-options.ts'
6
+ import type { FunctionShape } from './function.ts'
7
+ import { lifecycle } from './lifecycle.ts'
8
+ import type {
9
+ App,
10
+ FieldTypePlugins,
11
+ InverseCheck,
12
+ ModelShape,
13
+ } from './model.ts'
14
+ import type { PluginValue } from './plugin.ts'
15
+ import type { fieldType, modelFields } from './symbols.ts'
16
+
17
+ // Checked on the `defineApp` line, where every model is typed (D-24).
18
+ type Used<M> =
19
+ | (M extends { readonly plugins?: infer P } ? P : never)
20
+ | (M extends { readonly [modelFields]: infer F }
21
+ ? FieldTypePlugins<F>
22
+ : never)
23
+ type Missing<P extends readonly PluginValue<string, string>[], X> = Exclude<
24
+ Used<X>,
25
+ P[number]['name'] | undefined
26
+ >
27
+ type RequiresOf<V> = V extends PluginValue<string, infer R> ? R : never
28
+ type Unmet<P extends readonly PluginValue<string, string>[]> = Exclude<
29
+ RequiresOf<P[number]>,
30
+ P[number]['name']
31
+ >
32
+ type PluginCheck<
33
+ P extends readonly PluginValue<string, string>[],
34
+ M extends readonly ModelShape[],
35
+ Fn extends readonly FunctionShape[],
36
+ > = [Missing<P, M[number]>] extends [never]
37
+ ? [Missing<P, Fn[number]>] extends [never]
38
+ ? [Unmet<P>] extends [never]
39
+ ? unknown
40
+ : {
41
+ readonly pluginError: `a plugin requires '${Unmet<P> & string}', which is not in plugins`
42
+ }
43
+ : {
44
+ readonly pluginError: `a function uses '${Missing<P, Fn[number]> & string}', which is not in plugins`
45
+ }
46
+ : {
47
+ readonly pluginError: `a model uses '${Missing<P, M[number]> & string}', which is not in plugins`
48
+ }
49
+
50
+ type Targets<X> = X extends { readonly [modelFields]: infer F }
51
+ ? {
52
+ [K in keyof F]: F[K] extends {
53
+ readonly [fieldType]: { readonly target: () => infer T }
54
+ }
55
+ ? T extends { readonly name: infer N }
56
+ ? N
57
+ : never
58
+ : never
59
+ }[keyof F]
60
+ : never
61
+ type Unlisted<M extends readonly ModelShape[]> = Exclude<
62
+ Targets<M[number]>,
63
+ M[number]['name']
64
+ >
65
+ // Over the names alone, tail-recursive, so a long list stays cheap and within
66
+ // TypeScript's depth. A name typed `string`, a model a function builds, is not
67
+ // compared.
68
+ type Names<M> = {
69
+ [I in keyof M]: M[I] extends { readonly name: infer N } ? N : never
70
+ }
71
+ type Twice<N, Seen = never, Found = never> = N extends readonly [
72
+ infer H,
73
+ ...infer R,
74
+ ]
75
+ ? string extends H
76
+ ? Twice<R, Seen, Found>
77
+ : Twice<R, Seen | H, H extends Seen ? Found | H : Found>
78
+ : Found
79
+ type ModelCheck<M extends readonly ModelShape[]> = [Twice<Names<M>>] extends [
80
+ never,
81
+ ]
82
+ ? [Unlisted<M>] extends [never]
83
+ ? unknown
84
+ : {
85
+ readonly modelError: `a relation points to '${Unlisted<M> & string}', which is not in models`
86
+ }
87
+ : {
88
+ readonly modelError: `two models are named '${Twice<Names<M>> & string}'`
89
+ }
90
+
91
+ export function defineApp<
92
+ const P extends readonly PluginValue<string, string>[] = [],
93
+ const M extends readonly ModelShape[] = [],
94
+ const Fn extends readonly FunctionShape[] = [],
95
+ >(
96
+ options: {
97
+ readonly database: Adapter
98
+ readonly plugins?: P
99
+ readonly models: M
100
+ readonly functions?: Fn
101
+ readonly masterKey?: MasterKey
102
+ readonly logger?: Logger
103
+ } & NoInfer<PluginCheck<P, M, Fn>> &
104
+ NoInfer<ModelCheck<M>> &
105
+ NoInfer<InverseCheck<M>>,
106
+ ): App<M> {
107
+ return remember({ models: options.models, ...lifecycle(options) }, options)
108
+ }
@@ -0,0 +1,26 @@
1
+ // Shared enums (D-150): one name and its values, which every field taking
2
+ // it shows as one GraphQL enum and one OpenAPI schema; storage is unchanged.
3
+ import { describedBy, enumValues, sharedEnums } from './definition.ts'
4
+ import type { Enum } from './fields.ts'
5
+
6
+ /** A shared enum, frozen, which `f.enumOf` takes in place of its values. */
7
+ export function defineEnum<const E extends string>(
8
+ name: string,
9
+ values: readonly E[],
10
+ options: { readonly description?: string } = {},
11
+ ): Enum<E> {
12
+ if (!/^[A-Z_a-z]\w*$/.test(name) || name.startsWith('__')) {
13
+ throw new Error(
14
+ `defineEnum takes a GraphQL name: letters, digits and _, not ${JSON.stringify(name)}.`,
15
+ )
16
+ }
17
+ const of = `defineEnum(${name})`
18
+ enumValues(values, of)
19
+ const shared: Enum<E> = Object.freeze({
20
+ name,
21
+ values: Object.freeze([...values]),
22
+ description: describedBy(options.description, of),
23
+ })
24
+ sharedEnums.set(shared, shared)
25
+ return shared
26
+ }
@@ -0,0 +1,188 @@
1
+ // `defineFunction` and `defineType` (D-27, D-109): a server operation, its
2
+ // access rule checked and its input validated on each `run` (D-75), and the
3
+ // named objects its output may hold.
4
+ import { refused } from './access.ts'
5
+ import type { FunctionDefinition, Output } from './definition.ts'
6
+ import {
7
+ describedBy,
8
+ functionDefinitions,
9
+ nameOf,
10
+ nullable,
11
+ outputOf,
12
+ typeDefinitions,
13
+ withOnce,
14
+ } from './definition.ts'
15
+ import { entriesOf } from './plugin-use.ts'
16
+ import { callerOf } from './engine.ts'
17
+ import { PublicError, Refused } from './errors.ts'
18
+ import type { StandardSchema } from './fields.ts'
19
+ import type {
20
+ Client,
21
+ FunctionPlugin,
22
+ FunctionWithKeys,
23
+ InputCheck,
24
+ ObjectType,
25
+ OutputSpec,
26
+ QueryCheck,
27
+ ResultOf,
28
+ RunFacts,
29
+ ServerFunction,
30
+ TypeFields,
31
+ } from './function.ts'
32
+ import type { ModelUse } from './plugin.ts'
33
+ import { isObject } from './query-where.ts'
34
+ import type { Caller } from './rules.ts'
35
+ import { isMaster } from './rules.ts'
36
+ import type { Running } from './running.ts'
37
+ import { current } from './running.ts'
38
+ import { checked, standardOf } from './validation.ts'
39
+
40
+ export function defineType<
41
+ const N extends string,
42
+ const F extends TypeFields,
43
+ >(definition: {
44
+ readonly name: N
45
+ /** What the type means, which the transports show (D-150). */
46
+ readonly description?: string
47
+ readonly fields: F
48
+ }): ObjectType<N, F> {
49
+ const { fields } = definition
50
+ const name = nameOf(definition.name, 'defineType')
51
+ const description = describedBy(definition.description, name)
52
+ if (!isObject(fields) || Object.keys(fields).length === 0) {
53
+ throw new Refused(`${name}: fields is an object of one output or more.`)
54
+ }
55
+ const outputs = new Map<string, Output>()
56
+ for (const [field, value] of Object.entries(fields)) {
57
+ outputs.set(field, outputOf(value, `${name}.${field}`))
58
+ }
59
+ const recorded = { name, description, fields: outputs }
60
+ const type: object = Object.freeze({
61
+ name,
62
+ nullable: (): object => nullable({ kind: 'type', type: recorded }),
63
+ })
64
+ typeDefinitions.set(type, recorded)
65
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- the value holds the name and `nullable`; its fields are a type only.
66
+ return type as ObjectType<N, F>
67
+ }
68
+
69
+ /** Closed to all but Master by default (D-04); the rule reads the caller. */
70
+ function allowed(
71
+ record: FunctionDefinition,
72
+ caller: Caller,
73
+ app: Running,
74
+ ): void {
75
+ if (isMaster(caller)) return
76
+ const rule = isObject(record.rules) ? record.rules['access'] : undefined
77
+ if (rule !== undefined && typeof rule !== 'function') {
78
+ throw new TypeError(`${record.name}: access is a function.`)
79
+ }
80
+ const result: unknown =
81
+ rule === undefined ? false : Reflect.apply(rule, undefined, [{ caller }])
82
+ if (typeof result !== 'boolean') {
83
+ throw new TypeError(`${record.name}: access returns a boolean.`)
84
+ }
85
+ if (result) return
86
+ const { name } = record
87
+ throw refused({ function: name }, `${name} refused.`, caller, app.logger)
88
+ }
89
+
90
+ /** `run`'s call, the input first when the function takes one; a transport
91
+ * passes its client (D-113). */
92
+ export async function called(
93
+ value: object,
94
+ record: FunctionDefinition,
95
+ args: readonly unknown[],
96
+ client?: Client,
97
+ ): Promise<unknown> {
98
+ const app = current()
99
+ if (app?.functions.get(value) !== record) {
100
+ throw new Error(
101
+ `${record.name} is not a function of a started application.`,
102
+ )
103
+ }
104
+ const { input: schema, name } = record
105
+ const [input, options] =
106
+ schema === undefined ? [undefined, args[0]] : [args[0], args[1]]
107
+ const identity = callerOf(options, name)
108
+ return app.work.run(async () => {
109
+ const caller = await app.complete(identity)
110
+ allowed(record, caller, app)
111
+ const facts: { [key: string]: unknown } = { caller, client }
112
+ const standard = standardOf(schema)
113
+ if (standard !== undefined) {
114
+ const result = await checked(standard, input, [], name)
115
+ if ('issues' in result) {
116
+ throw new PublicError('VALIDATION_FAILED', 'Invalid input.', {
117
+ details: { issues: result.issues },
118
+ })
119
+ }
120
+ facts['input'] = result.value
121
+ }
122
+ const output: unknown = await Reflect.apply(record.run, undefined, [
123
+ Object.freeze(facts),
124
+ ])
125
+ return record.output === undefined ? undefined : output
126
+ })
127
+ }
128
+
129
+ export function defineFunction<
130
+ const N extends string,
131
+ const O extends OutputSpec | undefined = undefined,
132
+ const I extends StandardSchema | undefined = undefined,
133
+ const U extends readonly ModelUse<string, FunctionPlugin>[] = [],
134
+ >(
135
+ definition: {
136
+ readonly name: N
137
+ /** What the function does, which the transports show (D-150). */
138
+ readonly description?: string
139
+ /** A query, served over GET too; a mutation by default (D-109). */
140
+ readonly query?: boolean
141
+ readonly use?: U
142
+ readonly input?: I
143
+ readonly output?: O
144
+ readonly run: (
145
+ facts: RunFacts<NoInfer<I>>,
146
+ ) => NoInfer<ResultOf<O>> | Promise<NoInfer<ResultOf<O>>>
147
+ } & NoInfer<InputCheck<I>> &
148
+ NoInfer<QueryCheck<U[number]>>,
149
+ ): ServerFunction<N, I, O, U[number]['plugin'], FunctionWithKeys<U[number]>> {
150
+ const { query = false, input, output, run } = definition
151
+ const name = nameOf(definition.name, 'defineFunction')
152
+ const description = describedBy(definition.description, name)
153
+ if (typeof query !== 'boolean')
154
+ throw new Refused(`${name}: query is a boolean.`)
155
+ if (input !== undefined && standardOf(input) === undefined) {
156
+ throw new Refused(`${name}: input is a Standard Schema.`)
157
+ }
158
+ if (typeof run !== 'function')
159
+ throw new Refused(`${name}: run is a function.`)
160
+ const record: FunctionDefinition = {
161
+ name,
162
+ description,
163
+ query,
164
+ input,
165
+ output:
166
+ output === undefined ? undefined : outputOf(output, `${name}.output`),
167
+ uses: entriesOf(name, definition.use ?? []),
168
+ run,
169
+ rules: undefined,
170
+ }
171
+ const fn: object = Object.freeze({
172
+ name,
173
+ input,
174
+ output,
175
+ with: withOnce(name, record, () => fn),
176
+ run: async (...args: unknown[]): Promise<unknown> =>
177
+ called(fn, record, args),
178
+ })
179
+ functionDefinitions.set(fn, record)
180
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- the value ServerFunction describes; its types follow the definition.
181
+ return fn as unknown as ServerFunction<
182
+ N,
183
+ I,
184
+ O,
185
+ U[number]['plugin'],
186
+ FunctionWithKeys<U[number]>
187
+ >
188
+ }
@@ -0,0 +1,220 @@
1
+ // `defineModel` (D-07, D-12): the fields its callback and its plugins build,
2
+ // recorded for `start`, and the model value whose methods run the queries
3
+ // (D-18) and its plugins' commands (D-89).
4
+ import {
5
+ describedBy,
6
+ fieldBuilders,
7
+ modelDefinitions,
8
+ nameOf,
9
+ nullable,
10
+ withOnce,
11
+ } from './definition.ts'
12
+ import type { FieldDefinition, ModelDefinition } from './definition.ts'
13
+ import { query } from './engine.ts'
14
+ import type { Operation } from './engine.ts'
15
+ import { addFields, usedBy } from './plugin-use.ts'
16
+ import type { FieldBuilders } from './fields.ts'
17
+ import type {
18
+ FieldShape,
19
+ IndexCheck,
20
+ IndexShape,
21
+ Model,
22
+ RecordCheck,
23
+ UniqueIndexFields,
24
+ } from './model.ts'
25
+ import type { ForModel, ModelUse, PluginTypes } from './plugin.ts'
26
+ import { Refused } from './errors.ts'
27
+
28
+ // The intersection of the used plugins' commands; `unknown` without any.
29
+ type CommandFn<U, F> =
30
+ U extends ModelUse<string, infer T>
31
+ ? T extends { readonly commands: object }
32
+ ? (value: ForModel<T, F>['commands']) => void
33
+ : never
34
+ : never
35
+ type Commands<U, F> = [CommandFn<U, F>] extends [never]
36
+ ? unknown
37
+ : CommandFn<U, F> extends (value: infer I) => void
38
+ ? I
39
+ : unknown
40
+
41
+ /** Each used plugin's key of `.with`, typed by the model's fields. */
42
+ type WithKeys<U, F> = {
43
+ readonly [
44
+ V in U as V extends ModelUse<infer P, infer T>
45
+ ? T extends { readonly with: object | false }
46
+ ? P
47
+ : never
48
+ : never
49
+ ]?: V extends ModelUse<
50
+ string,
51
+ infer T extends { readonly with: object | false }
52
+ >
53
+ ? ForModel<T, F>['with']
54
+ : never
55
+ }
56
+
57
+ /** The types of the plugins in a model's `use`. */
58
+ type UsedTypes<U> = U extends ModelUse<string, infer T> ? T : never
59
+
60
+ // The fields the used plugins add, merged with the model's own.
61
+ type AddFn<U> =
62
+ U extends ModelUse<string, infer T>
63
+ ? T extends { readonly addedFields: infer A }
64
+ ? (value: A) => void
65
+ : never
66
+ : never
67
+ type Added<U> = [AddFn<U>] extends [never]
68
+ ? unknown
69
+ : AddFn<U> extends (value: infer I) => void
70
+ ? I
71
+ : unknown
72
+ type AllFields<F, U> = [Added<U>] extends [unknown]
73
+ ? unknown extends Added<U>
74
+ ? F
75
+ : F & Added<U>
76
+ : F & Added<U>
77
+
78
+ /** A model's fields, as `fields` returns them. */
79
+ export type FieldShapes = { readonly [field: string]: FieldShape }
80
+
81
+ /** The `fields` callback: its builders know the plugins of `use` (D-12, D-57). */
82
+ export type ModelFields<
83
+ F,
84
+ U extends readonly ModelUse<string, PluginTypes>[],
85
+ > = (fields: FieldBuilders<UsedTypes<U[number]>>) => F & NoInfer<RecordCheck<F>>
86
+
87
+ /**
88
+ * The model a declaration with these fields and plugins builds; a plugin's
89
+ * `define<Kind>` returns it with its own entry in `U` (D-13).
90
+ */
91
+ export type ModelOf<
92
+ N extends string,
93
+ F,
94
+ U extends readonly ModelUse<string, PluginTypes>[],
95
+ X extends readonly IndexShape[] = [],
96
+ > = Model<
97
+ N,
98
+ AllFields<F, U[number]>,
99
+ U[number]['plugin'],
100
+ WithKeys<U[number], AllFields<F, U[number]>>,
101
+ UniqueIndexFields<X>
102
+ > &
103
+ Commands<U[number], AllFields<F, U[number]>>
104
+
105
+ /** `indexes`, whose fields are checked against the model's (D-52). */
106
+ export type ModelIndexes<
107
+ X,
108
+ F,
109
+ U extends readonly ModelUse<string, PluginTypes>[],
110
+ > = X & NoInfer<IndexCheck<X, AllFields<F, U[number]>>>
111
+
112
+ export function defineModel<
113
+ const N extends string,
114
+ const F extends FieldShapes,
115
+ const U extends readonly ModelUse<string, PluginTypes>[] = [],
116
+ const X extends readonly IndexShape[] = [],
117
+ >(definition: {
118
+ readonly name: N
119
+ /** What the model means, which the transports show (D-150). */
120
+ readonly description?: string
121
+ /** The stored table's or collection's name (D-63). */
122
+ readonly dbName?: string
123
+ readonly use?: U
124
+ /** The only form (D-12). */
125
+ readonly fields: ModelFields<F, U>
126
+ readonly indexes?: ModelIndexes<X, F, U>
127
+ }): ModelOf<N, F, U, X> {
128
+ const model = createModel({
129
+ name: definition.name,
130
+ description: definition.description,
131
+ dbName: definition.dbName,
132
+ use: definition.use ?? [],
133
+ fields: definition.fields,
134
+ indexes: definition.indexes ?? [],
135
+ })
136
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- createModel builds the value ModelOf describes; the types follow the definition.
137
+ return model as unknown as ModelOf<N, F, U, X>
138
+ }
139
+
140
+ const operations: readonly Operation[] = [
141
+ 'findMany',
142
+ 'findFirst',
143
+ 'findUnique',
144
+ 'findFirstOrThrow',
145
+ 'findUniqueOrThrow',
146
+ 'count',
147
+ 'aggregate',
148
+ 'groupBy',
149
+ 'create',
150
+ 'update',
151
+ 'upsert',
152
+ 'delete',
153
+ 'updateMany',
154
+ 'createMany',
155
+ 'updateManyAndReturn',
156
+ 'createManyAndReturn',
157
+ 'deleteMany',
158
+ ]
159
+
160
+ function createModel(definition: {
161
+ readonly name: unknown
162
+ readonly description: unknown
163
+ readonly dbName: unknown
164
+ readonly use: readonly unknown[]
165
+ readonly fields: Function
166
+ readonly indexes: readonly IndexShape[]
167
+ }): object {
168
+ const { dbName } = definition
169
+ const name = nameOf(definition.name, 'defineModel')
170
+ if (dbName !== undefined && typeof dbName !== 'string') {
171
+ throw new Refused(`${name}: dbName must be a string.`)
172
+ }
173
+ const description = describedBy(definition.description, name)
174
+ const built: unknown = Reflect.apply(definition.fields, undefined, [
175
+ fieldBuilders,
176
+ ])
177
+ const fields = new Map<string, FieldDefinition>()
178
+ addFields(name, built, fields, new Map())
179
+ const queries: { [operation: string]: unknown } = {}
180
+ for (const operation of operations) {
181
+ queries[operation] = async (args?: unknown, options?: unknown) =>
182
+ query(name, operation, args, options)
183
+ }
184
+ Object.freeze(queries)
185
+ const { uses, commands, indexes } = usedBy(
186
+ name,
187
+ definition.use,
188
+ fields,
189
+ queries,
190
+ )
191
+ const record: ModelDefinition = {
192
+ name,
193
+ description,
194
+ dbName,
195
+ fields,
196
+ indexes: [
197
+ ...definition.indexes.map((index) => ({
198
+ fields: [...index.fields],
199
+ ...(index.unique === undefined ? {} : { unique: index.unique }),
200
+ ...(index.contains === undefined ? {} : { contains: index.contains }),
201
+ })),
202
+ // A plugin's, checked with the model's at startup (D-122).
203
+ ...indexes,
204
+ ],
205
+ uses,
206
+ queries,
207
+ rules: undefined,
208
+ }
209
+ const model: { [key: string]: unknown } = {
210
+ name,
211
+ ...queries,
212
+ ...Object.fromEntries(commands),
213
+ }
214
+ model['with'] = withOnce(name, record, () => frozen)
215
+ model['nullable'] = (): object =>
216
+ nullable({ kind: 'model', value: frozen, name })
217
+ const frozen = Object.freeze(model)
218
+ modelDefinitions.set(frozen, record)
219
+ return frozen
220
+ }