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,60 @@
1
+ // A plugin's manifest (D-57, D-95): checked by `definePlugin`, its ranges
2
+ // matched at `start` against the running kernel and the installed plugins.
3
+ import { satisfies, valid, validRange } from 'semver';
4
+ import kernel from '../package.json' with { type: 'json' };
5
+ import { isObject } from './query-where.js';
6
+ import { Refused } from './errors.js';
7
+ /** Checks a plugin's `manifest`: a name, a version and valid ranges. */
8
+ export function manifestOf(value, plugin) {
9
+ const path = `${plugin}.manifest`;
10
+ if (!isObject(value))
11
+ throw new TypeError(`${path} is an object.`);
12
+ const { name, version, peerDependencies } = value;
13
+ if (typeof name !== 'string' || name === '') {
14
+ throw new TypeError(`${path}.name is a package name.`);
15
+ }
16
+ if (typeof version !== 'string' || valid(version) === null) {
17
+ throw new TypeError(`${path}.version is a version, not ${String(version)}.`);
18
+ }
19
+ if (peerDependencies === undefined)
20
+ return Object.freeze({ name, version });
21
+ if (!isObject(peerDependencies)) {
22
+ throw new TypeError(`${path}.peerDependencies is an object.`);
23
+ }
24
+ const ranges = {};
25
+ for (const [peer, range] of Object.entries(peerDependencies)) {
26
+ if (typeof range !== 'string' || validRange(range) === null) {
27
+ throw new TypeError(`${path}.peerDependencies.${peer} is a version range, not ${String(range)}.`);
28
+ }
29
+ ranges[peer] = range;
30
+ }
31
+ return Object.freeze({
32
+ name,
33
+ version,
34
+ peerDependencies: Object.freeze(ranges),
35
+ });
36
+ }
37
+ // A prerelease of the kernel runs the plugins written for its version range.
38
+ const accepts = (version, range) => satisfies(version, range, { includePrerelease: true });
39
+ /**
40
+ * Refuses a plugin whose ranges exclude the running kernel or an installed
41
+ * plugin, naming both versions; warns of one that gives the kernel no range.
42
+ */
43
+ export function checkVersions(plugins, logger) {
44
+ const installed = new Map([[kernel.name, kernel.version]]);
45
+ for (const { code } of plugins) {
46
+ installed.set(code.manifest.name, code.manifest.version);
47
+ }
48
+ for (const { code } of plugins) {
49
+ const { name, version, peerDependencies = {} } = code.manifest;
50
+ if (peerDependencies[kernel.name] === undefined) {
51
+ logger.warn(`${name} declares no ${kernel.name} range.`);
52
+ }
53
+ for (const [peer, range] of Object.entries(peerDependencies)) {
54
+ const found = installed.get(peer);
55
+ if (found === undefined || accepts(found, range))
56
+ continue;
57
+ throw new Refused(`${name} ${version} needs ${peer} ${range}; this is ${peer} ${found}.`);
58
+ }
59
+ }
60
+ }
@@ -0,0 +1,7 @@
1
+ import type { AggregateRead, Read } from './adapter.ts';
2
+ import type { Reader, StoredRow } from './memory-read.ts';
3
+ /** Of the rows with the same keys, the first in `read`'s order (D-147). */
4
+ export declare function distinct(reader: Reader, read: Read, rows: StoredRow[]): StoredRow[];
5
+ /** Each group of `rows`: its keys' values, then its aggregates', in order. */
6
+ export declare function grouped(reader: Reader, read: AggregateRead, rows: readonly StoredRow[]): unknown[][];
7
+ //# sourceMappingURL=memory-aggregate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-aggregate.d.ts","sourceRoot":"","sources":["../src/memory-aggregate.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAEX,aAAa,EAGb,IAAI,EAEJ,MAAM,cAAc,CAAA;AAIrB,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AA0DzD,2EAA2E;AAC3E,wBAAgB,QAAQ,CACvB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,SAAS,EAAE,GACf,SAAS,EAAE,CAeb;AAyBD,8EAA8E;AAC9E,wBAAgB,OAAO,CACtB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,SAAS,SAAS,EAAE,GACxB,OAAO,EAAE,EAAE,CAqCb"}
@@ -0,0 +1,107 @@
1
+ import { sumDecimals } from './decimal.js';
2
+ import { and, isFilters, not, or, scalar } from './memory-conditions.js';
3
+ import { compareKeys, compareValues, copy, sortable } from './memory-values.js';
4
+ function of(values, operation, field) {
5
+ if (operation === 'count')
6
+ return values.length;
7
+ const [head, ...rest] = values;
8
+ if (head === undefined)
9
+ return null;
10
+ if (operation === 'min' || operation === 'max') {
11
+ const sign = operation === 'min' ? 1 : -1;
12
+ const order = (a, b) => compareValues(sortable(a, field), sortable(b, field));
13
+ const found = rest.reduce((best, item) => (sign * order(item, best) < 0 ? item : best), head);
14
+ return copy(found);
15
+ }
16
+ const sum = field?.kind === 'scalar' && field.type === 'decimal'
17
+ ? sumDecimals(values.map(String), field.scale ?? 0)
18
+ : values.reduce((total, item) => total + Number(item), 0);
19
+ return operation === 'sum' ? sum : Number(sum) / values.length;
20
+ }
21
+ /** One value per aggregate of `rows`, in order. */
22
+ function aggregated(rows, aggregates, fieldOf) {
23
+ return aggregates.map(({ operation, field }) => {
24
+ if (field === undefined)
25
+ return rows.length;
26
+ const values = rows.map((row) => row[field] ?? null);
27
+ return of(values.filter((item) => item !== null), operation, fieldOf(field));
28
+ });
29
+ }
30
+ /** The values of a row's keys, a key through a relation its target's. */
31
+ function keysOf(reader, model, row, by) {
32
+ return by.map(({ field, through }) => {
33
+ const reached = reader.reach(model, row, through);
34
+ return copy(reached?.row[field] ?? null);
35
+ });
36
+ }
37
+ /** Of the rows with the same keys, the first in `read`'s order (D-147). */
38
+ export function distinct(reader, read, rows) {
39
+ const { where, orderBy } = read;
40
+ const sorted = reader.select(read.model, rows, {
41
+ ...(where && { where }),
42
+ ...(orderBy && { orderBy }),
43
+ });
44
+ const seen = new Set();
45
+ return sorted.filter((row) => {
46
+ const id = JSON.stringify(keysOf(reader, read.model, row, read.distinct ?? []));
47
+ if (seen.has(id))
48
+ return false;
49
+ seen.add(id);
50
+ return true;
51
+ });
52
+ }
53
+ /** Whether a group's values pass `having`, whose keys are positions (D-149). */
54
+ function held(filter, values, fields) {
55
+ const truths = [];
56
+ for (const [key, part] of Object.entries(filter)) {
57
+ if (part === undefined)
58
+ continue;
59
+ if (!isFilters(part)) {
60
+ const at = Number(key);
61
+ const sorted = (value) => sortable(value, fields[at]);
62
+ truths.push(scalar(values[at] ?? null, part, sorted));
63
+ continue;
64
+ }
65
+ const inner = part.map((each) => held(each, values, fields));
66
+ if (key === 'AND')
67
+ truths.push(and(inner));
68
+ else if (key === 'OR')
69
+ truths.push(or(inner));
70
+ else
71
+ truths.push(and(inner.map((truth) => not(truth))));
72
+ }
73
+ return and(truths);
74
+ }
75
+ /** Each group of `rows`: its keys' values, then its aggregates', in order. */
76
+ export function grouped(reader, read, rows) {
77
+ const by = read.by ?? [];
78
+ const fieldOf = (name) => reader.field(read.model, name);
79
+ const groups = new Map();
80
+ if (by.length === 0)
81
+ groups.set('[]', { keys: [], rows: [] });
82
+ for (const row of rows) {
83
+ const keys = keysOf(reader, read.model, row, by);
84
+ const id = JSON.stringify(keys);
85
+ const group = groups.get(id) ?? { keys, rows: [] };
86
+ group.rows.push(row);
87
+ groups.set(id, group);
88
+ }
89
+ const lists = [...groups.values()].map((group) => [
90
+ ...group.keys,
91
+ ...aggregated(group.rows, read.aggregates, fieldOf),
92
+ ]);
93
+ // A key through a relation is an id; a decimal sorts by value (D-145).
94
+ const fields = [
95
+ ...by.map(({ field, through }) => (through ? undefined : field)),
96
+ ...read.aggregates.map(({ operation, field }) => operation === 'count' ? undefined : field),
97
+ ].map((name) => (name === undefined ? undefined : fieldOf(name)));
98
+ const { having } = read;
99
+ const kept = having === undefined
100
+ ? lists
101
+ : lists.filter((list) => held(having, list, fields) === true);
102
+ const order = read.orderBy ?? [];
103
+ const sorted = (list) => order.map(({ at }) => sortable(list[at], fields[at]));
104
+ kept.sort((a, b) => compareKeys(sorted(a), sorted(b), order));
105
+ const skip = read.skip ?? 0;
106
+ return kept.slice(skip, read.take === undefined ? undefined : skip + read.take);
107
+ }
@@ -0,0 +1,8 @@
1
+ import type { Condition, Filter } from './adapter.ts';
2
+ export type Truth = boolean | null;
3
+ export declare function and(truths: readonly Truth[]): Truth;
4
+ export declare function or(truths: readonly Truth[]): Truth;
5
+ export declare function not(truth: Truth): Truth;
6
+ export declare function isFilters(value: Condition | readonly Filter[]): value is readonly Filter[];
7
+ export declare function scalar(stored: unknown, condition: Condition, sorted: (value: unknown) => unknown): Truth;
8
+ //# sourceMappingURL=memory-conditions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-conditions.d.ts","sourceRoot":"","sources":["../src/memory-conditions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAIrD,MAAM,MAAM,KAAK,GAAG,OAAO,GAAG,IAAI,CAAA;AAElC,wBAAgB,GAAG,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,GAAG,KAAK,CAGnD;AAED,wBAAgB,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,GAAG,KAAK,CAGlD;AAED,wBAAgB,GAAG,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAEvC;AAED,wBAAgB,SAAS,CACxB,KAAK,EAAE,SAAS,GAAG,SAAS,MAAM,EAAE,GAClC,KAAK,IAAI,SAAS,MAAM,EAAE,CAE5B;AAED,wBAAgB,MAAM,CACrB,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,GACjC,KAAK,CAuDP"}
@@ -0,0 +1,82 @@
1
+ import { jsonPath } from './memory-json.js';
2
+ import { compareValues, lower, same, text } from './memory-values.js';
3
+ export function and(truths) {
4
+ if (truths.includes(false))
5
+ return false;
6
+ return truths.includes(null) ? null : true;
7
+ }
8
+ export function or(truths) {
9
+ if (truths.includes(true))
10
+ return true;
11
+ return truths.includes(null) ? null : false;
12
+ }
13
+ export function not(truth) {
14
+ return truth === null ? null : !truth;
15
+ }
16
+ export function isFilters(value) {
17
+ return Array.isArray(value);
18
+ }
19
+ export function scalar(stored, condition, sorted) {
20
+ if (condition.path !== undefined)
21
+ return jsonPath(stored, condition);
22
+ const truths = [];
23
+ const known = stored !== null;
24
+ const fold = condition.mode === 'insensitive' ? lower : (item) => item;
25
+ const value = fold(stored);
26
+ for (const [operator, raw] of Object.entries(condition)) {
27
+ if (raw === undefined || operator === 'mode')
28
+ continue;
29
+ const operand = Array.isArray(raw)
30
+ ? raw.map((item) => fold(item))
31
+ : fold(raw);
32
+ if (operator === 'equals' || operator === 'not') {
33
+ const equal = operand === null ? !known : known ? same(value, operand) : null;
34
+ truths.push(operator === 'equals' ? equal : not(equal));
35
+ }
36
+ else if (operator === 'in' || operator === 'notIn') {
37
+ const list = Array.isArray(operand) ? operand : [];
38
+ const found = list.length === 0
39
+ ? false
40
+ : known
41
+ ? list.some((item) => same(value, item))
42
+ : null;
43
+ truths.push(operator === 'in' ? found : not(found));
44
+ }
45
+ else if (!known) {
46
+ truths.push(null);
47
+ }
48
+ else if (operator.startsWith('has') || operator === 'isEmpty') {
49
+ const items = Array.isArray(value) ? value : [];
50
+ const wanted = Array.isArray(operand)
51
+ ? operand
52
+ : [operand];
53
+ const holds = (item) => items.includes(item);
54
+ truths.push(operator === 'isEmpty'
55
+ ? (items.length === 0) === operand
56
+ : operator === 'hasEvery'
57
+ ? wanted.every(holds)
58
+ : wanted.some(holds));
59
+ }
60
+ else if (operator === 'contains') {
61
+ truths.push(text(value, operand, (a, b) => a.includes(b)));
62
+ }
63
+ else if (operator === 'startsWith') {
64
+ truths.push(text(value, operand, (a, b) => a.startsWith(b)));
65
+ }
66
+ else if (operator === 'endsWith') {
67
+ truths.push(text(value, operand, (a, b) => a.endsWith(b)));
68
+ }
69
+ else {
70
+ const order = compareValues(sorted(value), sorted(operand));
71
+ if (operator === 'lt')
72
+ truths.push(order < 0);
73
+ else if (operator === 'lte')
74
+ truths.push(order <= 0);
75
+ else if (operator === 'gt')
76
+ truths.push(order > 0);
77
+ else
78
+ truths.push(order >= 0);
79
+ }
80
+ }
81
+ return and(truths);
82
+ }
@@ -0,0 +1,34 @@
1
+ import type { AggregateRead, Changed, CountRead, Read, Row, Schema, Write } from './adapter.ts';
2
+ import type { Fields, Store } from './memory-read.ts';
3
+ import { Reader } from './memory-read.ts';
4
+ export declare class Draft {
5
+ readonly reader: Reader;
6
+ readonly schema: Schema;
7
+ /** What the write changed, in order, for the feed (D-154). */
8
+ readonly changed: Changed[];
9
+ constructor(store: Store, fields: Fields, schema: Schema);
10
+ find(read: Read): Row[];
11
+ count(read: CountRead): number;
12
+ aggregate(read: AggregateRead): unknown[][];
13
+ private selected;
14
+ write(write: Write): Row[];
15
+ private change;
16
+ private note;
17
+ private matching;
18
+ private stored;
19
+ /** The numbers and lists a change computes on `row` (D-132, D-149). */
20
+ private computed;
21
+ /** Applies `delete`; returns the ids it removed. */
22
+ private remove;
23
+ private apply;
24
+ private joinFields;
25
+ private side;
26
+ private ids;
27
+ /** Links `id` to `target` unless they were; tells whether it did. */
28
+ private link;
29
+ /** Unlinks `id` from `targets`; returns the targets it was linked to. */
30
+ private unlink;
31
+ /** Unique fields, unique indexes and one-to-one keys; `null` never clashes. */
32
+ private checkUnique;
33
+ }
34
+ //# sourceMappingURL=memory-draft.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-draft.d.ts","sourceRoot":"","sources":["../src/memory-draft.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACX,aAAa,EAGb,OAAO,EACP,SAAS,EAET,IAAI,EACJ,GAAG,EAEH,MAAM,EAEN,KAAK,EACL,MAAM,cAAc,CAAA;AAErB,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAa,MAAM,kBAAkB,CAAA;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AA4BzC,qBAAa,KAAK;IACjB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,CAAK;IAEhC,YAAY,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAGvD;IAED,IAAI,CAAC,IAAI,EAAE,IAAI,GAAG,GAAG,EAAE,CAMtB;IAED,KAAK,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAE7B;IAED,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,EAAE,EAAE,CAE1C;IAED,OAAO,CAAC,QAAQ;IAOhB,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,GAAG,EAAE,CA4BzB;IAED,OAAO,CAAC,MAAM;IAcd,OAAO,CAAC,IAAI;IAKZ,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,MAAM;IAad,uEAAuE;IACvE,OAAO,CAAC,QAAQ;IAmBhB,oDAAoD;IACpD,OAAO,CAAC,MAAM;IAed,OAAO,CAAC,KAAK;IAuDb,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,IAAI;IAUZ,OAAO,CAAC,GAAG;IAUX,qEAAqE;IACrE,OAAO,CAAC,IAAI;IAaZ,yEAAyE;IACzE,OAAO,CAAC,MAAM;IAcd,+EAA+E;IAC/E,OAAO,CAAC,WAAW;CAqBnB"}
@@ -0,0 +1,255 @@
1
+ import { CheckFailed, OutOfRange, UniqueViolation } from './adapter.js';
2
+ import { Reader } from './memory-read.js';
3
+ import { distinct, grouped } from './memory-aggregate.js';
4
+ import { copy } from './memory-values.js';
5
+ import { listed } from './list-update.js';
6
+ import { computed } from './number-update.js';
7
+ import { isInteger } from './query-where.js';
8
+ /**
9
+ * A value as PostgreSQL gives it back: `-0` is `0`, which `pg` sends for a
10
+ * number, and JSON text for json (D-94).
11
+ */
12
+ function storedAs(type, value) {
13
+ if (type === 'json') {
14
+ const parsed = JSON.parse(JSON.stringify(value));
15
+ return parsed;
16
+ }
17
+ if (type === 'number' && value === 0)
18
+ return 0;
19
+ return copy(value);
20
+ }
21
+ function keyOf(values) {
22
+ return JSON.stringify(values.map((value) => value instanceof Date ? `date:${value.getTime()}` : value));
23
+ }
24
+ export class Draft {
25
+ reader;
26
+ schema;
27
+ /** What the write changed, in order, for the feed (D-154). */
28
+ changed = [];
29
+ constructor(store, fields, schema) {
30
+ this.reader = new Reader(store, fields);
31
+ this.schema = schema;
32
+ }
33
+ find(read) {
34
+ const stored = [...this.reader.table(read.model).values()];
35
+ const rows = read.distinct ? distinct(this.reader, read, stored) : stored;
36
+ return this.reader
37
+ .select(read.model, rows, read)
38
+ .map((row) => this.reader.output(read.model, row, read));
39
+ }
40
+ count(read) {
41
+ return this.selected(read).length;
42
+ }
43
+ aggregate(read) {
44
+ return grouped(this.reader, read, this.selected(read));
45
+ }
46
+ selected(read) {
47
+ const rows = [...this.reader.table(read.model).values()];
48
+ return rows.filter((row) => this.reader.matches(read.model, row, read.where) === true);
49
+ }
50
+ write(write) {
51
+ for (const [index, check] of (write.checks ?? []).entries()) {
52
+ if (this.count(check) !== check.count)
53
+ throw new CheckFailed(index);
54
+ }
55
+ const read = write.read;
56
+ if (read !== undefined && write.before === true) {
57
+ const { model } = read;
58
+ const deletes = write.changes.some((change) => change.kind === 'delete' && change.model === model);
59
+ const update = write.changes.find((change) => change.kind === 'update' && change.model === model);
60
+ if (!deletes) {
61
+ // The rows its update changed, as it left them (D-133).
62
+ const changed = update && this.matching(model, update);
63
+ const ids = new Set(changed?.map((row) => row.id));
64
+ this.change(write.changes);
65
+ return this.find(read).filter((row) => ids.has(row.id));
66
+ }
67
+ const rows = this.find(read);
68
+ this.change(write.changes);
69
+ // The rows the write's delete removed, as they were (D-104).
70
+ const table = this.reader.table(read.model);
71
+ return rows.filter((row) => !table.has(row.id));
72
+ }
73
+ this.change(write.changes);
74
+ return read === undefined ? [] : this.find(read);
75
+ }
76
+ change(changes) {
77
+ const touched = new Set();
78
+ this.reader.removed.clear();
79
+ for (const [index, change] of changes.entries()) {
80
+ touched.add(change.model);
81
+ if (change.kind === 'delete') {
82
+ const removed = this.remove(change);
83
+ this.reader.removed.set(index, removed);
84
+ this.note({ kind: 'delete', model: change.model, ids: [...removed] });
85
+ }
86
+ else
87
+ this.apply(change);
88
+ }
89
+ for (const model of touched)
90
+ this.checkUnique(model);
91
+ }
92
+ note(change) {
93
+ const rows = 'field' in change ? change.pairs : change.ids;
94
+ if (rows?.length !== 0)
95
+ this.changed.push(change);
96
+ }
97
+ matching(model, change) {
98
+ if (change.kind !== 'update' && change.kind !== 'delete')
99
+ return [];
100
+ return [...this.reader.table(model).values()].filter((row) => this.reader.matches(model, row, change.where) === true);
101
+ }
102
+ stored(model, value) {
103
+ return Object.fromEntries(Object.entries(value).map(([key, item]) => {
104
+ const field = this.reader.field(model, key);
105
+ const type = field?.kind === 'scalar' ? field.type : undefined;
106
+ return [key, storedAs(type, item)];
107
+ }));
108
+ }
109
+ /** The numbers and lists a change computes on `row` (D-132, D-149). */
110
+ computed(model, row, compute = {}) {
111
+ return Object.fromEntries(Object.entries(compute).map(([key, operation]) => {
112
+ if ('elements' in operation)
113
+ return [key, listed(row[key], operation)];
114
+ const field = this.reader.field(model, key);
115
+ const integer = field?.kind === 'scalar' && field.integer === true;
116
+ const result = computed(row[key], operation, integer);
117
+ if (integer ? !isInteger(result) : !Number.isFinite(result)) {
118
+ throw new OutOfRange(model, key);
119
+ }
120
+ return [key, result];
121
+ }));
122
+ }
123
+ /** Applies `delete`; returns the ids it removed. */
124
+ remove(change) {
125
+ const table = this.reader.table(change.model);
126
+ const removed = new Set();
127
+ for (const row of this.matching(change.model, change)) {
128
+ removed.add(row.id);
129
+ table.delete(row.id);
130
+ for (const field of this.joinFields(change.model)) {
131
+ this.unlink(change.model, field, row.id, [
132
+ ...(this.side(change.model, field.name).get(row.id) ?? []),
133
+ ]);
134
+ }
135
+ }
136
+ return removed;
137
+ }
138
+ apply(change) {
139
+ const table = this.reader.table(change.model);
140
+ switch (change.kind) {
141
+ case 'insert': {
142
+ if (table.has(change.row.id)) {
143
+ throw new UniqueViolation(change.model, ['id']);
144
+ }
145
+ table.set(change.row.id, {
146
+ ...this.stored(change.model, change.row),
147
+ id: change.row.id,
148
+ });
149
+ this.note({ kind: 'insert', model: change.model, ids: [change.row.id] });
150
+ return;
151
+ }
152
+ case 'update': {
153
+ const rows = this.matching(change.model, change);
154
+ for (const row of rows) {
155
+ const set = {
156
+ ...change.set,
157
+ ...this.computed(change.model, row, change.compute),
158
+ };
159
+ table.set(row.id, {
160
+ ...row,
161
+ ...this.stored(change.model, set),
162
+ id: row.id,
163
+ });
164
+ }
165
+ const fields = [
166
+ ...Object.keys(change.set),
167
+ ...Object.keys(change.compute ?? {}),
168
+ ];
169
+ const ids = rows.map((row) => row.id);
170
+ this.note({ kind: 'update', model: change.model, ids, fields });
171
+ return;
172
+ }
173
+ case 'link':
174
+ case 'unlink': {
175
+ const field = this.reader.field(change.model, change.field);
176
+ if (field?.kind !== 'many' || !field.join) {
177
+ throw new Error(`${change.model}.${change.field} has no join.`);
178
+ }
179
+ const { model, id } = change;
180
+ const targets = change.kind === 'unlink'
181
+ ? this.unlink(model, field, id, change.targets)
182
+ : change.targets.filter((target) => this.link(model, field, id, target));
183
+ const pairs = targets.map((target) => [id, target]);
184
+ this.note({ kind: change.kind, model, field: field.name, pairs });
185
+ return;
186
+ }
187
+ }
188
+ }
189
+ joinFields(model) {
190
+ return [...(this.reader.fields.get(model)?.values() ?? [])].filter((field) => field.kind === 'many' && field.join && field.from === undefined);
191
+ }
192
+ side(model, field) {
193
+ const name = `${model}.${field}`;
194
+ let side = this.reader.store.joins.get(name);
195
+ if (side === undefined) {
196
+ side = new Map();
197
+ this.reader.store.joins.set(name, side);
198
+ }
199
+ return side;
200
+ }
201
+ ids(model, field, id) {
202
+ const side = this.side(model, field);
203
+ let ids = side.get(id);
204
+ if (ids === undefined) {
205
+ ids = new Set();
206
+ side.set(id, ids);
207
+ }
208
+ return ids;
209
+ }
210
+ /** Links `id` to `target` unless they were; tells whether it did. */
211
+ link(model, field, id, target) {
212
+ const ids = this.ids(model, field.name, id);
213
+ if (ids.has(target))
214
+ return false;
215
+ ids.add(target);
216
+ this.ids(field.target, field.inverse, target).add(id);
217
+ return true;
218
+ }
219
+ /** Unlinks `id` from `targets`; returns the targets it was linked to. */
220
+ unlink(model, field, id, targets) {
221
+ if (field.kind !== 'many')
222
+ return [];
223
+ return targets.filter((target) => {
224
+ const removed = this.side(model, field.name).get(id)?.delete(target);
225
+ this.side(field.target, field.inverse).get(target)?.delete(id);
226
+ return removed === true;
227
+ });
228
+ }
229
+ /** Unique fields, unique indexes and one-to-one keys; `null` never clashes. */
230
+ checkUnique(model) {
231
+ const definition = this.schema.models.find((each) => each.name === model);
232
+ if (definition === undefined)
233
+ return;
234
+ const sets = definition.indexes
235
+ .filter((index) => index.unique)
236
+ .map((index) => index.fields);
237
+ for (const field of definition.fields) {
238
+ if (field.kind !== 'many' && field.unique)
239
+ sets.push([field.name]);
240
+ }
241
+ const rows = [...this.reader.table(model).values()];
242
+ for (const fields of sets) {
243
+ const seen = new Set();
244
+ for (const row of rows) {
245
+ const values = fields.map((field) => row[field] ?? null);
246
+ if (values.includes(null))
247
+ continue;
248
+ const found = keyOf(values);
249
+ if (seen.has(found))
250
+ throw new UniqueViolation(model, fields);
251
+ seen.add(found);
252
+ }
253
+ }
254
+ }
255
+ }
@@ -0,0 +1,6 @@
1
+ import type { Condition } from './adapter.ts';
2
+ type Truth = boolean | null;
3
+ /** A json condition with `path`: unknown where the value lacks the path. */
4
+ export declare function jsonPath(stored: unknown, condition: Condition): Truth;
5
+ export {};
6
+ //# sourceMappingURL=memory-json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-json.d.ts","sourceRoot":"","sources":["../src/memory-json.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAI7C,KAAK,KAAK,GAAG,OAAO,GAAG,IAAI,CAAA;AA2C3B,4EAA4E;AAC5E,wBAAgB,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,GAAG,KAAK,CAwCrE"}
@@ -0,0 +1,86 @@
1
+ import { compareValues, lower, same, text } from './memory-values.js';
2
+ import { isObject } from './query-where.js';
3
+ /** An array's index as PostgreSQL's `strtoint` reads it; `undefined` when not one. */
4
+ function indexOf(key, length) {
5
+ if (!/^[\t\n\v\f\r ]*[+-]?\d+$/.test(key))
6
+ return undefined;
7
+ const index = Number(key);
8
+ if (index < -2_147_483_647 || index > 2_147_483_647)
9
+ return undefined;
10
+ return index < 0 ? length + index : index;
11
+ }
12
+ /** The value at `path`, `undefined` where the value lacks it. */
13
+ function at(value, path) {
14
+ let current = value;
15
+ for (const key of path) {
16
+ if (Array.isArray(current)) {
17
+ const index = indexOf(key, current.length);
18
+ current = index === undefined || index < 0 ? undefined : current[index];
19
+ }
20
+ else if (isObject(current) && Object.hasOwn(current, key)) {
21
+ current = current[key];
22
+ }
23
+ else
24
+ return undefined;
25
+ }
26
+ return current;
27
+ }
28
+ /** `@>`: a nested value is held only by a value of its own JSON type. */
29
+ function holds(container, item) {
30
+ if (Array.isArray(container) && Array.isArray(item)) {
31
+ return item.every((each) => container.some((one) => holds(one, each)));
32
+ }
33
+ if (isObject(container) && isObject(item)) {
34
+ return Object.entries(item).every(([key, each]) => Object.hasOwn(container, key) && holds(container[key], each));
35
+ }
36
+ return (!Array.isArray(container) && !isObject(container) && same(container, item));
37
+ }
38
+ const typeOf = (value) => Array.isArray(value) ? 'array' : value === null ? 'null' : typeof value;
39
+ /** A json condition with `path`: unknown where the value lacks the path. */
40
+ export function jsonPath(stored, condition) {
41
+ const value = stored === null ? undefined : at(stored, condition.path ?? []);
42
+ if (value === undefined)
43
+ return null;
44
+ const fold = condition.mode === 'insensitive' ? lower : (item) => item;
45
+ const strings = (test, operand) => text(fold(value), fold(operand), test);
46
+ const items = Array.isArray(value) ? value : [];
47
+ const truths = [];
48
+ for (const [operator, operand] of Object.entries(condition)) {
49
+ if (operand === undefined || operator === 'mode' || operator === 'path')
50
+ continue;
51
+ if (operator === 'equals')
52
+ truths.push(same(value, operand));
53
+ else if (operator === 'not')
54
+ truths.push(!same(value, operand));
55
+ else if (operator === 'stringContains') {
56
+ truths.push(strings((a, b) => a.includes(b), operand));
57
+ }
58
+ else if (operator === 'stringStartsWith') {
59
+ truths.push(strings((a, b) => a.startsWith(b), operand));
60
+ }
61
+ else if (operator === 'stringEndsWith') {
62
+ truths.push(strings((a, b) => a.endsWith(b), operand));
63
+ }
64
+ else if (operator === 'arrayContains') {
65
+ truths.push(Array.isArray(value) && holds(value, operand));
66
+ }
67
+ else if (operator === 'arrayStartsWith') {
68
+ truths.push(items.length > 0 && same(items[0], operand));
69
+ }
70
+ else if (operator === 'arrayEndsWith') {
71
+ truths.push(items.length > 0 && same(items.at(-1), operand));
72
+ }
73
+ else {
74
+ const order = compareValues(value, operand);
75
+ const kept = operator === 'lt'
76
+ ? order < 0
77
+ : operator === 'lte'
78
+ ? order <= 0
79
+ : operator === 'gt'
80
+ ? order > 0
81
+ : order >= 0;
82
+ truths.push(typeOf(value) === typeOf(operand) && kept);
83
+ }
84
+ }
85
+ return !truths.includes(false);
86
+ }