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,200 @@
1
+ import { storedValue } from './decimal.js';
2
+ import { InvalidQuery } from './errors.js';
3
+ import { listCondition } from './query-conditions.js';
4
+ import { isPathFilter, jsonCondition } from './query-json.js';
5
+ import { searchedFields } from './query-search.js';
6
+ import { clean, cleanText, entries, isObject, misfit, storedDate, unknownKey, } from './query-values.js';
7
+ export { clean, entries, integerRange, isInteger, isJson, isObject, misfit, storedDate, unknownKey, } from './query-values.js';
8
+ /** The model, or the table, of `name`; another name is a kernel bug. */
9
+ export function modelOf(models, name) {
10
+ const model = models.get(name);
11
+ if (model === undefined)
12
+ throw new Error(`Unknown model ${name}.`);
13
+ return model;
14
+ }
15
+ export const byId = (id) => ({ id: { equals: id } });
16
+ export const byIds = (ids) => ({ id: { in: ids } });
17
+ /** `id`, `createdAt` and `updatedAt`, which every model has (D-22). */
18
+ const system = new Map([
19
+ ['id', 'id'],
20
+ ['createdAt', 'dateTime'],
21
+ ['updatedAt', 'dateTime'],
22
+ ]);
23
+ export const systemFields = [...system.keys()];
24
+ function typeOf(model, name) {
25
+ const field = model.fields.get(name);
26
+ return field?.kind === 'scalar' ? field.type : system.get(name);
27
+ }
28
+ /** Whether `value` fits a field, or a system field, which has no info (D-22). */
29
+ const fits = (type, value, field) => field?.kind === 'scalar'
30
+ ? misfit(value, field) === undefined
31
+ : type === 'dateTime'
32
+ ? storedDate(value)
33
+ : typeof value === 'string' && clean(value);
34
+ const base = new Set(['equals', 'not', 'in', 'notIn']);
35
+ const ordered = new Set(['lt', 'lte', 'gt', 'gte']);
36
+ const text = new Set(['contains', 'startsWith', 'endsWith']);
37
+ function operators(type) {
38
+ if (type === 'number' ||
39
+ type === 'decimal' ||
40
+ type === 'dateTime' ||
41
+ type === 'date')
42
+ return new Set([...base, ...ordered]);
43
+ if (type === 'string')
44
+ return new Set([...base, ...text, 'mode']);
45
+ if (type === 'id' || type === 'enum')
46
+ return new Set([...base, ...text]);
47
+ return base;
48
+ }
49
+ function scalarCondition(model, name, type, value, path, other) {
50
+ const field = model.fields.get(name);
51
+ const fit = (item, at) => {
52
+ if (!fits(type, item, field)) {
53
+ throw new InvalidQuery(at, `${at} does not fit ${model.name}.${name}.`);
54
+ }
55
+ return field?.kind === 'scalar' ? storedValue(item, field) : item;
56
+ };
57
+ const check = (item, at, nullable) => item === null && nullable ? null : (other ?? fit)(item, at);
58
+ // A primitive, a `Date` or a list is `equals`; an object is a filter, on
59
+ // `json` too, which compares whole values with `equals` as in Prisma.
60
+ if (value === null || !isObject(value)) {
61
+ return { equals: check(value, path, true) };
62
+ }
63
+ const allowed = operators(type);
64
+ const condition = {};
65
+ let insensitive = false;
66
+ for (const [operator, operand] of entries(value, path)) {
67
+ const at = `${path}.${operator}`;
68
+ if (!allowed.has(operator))
69
+ throw unknownKey(at, model.name);
70
+ if (operator === 'in' || operator === 'notIn') {
71
+ if (!Array.isArray(operand)) {
72
+ throw new InvalidQuery(at, `${at} must be a list.`);
73
+ }
74
+ condition[operator] = operand.map((item, index) => check(item, `${at}.${index}`, false));
75
+ }
76
+ else if (operator === 'mode') {
77
+ if (operand !== 'insensitive') {
78
+ throw new InvalidQuery(at, `${at} must be 'insensitive'.`);
79
+ }
80
+ insensitive = true;
81
+ }
82
+ else if (text.has(operator)) {
83
+ condition[operator] = cleanText(operand, at);
84
+ }
85
+ else {
86
+ condition[operator] = check(operand, at, base.has(operator));
87
+ }
88
+ }
89
+ // `mode` alone filters nothing, as in Prisma (D-140).
90
+ if (Object.keys(condition).length === 0)
91
+ return undefined;
92
+ return insensitive ? { ...condition, mode: 'insensitive' } : condition;
93
+ }
94
+ /** A scalar field's condition, or with `operand` another value's of it. */
95
+ export function fieldCondition(model, name, value, path, operand) {
96
+ const type = operand?.type ?? typeOf(model, name);
97
+ if (type === undefined)
98
+ throw unknownKey(path, model.name);
99
+ return scalarCondition(model, name, type, value, path, operand?.check);
100
+ }
101
+ /**
102
+ * A relation operator that sees readable targets only (D-86): an unreadable
103
+ * row is absent, so `is: null` holds when the target is unreadable.
104
+ */
105
+ function restricted(operator, inner, readable) {
106
+ if (inner === null) {
107
+ return operator === 'is' ? { isNot: readable } : { is: readable };
108
+ }
109
+ if (operator === 'every') {
110
+ return { every: { OR: [{ NOT: [readable] }, inner] } };
111
+ }
112
+ return { [operator]: { AND: [readable, inner] } };
113
+ }
114
+ function relationFilters(models, model, field, value, path, scope) {
115
+ const target = modelOf(models, field.target);
116
+ const readable = field.kind === 'one'
117
+ ? scope?.readable(field.target)
118
+ : scope?.related(model, field);
119
+ const allowed = field.kind === 'one' ? ['is', 'isNot'] : ['some', 'every', 'none'];
120
+ const filters = [];
121
+ for (const [operator, operand] of entries(value, path)) {
122
+ const at = `${path}.${operator}`;
123
+ if (!allowed.includes(operator))
124
+ throw unknownKey(at, model.name);
125
+ const inner = operand === null && field.kind === 'one'
126
+ ? null
127
+ : normalizeWhere(models, target, operand, at, scope);
128
+ filters.push({
129
+ [field.name]: readable === undefined
130
+ ? { [operator]: inner }
131
+ : restricted(operator, inner, readable),
132
+ });
133
+ }
134
+ return filters;
135
+ }
136
+ function list(models, model, value, path, single, scope, stored) {
137
+ if (Array.isArray(value)) {
138
+ return value.map((item, index) => normalizeWhere(models, model, item, `${path}.${index}`, scope, stored));
139
+ }
140
+ if (single)
141
+ return [normalizeWhere(models, model, value, path, scope, stored)];
142
+ throw new InvalidQuery(path, `${path} must be a list.`);
143
+ }
144
+ /**
145
+ * A `where` of `model`, normalized; `path` names it in errors. With a
146
+ * `scope`, relation filters see readable rows only (D-86). Only a
147
+ * `beforeFind`'s, `stored`, filters a plugin field, in its stored form
148
+ * (D-122).
149
+ */
150
+ export function normalizeWhere(models, model, where, path, scope, stored = false) {
151
+ const filter = {};
152
+ const relations = [];
153
+ for (const [key, value] of entries(where, path)) {
154
+ const at = `${path}.${key}`;
155
+ if (key === 'AND' || key === 'NOT' || key === 'OR') {
156
+ filter[key] = list(models, model, value, at, key !== 'OR', scope, stored);
157
+ continue;
158
+ }
159
+ if (key === '_search' && searchedFields(model.fields.values()).length > 0) {
160
+ if (value !== undefined)
161
+ filter[key] = { search: cleanText(value, at) };
162
+ continue;
163
+ }
164
+ const field = model.fields.get(key);
165
+ const type = typeOf(model, key);
166
+ if (field === undefined && type === undefined) {
167
+ throw unknownKey(at, model.name);
168
+ }
169
+ const codec = field?.kind === 'scalar' ? field.codec : undefined;
170
+ if (codec !== undefined && !stored) {
171
+ throw new InvalidQuery(at, `${at}: ${model.name}.${key} is a ${codec.plugin} field, which only a beforeFind filters.`);
172
+ }
173
+ scope?.check(model, key, at, 'filters');
174
+ if (field !== undefined && field.kind !== 'scalar') {
175
+ relations.push(...relationFilters(models, model, field, value, at, scope));
176
+ continue;
177
+ }
178
+ const condition = type === undefined
179
+ ? undefined
180
+ : field?.kind === 'scalar' && field.list
181
+ ? listCondition(model, field, value, at)
182
+ : type === 'json' && isPathFilter(value)
183
+ ? jsonCondition(model.name, value, at)
184
+ : scalarCondition(model, key, type, value, at);
185
+ if (condition !== undefined)
186
+ filter[key] = condition;
187
+ }
188
+ const [only, ...others] = relations;
189
+ if (only === undefined)
190
+ return filter;
191
+ // One relation filter stays in place; more join `AND`.
192
+ if (others.length === 0 && filter['AND'] === undefined) {
193
+ return { ...filter, ...only };
194
+ }
195
+ const and = filter['AND'];
196
+ return {
197
+ ...filter,
198
+ AND: [...(Array.isArray(and) ? and : []), ...relations],
199
+ };
200
+ }
@@ -0,0 +1,14 @@
1
+ import type { Operations } from './number-update.ts';
2
+ import type { ModelInfo } from './schema.ts';
3
+ import type { QueryScope } from './scope.ts';
4
+ import type { Draft } from './write-data.ts';
5
+ import type { Reads } from './write-plan.ts';
6
+ import { Plan } from './write-plan.ts';
7
+ /** `create`'s changes: the row with its id and timestamps (D-22). */
8
+ export declare function createPlan(scope: QueryScope, model: ModelInfo, draft: Draft, sent: Readonly<Draft>, reads: Reads, id?: string): Promise<{
9
+ readonly id: string;
10
+ readonly plan: Plan;
11
+ }>;
12
+ /** `update`'s changes on the stored row. */
13
+ export declare function updatePlan(scope: QueryScope, model: ModelInfo, id: string, draft: Draft, sent: Readonly<Draft>, reads: Reads, operations?: Operations): Promise<Plan>;
14
+ //# sourceMappingURL=query-write.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-write.d.ts","sourceRoot":"","sources":["../src/query-write.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AACpD,OAAO,KAAK,EAAa,SAAS,EAAE,MAAM,aAAa,CAAA;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAc5C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAE5C,OAAO,KAAK,EAAE,KAAK,EAAQ,MAAM,iBAAiB,CAAA;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AA+StC,qEAAqE;AACrE,wBAAsB,UAAU,CAC/B,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,EACrB,KAAK,EAAE,KAAK,EACZ,EAAE,GAAE,MAAiB,GACnB,OAAO,CAAC;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;CAAE,CAAC,CAIvD;AAED,4CAA4C;AAC5C,wBAAsB,UAAU,CAC/B,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE,SAAS,EAChB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,EACrB,KAAK,EAAE,KAAK,EACZ,UAAU,GAAE,UAAsB,GAChC,OAAO,CAAC,IAAI,CAAC,CAIf"}
@@ -0,0 +1,260 @@
1
+ // A write's data after its `before*` hooks, turned into the adapter's
2
+ // changes: values and relation writes by id, from either side (D-20, D-78),
3
+ // and the rows its relation writes create, update and delete (D-128, D-138).
4
+ // The caller's data was checked before the hooks (write-data.ts): what fails
5
+ // here is a hook's or a default's value (D-88).
6
+ import { recordOf } from './access.js';
7
+ import { InvalidQuery } from './errors.js';
8
+ import { runHook } from './hooks.js';
9
+ import { resolveData, resolveMany, resolveOne } from './nested-write.js';
10
+ import { madeId, uuidv7 } from './uuid.js';
11
+ import { byId, entries, modelOf, unknownKey } from './query-where.js';
12
+ import { fail, holds, linking, pathOf, resolving, scalar, trusted, viaOf, } from './write-context.js';
13
+ import { prepared, readData } from './write-data.js';
14
+ import { Plan } from './write-plan.js';
15
+ /**
16
+ * A row a relation write creates, as `Target.create` creates it (D-128):
17
+ * its access rules unless a hook or a default wrote it, its defaults, its
18
+ * validation and `beforeCreate`, then its own relation writes.
19
+ */
20
+ async function created(context, field, data, at, skips) {
21
+ const { scope, plan } = context;
22
+ const model = modelOf(context.scope.models, field.target);
23
+ const made = madeId(data);
24
+ // A hook's data may come back in another write: it gets a fresh id.
25
+ const id = skips || plan.made.has(made) ? uuidv7() : made;
26
+ const path = ['data', ...at].join('.');
27
+ const draft = readData(scope.models, model, data, true, path, field.inverse);
28
+ const inverse = model.fields.get(field.inverse);
29
+ if (inverse?.kind === 'one' && inverse.stored) {
30
+ draft[field.inverse] = { connect: { id: context.id } };
31
+ }
32
+ const child = { ...context, model, id, set: {}, at };
33
+ await resolveData(resolving(child, skips, true), draft);
34
+ const sent = skips ? {} : { ...draft };
35
+ if (!skips)
36
+ scope.access?.allow(model, 'create', { data: sent });
37
+ await prepared(model, draft, scope.caller, true, at);
38
+ await runHook(model, 'beforeCreate', { caller: scope.caller, data: draft });
39
+ plan.events.push({ model, operation: 'create', id });
40
+ const steps = await inserted({ ...child, sent, before: [], after: [] }, draft);
41
+ return { id, steps };
42
+ }
43
+ /**
44
+ * A linked row a relation write updates, as `Target.update` updates it
45
+ * (D-138): its rules unless a hook or a default wrote it, its validation,
46
+ * `beforeUpdate`, then its own relation writes.
47
+ */
48
+ async function changed(context, field, update, at, skips) {
49
+ const { scope, plan } = context;
50
+ const { data, row } = update;
51
+ const model = modelOf(context.scope.models, field.target);
52
+ const child = { ...context, model, id: row.id, set: {}, at };
53
+ await resolveData(resolving(child, skips, false), data);
54
+ const sent = skips ? {} : { ...data };
55
+ const via = viaOf(context, field);
56
+ if (!skips)
57
+ scope.access?.allow(model, 'update', { record: row, data: sent, via });
58
+ await prepared(model, data, scope.caller, false, at);
59
+ const record = recordOf(model, row);
60
+ await runHook(model, 'beforeUpdate', { caller: scope.caller, record, data });
61
+ plan.events.push({ model, operation: 'update', id: row.id, before: row });
62
+ return updateSteps({ ...child, sent, before: [], after: [] }, data);
63
+ }
64
+ /** A linked row a relation write deletes, as `Target.delete` (D-138). */
65
+ function dropped(context, field, row, path, skips) {
66
+ const model = modelOf(context.scope.models, field.target);
67
+ const via = viaOf(context, field);
68
+ if (!skips)
69
+ context.scope.access?.allow(model, 'delete', { record: row, via });
70
+ // The parent empties its own key to the row: the cascade leaves it.
71
+ const except = field.kind === 'one' && field.stored
72
+ ? { model: context.model.name, field: field.name, id: context.id }
73
+ : undefined;
74
+ return {
75
+ kind: 'drop',
76
+ model: model.name,
77
+ rows: [row],
78
+ path,
79
+ ...(except === undefined ? {} : { except }),
80
+ written: context.plan.written,
81
+ };
82
+ }
83
+ async function one(context, field, value, creating) {
84
+ const skips = trusted(context, field, value);
85
+ const write = await resolveOne(resolving(context, skips, creating), field, value);
86
+ const at = [...context.at, field.name, write.kind];
87
+ if (write.kind === 'update') {
88
+ context.after.push(...(await changed(context, field, write, at, skips)));
89
+ return;
90
+ }
91
+ if (write.kind === 'delete') {
92
+ context.after.push(dropped(context, field, write.row, `${pathOf(context, field.name)}.delete`, skips));
93
+ }
94
+ // A key the other side holds changes its row: it is updated (D-124).
95
+ const operation = field.stored ? 'read' : 'update';
96
+ let target = write.kind === 'connect' ? write.id : undefined;
97
+ if (target !== undefined) {
98
+ context.plan.connect(field.target, [target], skips, operation);
99
+ }
100
+ if (write.kind === 'create') {
101
+ const made = await created(context, field, write.data, write.at, skips);
102
+ target = made.id;
103
+ (field.stored ? context.before : context.after).push(...made.steps);
104
+ }
105
+ if (field.stored) {
106
+ if (target === undefined && !field.optional) {
107
+ fail(context, [field.name], 'Required.');
108
+ return;
109
+ }
110
+ context.set[field.name] = target ?? null;
111
+ return;
112
+ }
113
+ // A deleted row holds no key; another one may not be left empty (D-37).
114
+ if (write.kind === 'delete')
115
+ return;
116
+ if (!creating && (await holds(context, field, target))) {
117
+ fail(context, [field.name], `The ${field.target} it points to cannot be left without one.`);
118
+ return;
119
+ }
120
+ if (write.kind === 'connect') {
121
+ context.after.push({
122
+ kind: 'move',
123
+ model: field.target,
124
+ field: field.inverse,
125
+ via: viaOf(context, field),
126
+ where: byId(write.id),
127
+ to: context.id,
128
+ trusted: skips,
129
+ });
130
+ }
131
+ }
132
+ /** Deletes, then creates, disconnects and connects, then updates (D-138). */
133
+ async function many(context, field, value, creating) {
134
+ const skips = trusted(context, field, value);
135
+ const write = await resolveMany(resolving(context, skips, creating), field, value);
136
+ const operation = field.join ? 'read' : 'update';
137
+ context.plan.connect(field.target, write.connect, skips, operation);
138
+ for (const { row, path } of write.delete) {
139
+ context.after.push(dropped(context, field, row, path, skips));
140
+ }
141
+ const made = [];
142
+ for (const { data, at } of write.create) {
143
+ const child = await created(context, field, data, at, skips);
144
+ made.push(child.id);
145
+ context.after.push(...child.steps);
146
+ }
147
+ linking(context, field, write, made, skips);
148
+ for (const [index, update] of write.update.entries()) {
149
+ const at = [...context.at, field.name, 'update', index, 'data'];
150
+ context.after.push(...(await changed(context, field, update, at, skips)));
151
+ }
152
+ }
153
+ /** A hook's value the plan refuses is the hook's error, not the caller's. */
154
+ function hookError(context, error) {
155
+ if (!(error instanceof InvalidQuery))
156
+ return error;
157
+ return new TypeError(`${context.model.name}: a before hook wrote invalid data. ${error.message}`, { cause: error });
158
+ }
159
+ async function fields(context, data, creating) {
160
+ const given = new Set();
161
+ const at = ['data', ...context.at].join('.');
162
+ for (const [name, value] of entries(data, at)) {
163
+ const field = context.model.fields.get(name);
164
+ // The caller's data was read before the hooks: a hook wrote the key.
165
+ if (field === undefined) {
166
+ throw hookError(context, unknownKey(pathOf(context, name), context.model.name));
167
+ }
168
+ given.add(name);
169
+ try {
170
+ if (field.kind === 'scalar')
171
+ scalar(context, field, value);
172
+ else if (field.kind === 'one')
173
+ await one(context, field, value, creating);
174
+ else
175
+ await many(context, field, value, creating);
176
+ }
177
+ catch (error) {
178
+ // The caller's relation value reaches rows only now (D-138).
179
+ throw trusted(context, field, value) ? hookError(context, error) : error;
180
+ }
181
+ }
182
+ return given;
183
+ }
184
+ function contextOf(scope, model, id, sent, reads) {
185
+ const plan = new Plan();
186
+ const set = {};
187
+ return {
188
+ scope,
189
+ model,
190
+ id,
191
+ plan,
192
+ reads,
193
+ sent,
194
+ set,
195
+ before: [],
196
+ after: [],
197
+ at: [],
198
+ };
199
+ }
200
+ /** A created row's steps: the rows it points to, its insert, then the rest. */
201
+ async function inserted(context, draft) {
202
+ const { model, id, plan } = context;
203
+ plan.made.add(id);
204
+ const given = await fields(context, draft, true);
205
+ for (const field of model.fields.values()) {
206
+ if (given.has(field.name) || field.kind === 'many')
207
+ continue;
208
+ if (field.kind === 'one' && !field.stored)
209
+ continue;
210
+ // A required field may be left to a hook: checked after it (D-88).
211
+ // A list left unwritten is empty (D-120).
212
+ if (field.kind === 'scalar' && field.list) {
213
+ context.set[field.name] = [];
214
+ }
215
+ else if (field.optional)
216
+ context.set[field.name] = null;
217
+ else
218
+ fail(context, [field.name], 'Required.');
219
+ }
220
+ const now = Date.now();
221
+ const row = {
222
+ ...context.set,
223
+ id,
224
+ createdAt: new Date(now),
225
+ updatedAt: new Date(now),
226
+ };
227
+ const insert = { kind: 'insert', model: model.name, row };
228
+ return [...context.before, insert, ...context.after];
229
+ }
230
+ /** An updated row's steps; `updatedAt` always moves. */
231
+ async function updateSteps(context, draft, operations = new Map()) {
232
+ const { model, id, plan } = context;
233
+ plan.written.add(`${model.name}:${id}`);
234
+ await fields(context, draft, false);
235
+ return [
236
+ ...context.before,
237
+ {
238
+ kind: 'update',
239
+ model: model.name,
240
+ where: byId(id),
241
+ set: { ...context.set, updatedAt: new Date(Date.now()) },
242
+ ...(operations.size === 0
243
+ ? {}
244
+ : { compute: Object.fromEntries(operations) }),
245
+ },
246
+ ...context.after,
247
+ ];
248
+ }
249
+ /** `create`'s changes: the row with its id and timestamps (D-22). */
250
+ export async function createPlan(scope, model, draft, sent, reads, id = uuidv7()) {
251
+ const context = contextOf(scope, model, id, sent, reads);
252
+ context.plan.steps.push(...(await inserted(context, draft)));
253
+ return { id: context.id, plan: context.plan };
254
+ }
255
+ /** `update`'s changes on the stored row. */
256
+ export async function updatePlan(scope, model, id, draft, sent, reads, operations = new Map()) {
257
+ const context = contextOf(scope, model, id, sent, reads);
258
+ context.plan.steps.push(...(await updateSteps(context, draft, operations)));
259
+ return context.plan;
260
+ }