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
package/dist/writes.js ADDED
@@ -0,0 +1,246 @@
1
+ // `create`, `update` and `delete` in the order of D-67: access rules on the
2
+ // data sent, defaults, validation, `before*` hooks, the required check, the
3
+ // write, which a plugin's `redirect` may replace (D-89), `after*` hooks; the
4
+ // `*Commit` hooks once it commits (D-71, D-88). The row a write decides from
5
+ // is locked; a write that loads none answers from the rows it changed (D-99,
6
+ // D-104).
7
+ import { and, recordOf } from './access.js';
8
+ import { cascadeWhere } from './cascade.js';
9
+ import { deleted } from './delete-many.js';
10
+ import { PublicError } from './errors.js';
11
+ import { redirectOf, rereads, runHook, settle, settles } from './hooks.js';
12
+ import { first, given, hiddenBy, picked } from './query-context.js';
13
+ import { project } from './query-project.js';
14
+ import { computeVirtuals } from './virtual-read.js';
15
+ import { oneKeys, plan, uniqueWhere } from './query-args.js';
16
+ import { computeOn, operationsOf, inRange, validates } from './number-update.js';
17
+ import { nests, resolveData } from './nested-write.js';
18
+ import { createPlan, updatePlan } from './query-write.js';
19
+ import { planned } from './scope.js';
20
+ import { prepared, readData } from './write-data.js';
21
+ import { updated } from './write-plan.js';
22
+ import { uuidv7 } from './uuid.js';
23
+ import { guarded, target } from './write-target.js';
24
+ import { writingOf } from './writing.js';
25
+ import { byId } from './query-where.js';
26
+ /** The shape a single-row write returns, and each row of a bulk one's (D-149). */
27
+ export async function returned(context, found) {
28
+ const { models, model, scope } = context;
29
+ return planned(scope, () => plan(models, model, picked(found), '', 'one', oneKeys, scope));
30
+ }
31
+ /**
32
+ * Runs the plan, then the `after*` hooks. The written row comes back even
33
+ * when a read rule or `beforeFind` would hide it (D-86, D-88).
34
+ */
35
+ async function written(context, store, commits, steps, events, at, checks = []) {
36
+ const { model, scope } = context;
37
+ const writing = writingOf(scope, store, events, checks);
38
+ // The rows it creates, after the row written, before the rows it moves.
39
+ events.push(...steps.events);
40
+ await steps.check(writing);
41
+ const changes = await steps.changes(writing);
42
+ const read = { model: model.name, ...at.read, where: byId(at.id) };
43
+ const again = rereads(events);
44
+ const write = {
45
+ checks: checks.map(({ check }) => check),
46
+ changes,
47
+ ...(again ? {} : { read }),
48
+ };
49
+ // Nothing follows a write without hooks: it may need no transaction.
50
+ const run = settles(events) ? store.write(write) : store.last(write);
51
+ const rows = await guarded(run, checks);
52
+ await settle(store, scope.caller, events, commits);
53
+ // An `after*` hook may have changed the rows: read them again (D-88).
54
+ const result = again ? await store.find(read) : rows;
55
+ return first(context, store, result, at.shape, scope.access);
56
+ }
57
+ /** Creates the row of `draft` as the rules allow. */
58
+ async function creating(context, store, commits, draft, at) {
59
+ const { model, caller, scope } = context;
60
+ const { read, shape } = at;
61
+ const made = uuidv7();
62
+ const reach = { scope, reads: store, model, id: made, at: [] };
63
+ await resolveData({ ...reach, creating: true, trusted: false }, draft);
64
+ const sent = { ...draft };
65
+ scope.access?.allow(model, 'create', { data: sent });
66
+ await prepared(model, draft, caller, true);
67
+ await runHook(model, 'beforeCreate', { caller, data: draft });
68
+ const { id, plan: steps } = await createPlan(scope, model, draft, sent, store, made);
69
+ const events = [{ model, operation: 'create', id }];
70
+ return written(context, store, commits, steps, events, { id, read, shape });
71
+ }
72
+ export async function create(context, store, commits, args) {
73
+ const { models, model } = context;
74
+ const found = given(args, model.name, ['data', ...oneKeys], ['data']);
75
+ const at = await returned(context, found);
76
+ const draft = readData(models, model, found.get('data'), true);
77
+ return creating(context, store, commits, draft, at);
78
+ }
79
+ /**
80
+ * The rows a single-row write may target: the caller reads them (D-72), and
81
+ * the `beforeFind` hooks let it `operation` them (D-124).
82
+ */
83
+ async function targets(context, found, operation) {
84
+ const { models, model, scope } = context;
85
+ return planned(scope, () => and(uniqueWhere(models, model, found.get('where'), 'where', scope), scope.readable(model.name, operation)));
86
+ }
87
+ const missing = (model) => `No ${model} matches.`;
88
+ /** The `id` a unique `where` gives, if any. */
89
+ function idOf(where) {
90
+ if (typeof where !== 'object' || where === null || !('id' in where)) {
91
+ return undefined;
92
+ }
93
+ return typeof where.id === 'string' ? where.id : undefined;
94
+ }
95
+ /**
96
+ * Updates the locked `row` as the rules allow; its number and list updates
97
+ * are computed on it first, so the rules and hooks see the results (D-132,
98
+ * D-149).
99
+ */
100
+ async function updating(context, store, commits, data, at) {
101
+ const { model, caller, scope } = context;
102
+ const { row, read, shape } = at;
103
+ const { draft, operations } = data;
104
+ computeOn(model, row, draft, operations);
105
+ const reach = { scope, reads: store, model, id: row.id, at: [] };
106
+ await resolveData({ ...reach, creating: false, trusted: false }, draft);
107
+ const sent = { ...draft };
108
+ scope.access?.allow(model, 'update', { record: row, data: sent });
109
+ await prepared(model, draft, caller, false);
110
+ const record = recordOf(model, row);
111
+ await runHook(model, 'beforeUpdate', { caller, record, data: draft });
112
+ const steps = await updatePlan(scope, model, row.id, draft, sent, store);
113
+ const events = [
114
+ { model, operation: 'update', id: row.id, before: row },
115
+ ];
116
+ const to = { id: row.id, read, shape };
117
+ return written(context, store, commits, steps, events, to);
118
+ }
119
+ export async function update(context, store, commits, args) {
120
+ const { models, model, caller, scope } = context;
121
+ const found = given(args, model.name, ['where', 'data', ...oneKeys], ['where', 'data']);
122
+ const { read, shape } = await returned(context, found);
123
+ // The data's shape is checked whether or not the row is found.
124
+ const draft = readData(models, model, found.get('data'), false);
125
+ const operations = operationsOf(model, draft);
126
+ const id = idOf(found.get('where'));
127
+ const where = await targets(context, found, 'update');
128
+ if (scope.access === undefined &&
129
+ id !== undefined &&
130
+ !updated(model) &&
131
+ !nests(model, draft) &&
132
+ !validates(model, operations)) {
133
+ // Nothing needs the stored row: a check stands for its read (D-99),
134
+ // and the write computes its numbers and lists (D-132, D-149).
135
+ const sent = { ...draft };
136
+ await prepared(model, draft, caller, false);
137
+ const steps = await updatePlan(scope, model, id, draft, sent, store, operations);
138
+ const check = { model: model.name, where, count: 1, lock: true };
139
+ const message = missing(model.name);
140
+ const at = { id, read, shape };
141
+ const checks = [{ check, message }];
142
+ const result = await inRange(model, written(context, store, commits, steps, [], at, checks));
143
+ // The row went between the write's check and its change (D-104).
144
+ if (result === null)
145
+ throw new PublicError('NOT_FOUND', message);
146
+ return result;
147
+ }
148
+ const row = await target(context, store, where);
149
+ const data = { draft, operations };
150
+ return updating(context, store, commits, data, { row, read, shape });
151
+ }
152
+ export async function remove(context, store, commits, args) {
153
+ const { models, model, scope } = context;
154
+ const found = given(args, model.name, ['where', ...oneKeys], ['where']);
155
+ const { read, shape } = await returned(context, found);
156
+ const where = await targets(context, found, 'delete');
157
+ // Its relations, counts and virtuals, as the caller reads them, before
158
+ // the delete removes any: one read in its transaction (D-135, D-151).
159
+ const reaches = shape.relations.size > 0 ||
160
+ shape.counts.length > 0 ||
161
+ shape.virtuals.size > 0;
162
+ const shaped = async (by, lock) => {
163
+ if (!reaches)
164
+ return undefined;
165
+ const rows = await store.find({
166
+ model: model.name,
167
+ ...read,
168
+ where: by,
169
+ take: 1,
170
+ lock,
171
+ });
172
+ return rows[0];
173
+ };
174
+ const reach = cascadeWhere(models, model, where);
175
+ if (reach !== undefined && scope.access === undefined) {
176
+ const kept = await shaped(where, true);
177
+ const computed = await computeVirtuals(context, store, kept === undefined ? [] : [kept], shape, undefined);
178
+ // Nothing needs the stored row: a check stands for its read, and the
179
+ // write returns it as its delete removed it (D-102, D-104).
180
+ const check = { model: model.name, where, count: 1, lock: true };
181
+ const checks = [{ check, message: missing(model.name) }];
182
+ checks.push(...reach.checks);
183
+ const rows = await guarded(store.last({
184
+ checks: checks.map((each) => each.check),
185
+ changes: reach.changes,
186
+ read: { model: model.name, where, take: 1 },
187
+ before: true,
188
+ }), checks);
189
+ // Another transaction removed it meanwhile (D-104).
190
+ if (rows.length === 0)
191
+ throw new PublicError('NOT_FOUND', missing(model.name));
192
+ return project(kept ?? rows[0], shape, undefined, computed);
193
+ }
194
+ const row = await target(context, store, where);
195
+ scope.access?.allow(model, 'delete', { record: row });
196
+ const redirected = redirectOf(model) !== undefined;
197
+ // A redirected row stays: it is read as the redirect left it (D-89).
198
+ const kept = redirected ? undefined : await shaped(byId(row.id), false);
199
+ const hidden = hiddenBy(scope.access);
200
+ const before = redirected
201
+ ? undefined
202
+ : await computeVirtuals(context, store, [kept ?? row], shape, hidden);
203
+ await deleted(context, store, commits, [row]);
204
+ // The row as the redirect left it, or as it was once gone (D-89).
205
+ const [left] = redirected
206
+ ? await store.find({
207
+ model: model.name,
208
+ ...read,
209
+ where: byId(row.id),
210
+ take: 1,
211
+ })
212
+ : [kept];
213
+ const result = left ?? row;
214
+ const computed = before ?? (await computeVirtuals(context, store, [result], shape, hidden));
215
+ return project(result, shape, hidden, computed);
216
+ }
217
+ /**
218
+ * Updates the row `where` targets, or creates it when the caller finds
219
+ * none: the branch that runs is a plain update or create (D-142).
220
+ */
221
+ export async function upsert(context, store, commits, args) {
222
+ const { models, model } = context;
223
+ const found = given(args, model.name, ['where', 'create', 'update', ...oneKeys], ['where', 'create', 'update']);
224
+ const at = await returned(context, found);
225
+ // Both data are checked, whichever runs.
226
+ const creation = readData(models, model, found.get('create'), true);
227
+ const draft = readData(models, model, found.get('update'), false);
228
+ const operations = operationsOf(model, draft);
229
+ const where = await targets(context, found, 'update');
230
+ const [row] = await store.find({
231
+ model: model.name,
232
+ where,
233
+ take: 1,
234
+ lock: true,
235
+ });
236
+ // Another create of the row meanwhile fails on its unique index.
237
+ if (row === undefined) {
238
+ return {
239
+ row: await creating(context, store, commits, creation, at),
240
+ created: true,
241
+ };
242
+ }
243
+ const data = { draft, operations };
244
+ const changed = await updating(context, store, commits, data, { row, ...at });
245
+ return { row: changed, created: false };
246
+ }
@@ -0,0 +1,10 @@
1
+ import type { Change } from './adapter.ts';
2
+ import type { Cascade } from './cascade.ts';
3
+ import type { Event } from './hooks.ts';
4
+ import type { QueryScope } from './scope.ts';
5
+ import type { Store } from './transaction.ts';
6
+ import type { Checked, Writing } from './write-plan.ts';
7
+ /** The changes and events of a delete's cascade, its hooks run (D-90). */
8
+ export declare function cascaded(writing: Writing, cascade: Cascade): Promise<Change[]>;
9
+ export declare function writingOf(scope: QueryScope, store: Store, events: Event[], checks?: Checked[]): Writing;
10
+ //# sourceMappingURL=writing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writing.d.ts","sourceRoot":"","sources":["../src/writing.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAG3C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAGvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAC5C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAQ,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAI7D,0EAA0E;AAC1E,wBAAsB,QAAQ,CAC7B,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,GACd,OAAO,CAAC,MAAM,EAAE,CAAC,CA2BnB;AA4BD,wBAAgB,SAAS,CACxB,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,KAAK,EAAE,EACf,MAAM,GAAE,OAAO,EAAO,GACpB,OAAO,CAWT"}
@@ -0,0 +1,66 @@
1
+ // What one write's changes are made in (write-plan.ts): the rows a move's
2
+ // hooks update planned again, and deletes run with their cascade and hooks
3
+ // (D-88, D-90, D-138).
4
+ import { recordOf } from './access.js';
5
+ import { cascadeOf } from './cascade.js';
6
+ import { InvalidQuery } from './errors.js';
7
+ import { redirectOf, runHook } from './hooks.js';
8
+ import { updatePlan } from './query-write.js';
9
+ import { moved } from './write-plan.js';
10
+ import { modelOf } from './query-where.js';
11
+ /** The changes and events of a delete's cascade, its hooks run (D-90). */
12
+ export async function cascaded(writing, cascade) {
13
+ const { caller } = writing.scope;
14
+ const changes = [];
15
+ for (const { model, field, rows } of cascade.nulled) {
16
+ const step = { model: model.name, field, to: null };
17
+ changes.push(...(await moved(step, model, rows, writing)));
18
+ }
19
+ for (const { model, row } of cascade.deleted) {
20
+ await runHook(model, 'beforeDelete', {
21
+ caller,
22
+ record: recordOf(model, row),
23
+ });
24
+ }
25
+ const ids = new Map();
26
+ for (const { model, row, redirected } of cascade.deleted) {
27
+ const redirect = redirected ? redirectOf(model) : undefined;
28
+ // Its queries run their own pipeline, in this transaction (D-89).
29
+ if (redirect !== undefined)
30
+ await redirect(caller, row.id);
31
+ else
32
+ ids.set(model.name, [...(ids.get(model.name) ?? []), row.id]);
33
+ }
34
+ for (const [model, deleted] of ids) {
35
+ changes.push({ kind: 'delete', model, where: { id: { in: deleted } } });
36
+ }
37
+ for (const { model, row } of cascade.deleted) {
38
+ writing.events.push({ model, operation: 'delete', id: row.id, before: row });
39
+ }
40
+ return changes;
41
+ }
42
+ /**
43
+ * A nested delete as `Target.delete` runs it: a plugin's redirect, or the
44
+ * cascade, which may not reach a row the write updates (D-138).
45
+ */
46
+ async function dropped(writing, step) {
47
+ const { scope, store } = writing;
48
+ const model = modelOf(scope.models, step.model);
49
+ const cascade = await cascadeOf(scope.models, model, step.rows, store, step.except);
50
+ const reached = cascade.deleted.some(({ model: from, row }) => step.written.has(`${from.name}:${row.id}`));
51
+ if (reached) {
52
+ throw new InvalidQuery(step.path, `${step.path} deletes a row the write updates.`);
53
+ }
54
+ return cascaded(writing, cascade);
55
+ }
56
+ export function writingOf(scope, store, events, checks = []) {
57
+ const writing = {
58
+ store,
59
+ scope,
60
+ events,
61
+ checks,
62
+ replan: async (model, id, draft) => updatePlan(scope, model, id, draft, {}, store),
63
+ drop: async (step) => dropped(writing, step),
64
+ };
65
+ return writing;
66
+ }
package/package.json CHANGED
@@ -1,6 +1,45 @@
1
1
  {
2
2
  "name": "ultimabase",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.0",
4
+ "description": "The UltimaBase kernel and its in-memory adapter.",
5
+ "type": "module",
6
+ "license": "Apache-2.0",
7
+ "homepage": "https://ultimabase.dev",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/MrEkinox/ultimabase.git",
11
+ "directory": "packages/ultimabase"
12
+ },
13
+ "engines": {
14
+ "node": ">=24.7.0"
15
+ },
16
+ "bin": "./dist/cli.js",
17
+ "exports": {
18
+ ".": "./dist/index.js",
19
+ "./internal": "./dist/internal.js"
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "src",
24
+ "!src/**/*.test.ts",
25
+ "!src/test"
26
+ ],
27
+ "scripts": {
28
+ "prepack": "rm -rf dist && yarn run -T tsc --project tsconfig.build.json"
29
+ },
30
+ "publishConfig": {
31
+ "bin": "./dist/cli.js",
32
+ "exports": {
33
+ ".": "./dist/index.js",
34
+ "./internal": "./dist/internal.js"
35
+ }
36
+ },
37
+ "dependencies": {
38
+ "semver": "7.8.5"
39
+ },
40
+ "devDependencies": {
41
+ "@ultimabase/testing": "0.1.0",
42
+ "vite": "8.3.4",
43
+ "vitest": "5.0.5"
44
+ }
6
45
  }