@optimystic/db-core 0.0.1

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 (345) hide show
  1. package/README.md +328 -0
  2. package/dist/index.min.js +18 -0
  3. package/dist/index.min.js.map +7 -0
  4. package/dist/src/blocks/block-store.d.ts +12 -0
  5. package/dist/src/blocks/block-store.d.ts.map +1 -0
  6. package/dist/src/blocks/block-store.js +2 -0
  7. package/dist/src/blocks/block-store.js.map +1 -0
  8. package/dist/src/blocks/block-types.d.ts +3 -0
  9. package/dist/src/blocks/block-types.d.ts.map +1 -0
  10. package/dist/src/blocks/block-types.js +9 -0
  11. package/dist/src/blocks/block-types.js.map +1 -0
  12. package/dist/src/blocks/helpers.d.ts +4 -0
  13. package/dist/src/blocks/helpers.d.ts.map +1 -0
  14. package/dist/src/blocks/helpers.js +12 -0
  15. package/dist/src/blocks/helpers.js.map +1 -0
  16. package/dist/src/blocks/index.d.ts +5 -0
  17. package/dist/src/blocks/index.d.ts.map +1 -0
  18. package/dist/src/blocks/index.js +5 -0
  19. package/dist/src/blocks/index.js.map +1 -0
  20. package/dist/src/blocks/structs.d.ts +14 -0
  21. package/dist/src/blocks/structs.d.ts.map +1 -0
  22. package/dist/src/blocks/structs.js +2 -0
  23. package/dist/src/blocks/structs.js.map +1 -0
  24. package/dist/src/btree/btree.d.ts +135 -0
  25. package/dist/src/btree/btree.d.ts.map +1 -0
  26. package/dist/src/btree/btree.js +727 -0
  27. package/dist/src/btree/btree.js.map +1 -0
  28. package/dist/src/btree/independent-trunk.d.ts +17 -0
  29. package/dist/src/btree/independent-trunk.d.ts.map +1 -0
  30. package/dist/src/btree/independent-trunk.js +41 -0
  31. package/dist/src/btree/independent-trunk.js.map +1 -0
  32. package/dist/src/btree/index.d.ts +6 -0
  33. package/dist/src/btree/index.d.ts.map +1 -0
  34. package/dist/src/btree/index.js +6 -0
  35. package/dist/src/btree/index.js.map +1 -0
  36. package/dist/src/btree/key-range.d.ts +13 -0
  37. package/dist/src/btree/key-range.d.ts.map +1 -0
  38. package/dist/src/btree/key-range.js +20 -0
  39. package/dist/src/btree/key-range.js.map +1 -0
  40. package/dist/src/btree/keyset.d.ts +4 -0
  41. package/dist/src/btree/keyset.d.ts.map +1 -0
  42. package/dist/src/btree/keyset.js +4 -0
  43. package/dist/src/btree/keyset.js.map +1 -0
  44. package/dist/src/btree/nodes.d.ts +16 -0
  45. package/dist/src/btree/nodes.d.ts.map +1 -0
  46. package/dist/src/btree/nodes.js +9 -0
  47. package/dist/src/btree/nodes.js.map +1 -0
  48. package/dist/src/btree/path.d.ts +22 -0
  49. package/dist/src/btree/path.d.ts.map +1 -0
  50. package/dist/src/btree/path.js +39 -0
  51. package/dist/src/btree/path.js.map +1 -0
  52. package/dist/src/btree/tree-block.d.ts +7 -0
  53. package/dist/src/btree/tree-block.d.ts.map +1 -0
  54. package/dist/src/btree/tree-block.js +5 -0
  55. package/dist/src/btree/tree-block.js.map +1 -0
  56. package/dist/src/btree/trunk.d.ts +13 -0
  57. package/dist/src/btree/trunk.d.ts.map +1 -0
  58. package/dist/src/btree/trunk.js +2 -0
  59. package/dist/src/btree/trunk.js.map +1 -0
  60. package/dist/src/chain/chain-nodes.d.ts +18 -0
  61. package/dist/src/chain/chain-nodes.d.ts.map +1 -0
  62. package/dist/src/chain/chain-nodes.js +10 -0
  63. package/dist/src/chain/chain-nodes.js.map +1 -0
  64. package/dist/src/chain/chain.d.ts +75 -0
  65. package/dist/src/chain/chain.d.ts.map +1 -0
  66. package/dist/src/chain/chain.js +268 -0
  67. package/dist/src/chain/chain.js.map +1 -0
  68. package/dist/src/chain/index.d.ts +2 -0
  69. package/dist/src/chain/index.d.ts.map +1 -0
  70. package/dist/src/chain/index.js +2 -0
  71. package/dist/src/chain/index.js.map +1 -0
  72. package/dist/src/cluster/i-cluster.d.ts +5 -0
  73. package/dist/src/cluster/i-cluster.d.ts.map +1 -0
  74. package/dist/src/cluster/i-cluster.js +2 -0
  75. package/dist/src/cluster/i-cluster.js.map +1 -0
  76. package/dist/src/cluster/index.d.ts +3 -0
  77. package/dist/src/cluster/index.d.ts.map +1 -0
  78. package/dist/src/cluster/index.js +3 -0
  79. package/dist/src/cluster/index.js.map +1 -0
  80. package/dist/src/cluster/structs.d.ts +47 -0
  81. package/dist/src/cluster/structs.d.ts.map +1 -0
  82. package/dist/src/cluster/structs.js +2 -0
  83. package/dist/src/cluster/structs.js.map +1 -0
  84. package/dist/src/collection/action.d.ts +26 -0
  85. package/dist/src/collection/action.d.ts.map +1 -0
  86. package/dist/src/collection/action.js +2 -0
  87. package/dist/src/collection/action.js.map +1 -0
  88. package/dist/src/collection/collection.d.ts +48 -0
  89. package/dist/src/collection/collection.d.ts.map +1 -0
  90. package/dist/src/collection/collection.js +175 -0
  91. package/dist/src/collection/collection.js.map +1 -0
  92. package/dist/src/collection/index.d.ts +4 -0
  93. package/dist/src/collection/index.d.ts.map +1 -0
  94. package/dist/src/collection/index.js +4 -0
  95. package/dist/src/collection/index.js.map +1 -0
  96. package/dist/src/collection/struct.d.ts +16 -0
  97. package/dist/src/collection/struct.d.ts.map +1 -0
  98. package/dist/src/collection/struct.js +2 -0
  99. package/dist/src/collection/struct.js.map +1 -0
  100. package/dist/src/collections/diary/diary.d.ts +9 -0
  101. package/dist/src/collections/diary/diary.d.ts.map +1 -0
  102. package/dist/src/collections/diary/diary.js +37 -0
  103. package/dist/src/collections/diary/diary.js.map +1 -0
  104. package/dist/src/collections/diary/index.d.ts +3 -0
  105. package/dist/src/collections/diary/index.d.ts.map +1 -0
  106. package/dist/src/collections/diary/index.js +3 -0
  107. package/dist/src/collections/diary/index.js.map +1 -0
  108. package/dist/src/collections/diary/struct.d.ts +2 -0
  109. package/dist/src/collections/diary/struct.d.ts.map +1 -0
  110. package/dist/src/collections/diary/struct.js +3 -0
  111. package/dist/src/collections/diary/struct.js.map +1 -0
  112. package/dist/src/collections/index.d.ts +3 -0
  113. package/dist/src/collections/index.d.ts.map +1 -0
  114. package/dist/src/collections/index.js +3 -0
  115. package/dist/src/collections/index.js.map +1 -0
  116. package/dist/src/collections/tree/collection-trunk.d.ts +11 -0
  117. package/dist/src/collections/tree/collection-trunk.d.ts.map +1 -0
  118. package/dist/src/collections/tree/collection-trunk.js +22 -0
  119. package/dist/src/collections/tree/collection-trunk.js.map +1 -0
  120. package/dist/src/collections/tree/index.d.ts +3 -0
  121. package/dist/src/collections/tree/index.d.ts.map +1 -0
  122. package/dist/src/collections/tree/index.js +3 -0
  123. package/dist/src/collections/tree/index.js.map +1 -0
  124. package/dist/src/collections/tree/struct.d.ts +12 -0
  125. package/dist/src/collections/tree/struct.d.ts.map +1 -0
  126. package/dist/src/collections/tree/struct.js +4 -0
  127. package/dist/src/collections/tree/struct.js.map +1 -0
  128. package/dist/src/collections/tree/tree.d.ts +34 -0
  129. package/dist/src/collections/tree/tree.d.ts.map +1 -0
  130. package/dist/src/collections/tree/tree.js +100 -0
  131. package/dist/src/collections/tree/tree.js.map +1 -0
  132. package/dist/src/index.d.ts +18 -0
  133. package/dist/src/index.d.ts.map +1 -0
  134. package/dist/src/index.js +18 -0
  135. package/dist/src/index.js.map +1 -0
  136. package/dist/src/log/index.d.ts +3 -0
  137. package/dist/src/log/index.d.ts.map +1 -0
  138. package/dist/src/log/index.js +3 -0
  139. package/dist/src/log/index.js.map +1 -0
  140. package/dist/src/log/log.d.ts +57 -0
  141. package/dist/src/log/log.d.ts.map +1 -0
  142. package/dist/src/log/log.js +131 -0
  143. package/dist/src/log/log.js.map +1 -0
  144. package/dist/src/log/struct.d.ts +36 -0
  145. package/dist/src/log/struct.d.ts.map +1 -0
  146. package/dist/src/log/struct.js +3 -0
  147. package/dist/src/log/struct.js.map +1 -0
  148. package/dist/src/network/i-key-network.d.ts +21 -0
  149. package/dist/src/network/i-key-network.d.ts.map +1 -0
  150. package/dist/src/network/i-key-network.js +2 -0
  151. package/dist/src/network/i-key-network.js.map +1 -0
  152. package/dist/src/network/i-peer-network.d.ts +8 -0
  153. package/dist/src/network/i-peer-network.d.ts.map +1 -0
  154. package/dist/src/network/i-peer-network.js +2 -0
  155. package/dist/src/network/i-peer-network.js.map +1 -0
  156. package/dist/src/network/i-repo.d.ts +17 -0
  157. package/dist/src/network/i-repo.d.ts.map +1 -0
  158. package/dist/src/network/i-repo.js +2 -0
  159. package/dist/src/network/i-repo.js.map +1 -0
  160. package/dist/src/network/index.d.ts +6 -0
  161. package/dist/src/network/index.d.ts.map +1 -0
  162. package/dist/src/network/index.js +6 -0
  163. package/dist/src/network/index.js.map +1 -0
  164. package/dist/src/network/repo-protocol.d.ts +19 -0
  165. package/dist/src/network/repo-protocol.d.ts.map +1 -0
  166. package/dist/src/network/repo-protocol.js +2 -0
  167. package/dist/src/network/repo-protocol.js.map +1 -0
  168. package/dist/src/network/struct.d.ts +115 -0
  169. package/dist/src/network/struct.d.ts.map +1 -0
  170. package/dist/src/network/struct.js +2 -0
  171. package/dist/src/network/struct.js.map +1 -0
  172. package/dist/src/transaction/actions-engine.d.ts +37 -0
  173. package/dist/src/transaction/actions-engine.d.ts.map +1 -0
  174. package/dist/src/transaction/actions-engine.js +67 -0
  175. package/dist/src/transaction/actions-engine.js.map +1 -0
  176. package/dist/src/transaction/context.d.ts +60 -0
  177. package/dist/src/transaction/context.d.ts.map +1 -0
  178. package/dist/src/transaction/context.js +91 -0
  179. package/dist/src/transaction/context.js.map +1 -0
  180. package/dist/src/transaction/coordinator.d.ts +118 -0
  181. package/dist/src/transaction/coordinator.d.ts.map +1 -0
  182. package/dist/src/transaction/coordinator.js +417 -0
  183. package/dist/src/transaction/coordinator.js.map +1 -0
  184. package/dist/src/transaction/index.d.ts +10 -0
  185. package/dist/src/transaction/index.d.ts.map +1 -0
  186. package/dist/src/transaction/index.js +7 -0
  187. package/dist/src/transaction/index.js.map +1 -0
  188. package/dist/src/transaction/session.d.ts +80 -0
  189. package/dist/src/transaction/session.d.ts.map +1 -0
  190. package/dist/src/transaction/session.js +161 -0
  191. package/dist/src/transaction/session.js.map +1 -0
  192. package/dist/src/transaction/transaction.d.ts +156 -0
  193. package/dist/src/transaction/transaction.d.ts.map +1 -0
  194. package/dist/src/transaction/transaction.js +31 -0
  195. package/dist/src/transaction/transaction.js.map +1 -0
  196. package/dist/src/transaction/validator.d.ts +46 -0
  197. package/dist/src/transaction/validator.d.ts.map +1 -0
  198. package/dist/src/transaction/validator.js +97 -0
  199. package/dist/src/transaction/validator.js.map +1 -0
  200. package/dist/src/transactor/index.d.ts +4 -0
  201. package/dist/src/transactor/index.d.ts.map +1 -0
  202. package/dist/src/transactor/index.js +4 -0
  203. package/dist/src/transactor/index.js.map +1 -0
  204. package/dist/src/transactor/network-transactor.d.ts +36 -0
  205. package/dist/src/transactor/network-transactor.d.ts.map +1 -0
  206. package/dist/src/transactor/network-transactor.js +297 -0
  207. package/dist/src/transactor/network-transactor.js.map +1 -0
  208. package/dist/src/transactor/transactor-source.d.ts +24 -0
  209. package/dist/src/transactor/transactor-source.d.ts.map +1 -0
  210. package/dist/src/transactor/transactor-source.js +62 -0
  211. package/dist/src/transactor/transactor-source.js.map +1 -0
  212. package/dist/src/transactor/transactor.d.ts +38 -0
  213. package/dist/src/transactor/transactor.d.ts.map +1 -0
  214. package/dist/src/transactor/transactor.js +2 -0
  215. package/dist/src/transactor/transactor.js.map +1 -0
  216. package/dist/src/transform/atomic.d.ts +8 -0
  217. package/dist/src/transform/atomic.d.ts.map +1 -0
  218. package/dist/src/transform/atomic.js +14 -0
  219. package/dist/src/transform/atomic.js.map +1 -0
  220. package/dist/src/transform/cache-source.d.ts +13 -0
  221. package/dist/src/transform/cache-source.d.ts.map +1 -0
  222. package/dist/src/transform/cache-source.js +52 -0
  223. package/dist/src/transform/cache-source.js.map +1 -0
  224. package/dist/src/transform/helpers.d.ts +25 -0
  225. package/dist/src/transform/helpers.d.ts.map +1 -0
  226. package/dist/src/transform/helpers.js +105 -0
  227. package/dist/src/transform/helpers.js.map +1 -0
  228. package/dist/src/transform/index.d.ts +6 -0
  229. package/dist/src/transform/index.d.ts.map +1 -0
  230. package/dist/src/transform/index.js +6 -0
  231. package/dist/src/transform/index.js.map +1 -0
  232. package/dist/src/transform/struct.d.ts +19 -0
  233. package/dist/src/transform/struct.d.ts.map +1 -0
  234. package/dist/src/transform/struct.js +2 -0
  235. package/dist/src/transform/struct.js.map +1 -0
  236. package/dist/src/transform/tracker.d.ts +22 -0
  237. package/dist/src/transform/tracker.d.ts.map +1 -0
  238. package/dist/src/transform/tracker.js +64 -0
  239. package/dist/src/transform/tracker.js.map +1 -0
  240. package/dist/src/utility/actor.d.ts +11 -0
  241. package/dist/src/utility/actor.d.ts.map +1 -0
  242. package/dist/src/utility/actor.js +39 -0
  243. package/dist/src/utility/actor.js.map +1 -0
  244. package/dist/src/utility/batch-coordinator.d.ts +56 -0
  245. package/dist/src/utility/batch-coordinator.d.ts.map +1 -0
  246. package/dist/src/utility/batch-coordinator.js +127 -0
  247. package/dist/src/utility/batch-coordinator.js.map +1 -0
  248. package/dist/src/utility/block-id-to-bytes.d.ts +3 -0
  249. package/dist/src/utility/block-id-to-bytes.d.ts.map +1 -0
  250. package/dist/src/utility/block-id-to-bytes.js +7 -0
  251. package/dist/src/utility/block-id-to-bytes.js.map +1 -0
  252. package/dist/src/utility/ensured.d.ts +3 -0
  253. package/dist/src/utility/ensured.d.ts.map +1 -0
  254. package/dist/src/utility/ensured.js +24 -0
  255. package/dist/src/utility/ensured.js.map +1 -0
  256. package/dist/src/utility/groupby.d.ts +8 -0
  257. package/dist/src/utility/groupby.d.ts.map +1 -0
  258. package/dist/src/utility/groupby.js +15 -0
  259. package/dist/src/utility/groupby.js.map +1 -0
  260. package/dist/src/utility/is-record-empty.d.ts +3 -0
  261. package/dist/src/utility/is-record-empty.d.ts.map +1 -0
  262. package/dist/src/utility/is-record-empty.js +7 -0
  263. package/dist/src/utility/is-record-empty.js.map +1 -0
  264. package/dist/src/utility/latches.d.ts +11 -0
  265. package/dist/src/utility/latches.d.ts.map +1 -0
  266. package/dist/src/utility/latches.js +36 -0
  267. package/dist/src/utility/latches.js.map +1 -0
  268. package/dist/src/utility/nameof.d.ts +3 -0
  269. package/dist/src/utility/nameof.d.ts.map +1 -0
  270. package/dist/src/utility/nameof.js +5 -0
  271. package/dist/src/utility/nameof.js.map +1 -0
  272. package/dist/src/utility/pending.d.ts +13 -0
  273. package/dist/src/utility/pending.d.ts.map +1 -0
  274. package/dist/src/utility/pending.js +37 -0
  275. package/dist/src/utility/pending.js.map +1 -0
  276. package/package.json +56 -0
  277. package/src/blocks/block-store.ts +13 -0
  278. package/src/blocks/block-types.ts +11 -0
  279. package/src/blocks/helpers.ts +13 -0
  280. package/src/blocks/index.ts +5 -0
  281. package/src/blocks/structs.ts +17 -0
  282. package/src/btree/btree.ts +804 -0
  283. package/src/btree/independent-trunk.ts +54 -0
  284. package/src/btree/index.ts +5 -0
  285. package/src/btree/key-range.ts +15 -0
  286. package/src/btree/keyset.ts +6 -0
  287. package/src/btree/nodes.ts +25 -0
  288. package/src/btree/path.ts +37 -0
  289. package/src/btree/tree-block.ts +11 -0
  290. package/src/btree/trunk.ts +14 -0
  291. package/src/chain/chain-nodes.ts +24 -0
  292. package/src/chain/chain.ts +324 -0
  293. package/src/chain/index.ts +2 -0
  294. package/src/cluster/i-cluster.ts +6 -0
  295. package/src/cluster/index.ts +2 -0
  296. package/src/cluster/structs.ts +46 -0
  297. package/src/collection/action.ts +31 -0
  298. package/src/collection/collection.ts +200 -0
  299. package/src/collection/index.ts +3 -0
  300. package/src/collection/struct.ts +20 -0
  301. package/src/collections/diary/diary.ts +43 -0
  302. package/src/collections/diary/index.ts +2 -0
  303. package/src/collections/diary/struct.ts +3 -0
  304. package/src/collections/index.ts +2 -0
  305. package/src/collections/tree/collection-trunk.ts +25 -0
  306. package/src/collections/tree/index.ts +2 -0
  307. package/src/collections/tree/readme.md +19 -0
  308. package/src/collections/tree/struct.ts +18 -0
  309. package/src/collections/tree/tree.ts +124 -0
  310. package/src/index.ts +17 -0
  311. package/src/log/index.ts +2 -0
  312. package/src/log/log.ts +155 -0
  313. package/src/log/struct.ts +40 -0
  314. package/src/network/i-key-network.ts +24 -0
  315. package/src/network/i-peer-network.ts +8 -0
  316. package/src/network/i-repo.ts +19 -0
  317. package/src/network/index.ts +5 -0
  318. package/src/network/repo-protocol.ts +12 -0
  319. package/src/network/struct.ts +137 -0
  320. package/src/transaction/actions-engine.ts +83 -0
  321. package/src/transaction/context.ts +103 -0
  322. package/src/transaction/coordinator.ts +583 -0
  323. package/src/transaction/index.ts +30 -0
  324. package/src/transaction/session.ts +182 -0
  325. package/src/transaction/transaction.ts +205 -0
  326. package/src/transaction/validator.ts +150 -0
  327. package/src/transactor/index.ts +4 -0
  328. package/src/transactor/network-transactor.ts +435 -0
  329. package/src/transactor/transactor-source.ts +65 -0
  330. package/src/transactor/transactor.ts +44 -0
  331. package/src/transform/atomic.ts +16 -0
  332. package/src/transform/cache-source.ts +57 -0
  333. package/src/transform/helpers.ts +117 -0
  334. package/src/transform/index.ts +5 -0
  335. package/src/transform/struct.ts +22 -0
  336. package/src/transform/tracker.ts +70 -0
  337. package/src/utility/actor.ts +62 -0
  338. package/src/utility/batch-coordinator.ts +174 -0
  339. package/src/utility/block-id-to-bytes.ts +8 -0
  340. package/src/utility/ensured.ts +32 -0
  341. package/src/utility/groupby.ts +18 -0
  342. package/src/utility/is-record-empty.ts +5 -0
  343. package/src/utility/latches.ts +42 -0
  344. package/src/utility/nameof.ts +7 -0
  345. package/src/utility/pending.ts +41 -0
@@ -0,0 +1,727 @@
1
+ import { Path, PathBranch } from "./index.js";
2
+ import { apply, get } from "../blocks/index.js";
3
+ import { TreeLeafBlockType, TreeBranchBlockType, entries$, nodes$, partitions$ } from "./nodes.js";
4
+ export const NodeCapacity = 64;
5
+ /**
6
+ * Represents a lightweight B+(ish)Tree (data at leaves, but no linked list of leaves).
7
+ * Allows for efficient storage and retrieval of data in a sorted manner.
8
+ * @template TEntry The type of entries stored in the B-tree.
9
+ * @template TKey The type of keys used for indexing the entries. This might be an element of TEntry, or TEntry itself.
10
+ */
11
+ export class BTree {
12
+ store;
13
+ trunk;
14
+ keyFromEntry;
15
+ compare;
16
+ _version = 0; // only for path invalidation
17
+ /**
18
+ * @param [compare=(a: TKey, b: TKey) => a < b ? -1 : a > b ? 1 : 0] a comparison function for keys. The default uses < and > operators.
19
+ * @param [keyFromEntry=(entry: TEntry) => entry as unknown as TKey] a function to extract the key from an entry. The default assumes the key is the entry itself.
20
+ */
21
+ constructor(store, trunk, keyFromEntry = (entry) => entry, compare = (a, b) => a < b ? -1 : a > b ? 1 : 0) {
22
+ this.store = store;
23
+ this.trunk = trunk;
24
+ this.keyFromEntry = keyFromEntry;
25
+ this.compare = compare;
26
+ }
27
+ static createRoot(store) {
28
+ return newLeafNode(store, []);
29
+ }
30
+ static create(store, createTrunk, keyFromEntry = (entry) => entry, compare = (a, b) => a < b ? -1 : a > b ? 1 : 0, newId) {
31
+ const root = BTree.createRoot(store);
32
+ store.insert(root);
33
+ const trunk = createTrunk(store, root.header.id, newId);
34
+ return new BTree(store, trunk, keyFromEntry, compare);
35
+ }
36
+ /** @returns a path to the first entry (on = false if no entries) */
37
+ async first() {
38
+ return await this.getFirst(await this.trunk.get());
39
+ }
40
+ /** @returns a path to the last entry (on = false if no entries) */
41
+ async last() {
42
+ return await this.getLast(await this.trunk.get());
43
+ }
44
+ /** Attempts to find the given key
45
+ * @returns Path to the key or the "crack" before it. If `on` is true on the resulting path, the key was found.
46
+ * If `on` is false, next() and prior() can attempt to move to the nearest match. */
47
+ async find(key) {
48
+ return await this.getPath(await this.trunk.get(), key);
49
+ }
50
+ /** Retrieves the entry for the given key.
51
+ * Use find instead for a path to the key, the nearest match, or as a basis for navigation.
52
+ * @returns the entry for the given key if found; undefined otherwise. */
53
+ async get(key) {
54
+ return this.at(await this.find(key));
55
+ }
56
+ /** @returns the entry for the given path if on an entry; undefined otherwise. */
57
+ at(path) {
58
+ this.validatePath(path);
59
+ return path.on ? this.getEntry(path) : undefined;
60
+ }
61
+ /** Iterates based on the given range
62
+ * WARNING: mutation during iteration will result in an exception
63
+ */
64
+ async *range(range) {
65
+ const startPath = range.first
66
+ ? await this.findFirst(range)
67
+ : (range.isAscending ? await this.first() : await this.last());
68
+ const endPath = range.last
69
+ ? await this.findLast(range)
70
+ : (range.isAscending ? await this.last() : await this.first());
71
+ // If the tree is empty or endPath is not on an entry, return early
72
+ if (!endPath.on) {
73
+ return;
74
+ }
75
+ const endKey = this.keyFromPath(endPath);
76
+ const iterable = range.isAscending
77
+ ? this.internalAscending(startPath)
78
+ : this.internalDescending(startPath);
79
+ const iter = iterable[Symbol.asyncIterator]();
80
+ const ascendingFactor = range.isAscending ? 1 : -1;
81
+ for await (let path of iter) {
82
+ if (!path.on || this.compare(this.keyFromPath(path), endKey) * ascendingFactor > 0) {
83
+ break;
84
+ }
85
+ yield path;
86
+ }
87
+ }
88
+ /** @returns true if the given path remains valid; false if the tree has been mutated, invalidating the path. */
89
+ isValid(path) {
90
+ return path.version === this._version;
91
+ }
92
+ /**
93
+ * Adds a value to the tree. Be sure to check the result, as the tree does not allow duplicate keys.
94
+ * Added entries are frozen to ensure immutability
95
+ * @returns path to the new (on = true) or conflicting (on = false) row. */
96
+ async insert(entry) {
97
+ Object.freeze(entry); // Ensure immutability
98
+ const path = await this.internalInsert(entry);
99
+ if (path.on) {
100
+ path.version = ++this._version;
101
+ }
102
+ return path;
103
+ }
104
+ /** Updates the entry at the given path to the given value. Deletes and inserts if the key changes.
105
+ * @returns path to resulting entry and whether it was an update (as opposed to an insert).
106
+ * * on = true if update/insert succeeded.
107
+ * * wasUpdate = true if updated; false if inserted.
108
+ * * Returned path is on entry
109
+ * * on = false if update/insert failed.
110
+ * * wasUpdate = true, given path is not on an entry
111
+ * * else newEntry's new key already present; returned path is "near" existing entry */
112
+ async updateAt(path, newEntry) {
113
+ this.validatePath(path);
114
+ if (path.on) {
115
+ Object.freeze(newEntry);
116
+ }
117
+ const result = await this.internalUpdate(path, newEntry);
118
+ if (result[0].on) {
119
+ result[0].version = ++this._version;
120
+ }
121
+ return result;
122
+ }
123
+ /** Inserts the entry if it doesn't exist, or updates it if it does.
124
+ * The entry is frozen to ensure immutability.
125
+ * @returns path to the new entry. on = true if existing; on = false if new. */
126
+ async upsert(entry) {
127
+ const path = await this.find(this.keyFromEntry(entry));
128
+ Object.freeze(entry);
129
+ if (path.on) {
130
+ this.updateEntry(path, entry);
131
+ }
132
+ else {
133
+ await this.internalInsertAt(path, entry);
134
+ }
135
+ path.version = ++this._version;
136
+ return path;
137
+ }
138
+ /** Inserts or updates depending on the existence of the given key, using callbacks to generate the new value.
139
+ * @param newEntry the new entry to insert if the key doesn't exist.
140
+ * @param getUpdated a callback to generate an updated entry if the key does exist. WARNING: mutation in this callback will cause merge to error.
141
+ * @returns path to new entry and whether an update or insert attempted.
142
+ * If getUpdated callback returns a row that is already present, the resulting path will not be on. */
143
+ async merge(newEntry, getUpdated) {
144
+ const newKey = await this.keyFromEntry(newEntry);
145
+ const path = await this.find(newKey);
146
+ if (path.on) {
147
+ const result = await this.updateAt(path, getUpdated(this.getEntry(path))); // Don't use internalUpdate - need to freeze and check for mutation
148
+ if (result[0].on) {
149
+ result[0].version = ++this._version;
150
+ }
151
+ return result;
152
+ }
153
+ else {
154
+ await this.internalInsertAt(path, Object.freeze(newEntry));
155
+ path.on = true;
156
+ path.version = ++this._version;
157
+ return [path, false];
158
+ }
159
+ }
160
+ /** Deletes the entry at the given path.
161
+ * The on property of the path will be cleared.
162
+ * @returns true if the delete succeeded (the key was found); false otherwise.
163
+ */
164
+ async deleteAt(path) {
165
+ this.validatePath(path);
166
+ const result = await this.internalDelete(path);
167
+ if (result) {
168
+ ++this._version;
169
+ }
170
+ return result;
171
+ }
172
+ async drop() {
173
+ const root = await this.trunk.get();
174
+ for await (const id of this.nodeIds(root)) {
175
+ this.store.delete(id);
176
+ }
177
+ }
178
+ /** Iterates forward starting from the path location (inclusive) to the end.
179
+ * WARNING: mutation during iteration will result in an exception.
180
+ */
181
+ ascending(path) {
182
+ this.validatePath(path);
183
+ return this.internalAscending(path.clone());
184
+ }
185
+ /** Iterates backward starting from the path location (inclusive) to the end.
186
+ * WARNING: mutation during iteration will result in an exception
187
+ */
188
+ descending(path) {
189
+ this.validatePath(path);
190
+ return this.internalDescending(path.clone());
191
+ }
192
+ /** Computed (not stored) count. Computes the sum using leaf-node lengths. O(n/af) where af is average fill.
193
+ * @param from if provided, the count will start from the given path (inclusive). If ascending is false,
194
+ * the count will start from the end of the tree. Ascending is true by default.
195
+ */
196
+ async getCount(from) {
197
+ let result = 0;
198
+ const path = from ? from.path.clone() : await this.first();
199
+ if (from?.ascending ?? true) {
200
+ while (path.on) {
201
+ result += path.leafNode.entries.length - path.leafIndex;
202
+ path.leafIndex = path.leafNode.entries.length - 1;
203
+ await this.internalNext(path);
204
+ }
205
+ }
206
+ else {
207
+ while (path.on) {
208
+ result += path.leafIndex + 1;
209
+ path.leafIndex = 0;
210
+ await this.internalPrior(path);
211
+ }
212
+ }
213
+ return result;
214
+ }
215
+ /** @returns a path one step forward. on will be true if the path hasn't hit the end. */
216
+ async next(path) {
217
+ const newPath = path.clone();
218
+ await this.moveNext(newPath);
219
+ return newPath;
220
+ }
221
+ /** Attempts to advance the given path one step forward. (mutates the path) */
222
+ async moveNext(path) {
223
+ this.validatePath(path);
224
+ await this.internalNext(path);
225
+ }
226
+ /** @returns a path one step backward. on will be true if the path hasn't hit the end. */
227
+ async prior(path) {
228
+ const newPath = path.clone();
229
+ this.movePrior(newPath);
230
+ return newPath;
231
+ }
232
+ /** Attempts to advance the given path one step backwards. (mutates the path) */
233
+ async movePrior(path) {
234
+ this.validatePath(path);
235
+ await this.internalPrior(path);
236
+ }
237
+ /** @remarks Assumes the path is "on" */
238
+ keyFromPath(path) {
239
+ return this.keyFromEntry(path.leafNode.entries[path.leafIndex]);
240
+ }
241
+ async *internalAscending(path) {
242
+ this.validatePath(path);
243
+ while (path.on) {
244
+ yield path;
245
+ await this.moveNext(path); // Not internal - re-check after yield
246
+ }
247
+ }
248
+ async *internalDescending(path) {
249
+ this.validatePath(path);
250
+ while (path.on) {
251
+ yield path;
252
+ await this.movePrior(path); // Not internal - re-check after yield
253
+ }
254
+ }
255
+ async findFirst(range) {
256
+ const startPath = await this.find(range.first.key);
257
+ if (!startPath.on || (range.first && !range.first.inclusive)) {
258
+ if (range.isAscending) {
259
+ await this.internalNext(startPath);
260
+ }
261
+ else {
262
+ await this.internalPrior(startPath);
263
+ }
264
+ }
265
+ return startPath;
266
+ }
267
+ async findLast(range) {
268
+ const endPath = await this.find(range.last.key);
269
+ if (!endPath.on || (range.last && !range.last.inclusive)) {
270
+ if (range.isAscending) {
271
+ await this.internalPrior(endPath);
272
+ }
273
+ else {
274
+ await this.internalNext(endPath);
275
+ }
276
+ }
277
+ return endPath;
278
+ }
279
+ async getPath(node, key) {
280
+ if (node.header.type === TreeLeafBlockType) {
281
+ const leaf = node;
282
+ const [on, index] = this.indexOfEntry(leaf.entries, key);
283
+ return new Path([], leaf, index, on, this._version);
284
+ }
285
+ else {
286
+ const branch = node;
287
+ const index = this.indexOfKey(branch.partitions, key);
288
+ const path = await this.getPath(await get(this.store, branch.nodes[index]), key);
289
+ path.branches.unshift(new PathBranch(branch, index));
290
+ return path;
291
+ }
292
+ }
293
+ indexOfEntry(entries, key) {
294
+ let lo = 0;
295
+ let hi = entries.length - 1;
296
+ let split = 0;
297
+ let result = -1;
298
+ while (lo <= hi) {
299
+ split = (lo + hi) >>> 1;
300
+ result = this.compare(key, this.keyFromEntry(entries[split]));
301
+ if (result === 0)
302
+ return [true, split];
303
+ else if (result < 0)
304
+ hi = split - 1;
305
+ else
306
+ lo = split + 1;
307
+ }
308
+ return [false, lo];
309
+ }
310
+ indexOfKey(keys, key) {
311
+ let lo = 0;
312
+ let hi = keys.length - 1;
313
+ let split = 0;
314
+ let result = -1;
315
+ while (lo <= hi) {
316
+ split = (lo + hi) >>> 1;
317
+ result = this.compare(key, keys[split]);
318
+ if (result === 0)
319
+ return split + 1; // +1 because taking right partition
320
+ else if (result < 0)
321
+ hi = split - 1;
322
+ else
323
+ lo = split + 1;
324
+ }
325
+ return lo;
326
+ }
327
+ async internalNext(path) {
328
+ if (!path.on) { // Attempt to move off of crack
329
+ path.on = path.branches.every(branch => branch.index >= 0 && branch.index < branch.node.nodes.length)
330
+ && path.leafIndex >= 0 && path.leafIndex < path.leafNode.entries.length;
331
+ if (path.on) {
332
+ return;
333
+ }
334
+ }
335
+ else if (path.leafIndex >= path.leafNode.entries.length - 1) {
336
+ let popCount = 0;
337
+ let found = false;
338
+ const last = path.branches.length - 1;
339
+ while (popCount <= last && !found) {
340
+ const branch = path.branches[last - popCount];
341
+ if (branch.index === branch.node.partitions.length) // last node in branch
342
+ ++popCount;
343
+ else
344
+ found = true;
345
+ }
346
+ if (!found) {
347
+ path.leafIndex = path.leafNode.entries.length; // after last row = end crack
348
+ path.on = false;
349
+ }
350
+ else {
351
+ path.branches.splice(-popCount, popCount);
352
+ const branch = path.branches.at(-1);
353
+ ++branch.index;
354
+ this.moveToFirst(await get(this.store, branch.node.nodes[branch.index]), path);
355
+ }
356
+ }
357
+ else {
358
+ ++path.leafIndex;
359
+ path.on = true;
360
+ }
361
+ }
362
+ async internalPrior(path) {
363
+ this.validatePath(path);
364
+ if (path.leafIndex <= 0) {
365
+ let popCount = 0;
366
+ let opening = false;
367
+ const last = path.branches.length - 1;
368
+ while (popCount <= last && !opening) {
369
+ const branch = path.branches[last - popCount];
370
+ if (branch.index === 0) // first node in branch
371
+ ++popCount;
372
+ else
373
+ opening = true;
374
+ }
375
+ if (!opening) {
376
+ path.leafIndex = 0;
377
+ path.on = false;
378
+ }
379
+ else {
380
+ path.branches.splice(-popCount, popCount);
381
+ const branch = path.branches.at(-1);
382
+ --branch.index;
383
+ await this.moveToLast(await get(this.store, branch.node.nodes[branch.index]), path);
384
+ }
385
+ }
386
+ else {
387
+ --path.leafIndex;
388
+ path.on = true;
389
+ }
390
+ }
391
+ async internalUpdate(path, newEntry) {
392
+ if (path.on) {
393
+ const oldKey = this.keyFromPath(path);
394
+ const newKey = this.keyFromEntry(newEntry);
395
+ if (this.compare(oldKey, newKey) !== 0) { // if key changed, delete and re-insert
396
+ let newPath = await this.internalInsert(newEntry);
397
+ if (newPath.on) { // insert succeeded
398
+ this.internalDelete(await this.find(oldKey)); // Re-find - the prior insert invalidated the path
399
+ newPath = await this.find(newKey); // Re-find- delete invalidated path
400
+ }
401
+ return [newPath, false];
402
+ }
403
+ else {
404
+ this.updateEntry(path, newEntry);
405
+ }
406
+ }
407
+ return [path, true];
408
+ }
409
+ async internalDelete(path) {
410
+ if (path.on) {
411
+ apply(this.store, path.leafNode, [entries$, path.leafIndex, 1, []]);
412
+ if (path.branches.length > 0) { // Only worry about underflows, balancing, etc. if not root
413
+ if (path.leafIndex === 0) { // If we deleted index 0, update branches with new key
414
+ const pathBranch = path.branches.at(-1);
415
+ this.updatePartition(pathBranch.index, path, path.branches.length - 1, this.keyFromPath(path));
416
+ }
417
+ const newRoot = await this.rebalanceLeaf(path, path.branches.length);
418
+ if (newRoot) {
419
+ await this.trunk.set(newRoot);
420
+ }
421
+ }
422
+ path.on = false;
423
+ return true;
424
+ }
425
+ else {
426
+ return false;
427
+ }
428
+ }
429
+ async internalInsert(entry) {
430
+ const path = await this.find(this.keyFromEntry(entry));
431
+ if (path.on) {
432
+ path.on = false;
433
+ return path;
434
+ }
435
+ await this.internalInsertAt(path, entry);
436
+ path.on = true;
437
+ return path;
438
+ }
439
+ async internalInsertAt(path, entry) {
440
+ let split = this.leafInsert(path, entry);
441
+ let branchIndex = path.branches.length - 1;
442
+ while (split && branchIndex >= 0) {
443
+ split = await this.branchInsert(path, branchIndex, split);
444
+ --branchIndex;
445
+ }
446
+ if (split) {
447
+ const newBranch = newBranchNode(this.store, [split.key], [await this.trunk.getId(), split.right.header.id]);
448
+ await this.store.insert(newBranch);
449
+ await this.trunk.set(newBranch);
450
+ path.branches.unshift(new PathBranch(newBranch, split.indexDelta));
451
+ }
452
+ }
453
+ /** Starting from the given node, recursively working down to the leaf, build onto the path based on the beginning-most entry. */
454
+ async moveToFirst(node, path) {
455
+ if (node.header.type === TreeLeafBlockType) {
456
+ const leaf = node;
457
+ path.leafNode = leaf;
458
+ path.leafIndex = 0;
459
+ path.on = leaf.entries.length > 0;
460
+ }
461
+ else {
462
+ path.branches.push(new PathBranch(node, 0));
463
+ await this.moveToFirst(await get(this.store, node.nodes[0]), path);
464
+ }
465
+ }
466
+ /** Starting from the given node, recursively working down to the leaf, build onto the path based on the end-most entry. */
467
+ async moveToLast(node, path) {
468
+ if (node.header.type === TreeLeafBlockType) {
469
+ const leaf = node;
470
+ const count = leaf.entries.length;
471
+ path.leafNode = leaf;
472
+ path.on = count > 0;
473
+ path.leafIndex = count > 0 ? count - 1 : 0;
474
+ }
475
+ else {
476
+ const branch = node;
477
+ const pathBranch = new PathBranch(branch, branch.partitions.length);
478
+ path.branches.push(pathBranch);
479
+ await this.moveToLast(await get(this.store, branch.nodes[pathBranch.index]), path);
480
+ }
481
+ }
482
+ /** Construct a path based on the first-most edge of the given. */
483
+ async getFirst(node) {
484
+ if (node.header.type === TreeLeafBlockType) {
485
+ const leaf = node;
486
+ return new Path([], leaf, 0, leaf.entries.length > 0, this._version);
487
+ }
488
+ else {
489
+ const branch = node;
490
+ const path = await this.getFirst(await get(this.store, branch.nodes[0]));
491
+ path.branches.unshift(new PathBranch(branch, 0));
492
+ return path;
493
+ }
494
+ }
495
+ /** Construct a path based on the last-most edge of the given node */
496
+ async getLast(node) {
497
+ if (node.header.type === TreeLeafBlockType) {
498
+ const leaf = node;
499
+ const count = leaf.entries.length;
500
+ return new Path([], leaf, count > 0 ? count - 1 : 0, count > 0, this._version);
501
+ }
502
+ else {
503
+ const branch = node;
504
+ const index = branch.nodes.length - 1;
505
+ const path = await this.getLast(await get(this.store, branch.nodes[index]));
506
+ path.branches.unshift(new PathBranch(branch, index));
507
+ return path;
508
+ }
509
+ }
510
+ leafInsert(path, entry) {
511
+ const { leafNode: leaf, leafIndex: index } = path;
512
+ if (leaf.entries.length < NodeCapacity) { // No split needed
513
+ apply(this.store, leaf, [entries$, index, 0, [entry]]);
514
+ return undefined;
515
+ }
516
+ // Full. Split needed
517
+ const midIndex = (leaf.entries.length + 1) >>> 1;
518
+ const newEntries = leaf.entries.slice(midIndex);
519
+ // New node
520
+ if (index >= midIndex) { // Put the new entry directly rather than log an insert
521
+ newEntries.splice(index - midIndex, 0, entry);
522
+ }
523
+ const newLeaf = newLeafNode(this.store, newEntries);
524
+ this.store.insert(newLeaf);
525
+ // Delete entries from old node
526
+ apply(this.store, leaf, [entries$, midIndex, leaf.entries.length - midIndex, []]);
527
+ if (index < midIndex) { // Insert new entry into old node
528
+ apply(this.store, leaf, [entries$, index, 0, [entry]]);
529
+ }
530
+ else {
531
+ path.leafNode = newLeaf;
532
+ path.leafIndex -= midIndex;
533
+ }
534
+ return new Split(this.keyFromEntry(newEntries[0]), newLeaf, index < midIndex ? 0 : 1);
535
+ }
536
+ async branchInsert(path, branchIndex, split) {
537
+ const pathBranch = path.branches[branchIndex];
538
+ const { index: splitIndex, node } = pathBranch;
539
+ pathBranch.index += split.indexDelta;
540
+ if (node.nodes.length < NodeCapacity) { // no split needed
541
+ apply(this.store, node, [partitions$, splitIndex, 0, [split.key]]);
542
+ apply(this.store, node, [nodes$, splitIndex + 1, 0, [split.right.header.id]]);
543
+ return undefined;
544
+ }
545
+ // Full. Split needed
546
+ const midIndex = (node.nodes.length + 1) >>> 1;
547
+ const newPartitions = node.partitions.slice(midIndex);
548
+ const newNodes = node.nodes.slice(midIndex);
549
+ const delta = pathBranch.index < midIndex ? 0 : 1;
550
+ // New node
551
+ if (delta) { // If split is on new, add it before the split to avoid logging an insert
552
+ pathBranch.index -= midIndex;
553
+ newPartitions.splice(pathBranch.index, 0, split.key);
554
+ newNodes.splice(pathBranch.index + 1, 0, split.right.header.id);
555
+ }
556
+ const newBranch = newBranchNode(this.store, newPartitions, newNodes);
557
+ // Delete partitions and nodes
558
+ const newPartition = node.partitions[midIndex - 1];
559
+ apply(this.store, node, [partitions$, midIndex - 1, newPartitions.length + 1, []]);
560
+ apply(this.store, node, [nodes$, midIndex, newNodes.length, []]);
561
+ if (pathBranch.index < midIndex) { // Insert into old node
562
+ apply(this.store, node, [partitions$, splitIndex, 0, [split.key]]);
563
+ apply(this.store, node, [nodes$, splitIndex + 1, 0, [split.right.header.id]]);
564
+ }
565
+ return new Split(newPartition, newBranch, delta);
566
+ }
567
+ async rebalanceLeaf(path, depth) {
568
+ if (depth === 0 || path.leafNode.entries.length >= (NodeCapacity >>> 1)) {
569
+ return undefined;
570
+ }
571
+ const leaf = path.leafNode;
572
+ const parent = path.branches.at(depth - 1);
573
+ const pIndex = parent.index;
574
+ const pNode = parent.node;
575
+ const rightSibId = pNode.nodes[pIndex + 1];
576
+ const rightSib = rightSibId ? (await get(this.store, rightSibId)) : undefined;
577
+ if (rightSib && rightSib.entries.length > (NodeCapacity >>> 1)) { // Attempt to borrow from right sibling
578
+ const entry = rightSib.entries[0];
579
+ apply(this.store, rightSib, [entries$, 0, 1, []]);
580
+ apply(this.store, leaf, [entries$, leaf.entries.length, 0, [entry]]);
581
+ this.updatePartition(pIndex + 1, path, depth - 1, this.keyFromEntry(entry));
582
+ return undefined;
583
+ }
584
+ const leftSibId = pNode.nodes[pIndex - 1];
585
+ const leftSib = leftSibId ? (await get(this.store, leftSibId)) : undefined;
586
+ if (leftSib && leftSib.entries.length > (NodeCapacity >>> 1)) { // Attempt to borrow from left sibling
587
+ const entry = leftSib.entries[leftSib.entries.length - 1];
588
+ apply(this.store, leftSib, [entries$, leftSib.entries.length - 1, 1, []]);
589
+ apply(this.store, leaf, [entries$, 0, 0, [entry]]);
590
+ this.updatePartition(pIndex, path, depth - 1, this.keyFromEntry(entry));
591
+ path.leafIndex += 1;
592
+ return undefined;
593
+ }
594
+ if (rightSib && rightSib.entries.length + leaf.entries.length <= NodeCapacity) { // Attempt to merge right sibling into leaf (right sib deleted)
595
+ apply(this.store, leaf, [entries$, leaf.entries.length, 0, rightSib.entries]);
596
+ this.deletePartition(pNode, pIndex);
597
+ if (pIndex === 0) { // 0th node of parent, update parent key
598
+ this.updatePartition(pIndex, path, depth - 1, this.keyFromEntry(leaf.entries[0]));
599
+ }
600
+ this.store.delete(rightSib.header.id);
601
+ return await this.rebalanceBranch(path, depth - 1);
602
+ }
603
+ if (leftSib && leftSib.entries.length + leaf.entries.length <= NodeCapacity) { // Attempt to merge into left sibling (leaf deleted)
604
+ path.leafNode = leftSib;
605
+ path.leafIndex += leftSib.entries.length;
606
+ apply(this.store, leftSib, [entries$, leftSib.entries.length, 0, leaf.entries]);
607
+ this.deletePartition(pNode, pIndex - 1);
608
+ this.store.delete(leaf.header.id);
609
+ return await this.rebalanceBranch(path, depth - 1);
610
+ }
611
+ }
612
+ async rebalanceBranch(path, depth) {
613
+ const pathBranch = path.branches[depth];
614
+ const branch = pathBranch.node;
615
+ if (depth === 0 && branch.partitions.length === 0) { // last node... collapse child into root
616
+ return path.branches[depth + 1]?.node ?? path.leafNode;
617
+ }
618
+ if (depth === 0 || (branch.nodes.length >= NodeCapacity << 1)) {
619
+ return undefined;
620
+ }
621
+ const parent = path.branches.at(depth - 1);
622
+ const pIndex = parent.index;
623
+ const pNode = parent.node;
624
+ const rightSibId = pNode.nodes[pIndex + 1];
625
+ const rightSib = rightSibId ? (await get(this.store, rightSibId)) : undefined;
626
+ if (rightSib && rightSib.nodes.length > (NodeCapacity >>> 1)) { // Attempt to borrow from right sibling
627
+ const node = rightSib.nodes[0];
628
+ const rightKey = rightSib.partitions[0];
629
+ this.insertPartition(branch, branch.partitions.length, pNode.partitions[pIndex], node);
630
+ this.deletePartition(rightSib, 0, 0);
631
+ this.updatePartition(pIndex + 1, path, depth - 1, rightKey);
632
+ return undefined;
633
+ }
634
+ const leftSibId = pNode.nodes[pIndex - 1];
635
+ const leftSib = leftSibId ? (await get(this.store, leftSibId)) : undefined;
636
+ if (leftSib && leftSib.nodes.length > (NodeCapacity >>> 1)) { // Attempt to borrow from left sibling
637
+ const node = leftSib.nodes[leftSib.nodes.length - 1];
638
+ const pKey = leftSib.partitions[leftSib.partitions.length - 1];
639
+ this.insertPartition(branch, 0, pNode.partitions[pIndex - 1], node, 0);
640
+ this.deletePartition(leftSib, leftSib.partitions.length - 1);
641
+ pathBranch.index += 1;
642
+ this.updatePartition(pIndex, path, depth - 1, pKey);
643
+ return undefined;
644
+ }
645
+ if (rightSib && rightSib.nodes.length + branch.nodes.length <= NodeCapacity) { // Attempt to merge right sibling into self
646
+ const pKey = pNode.partitions[pIndex];
647
+ this.deletePartition(pNode, pIndex);
648
+ apply(this.store, branch, [partitions$, branch.partitions.length, 0, [pKey]]);
649
+ apply(this.store, branch, [partitions$, branch.partitions.length, 0, rightSib.partitions]);
650
+ apply(this.store, branch, [nodes$, branch.nodes.length, 0, rightSib.nodes]);
651
+ if (pIndex === 0 && pNode.partitions.length > 0) { // if parent is left edge, new right sibling is now the first partition
652
+ this.updatePartition(pIndex, path, depth - 1, pNode.partitions[0]);
653
+ }
654
+ this.store.delete(rightSib.header.id);
655
+ return this.rebalanceBranch(path, depth - 1);
656
+ }
657
+ if (leftSib && leftSib.nodes.length + branch.nodes.length <= NodeCapacity) { // Attempt to merge self into left sibling
658
+ const pKey = pNode.partitions[pIndex - 1];
659
+ this.deletePartition(pNode, pIndex - 1);
660
+ apply(this.store, leftSib, [partitions$, leftSib.partitions.length, 0, [pKey]]);
661
+ apply(this.store, leftSib, [partitions$, leftSib.partitions.length, 0, branch.partitions]);
662
+ apply(this.store, leftSib, [nodes$, leftSib.nodes.length, 0, branch.nodes]);
663
+ pathBranch.node = leftSib;
664
+ pathBranch.index += leftSib.nodes.length;
665
+ this.store.delete(branch.header.id);
666
+ return this.rebalanceBranch(path, depth - 1);
667
+ }
668
+ }
669
+ updatePartition(nodeIndex, path, depth, newKey) {
670
+ const pathBranch = path.branches[depth];
671
+ if (nodeIndex > 0) { // Only affects this branch; just update the partition key
672
+ apply(this.store, pathBranch.node, [partitions$, nodeIndex - 1, 1, [newKey]]);
673
+ }
674
+ else if (depth !== 0) {
675
+ this.updatePartition(path.branches[depth - 1].index, path, depth - 1, newKey);
676
+ }
677
+ }
678
+ insertPartition(branch, index, key, node, nodeOffset = 1) {
679
+ apply(this.store, branch, [partitions$, index, 0, [key]]);
680
+ apply(this.store, branch, [nodes$, index + nodeOffset, 0, [node]]);
681
+ }
682
+ deletePartition(branch, index, nodeOffset = 1) {
683
+ apply(this.store, branch, [partitions$, index, 1, []]);
684
+ apply(this.store, branch, [nodes$, index + nodeOffset, 1, []]);
685
+ }
686
+ validatePath(path) {
687
+ if (!this.isValid(path)) {
688
+ throw new Error("Path is invalid due to mutation of the tree");
689
+ }
690
+ }
691
+ /** Iterates every node ID below and including the given node. */
692
+ async *nodeIds(node) {
693
+ // TODO: This would be much more efficient if we avoided iterating into leaf nodes
694
+ if (node.header.type === TreeBranchBlockType) {
695
+ const subNodes = await Promise.all(node.nodes.map(id => get(this.store, id)));
696
+ for (let subNode of subNodes) {
697
+ yield* this.nodeIds(subNode);
698
+ }
699
+ }
700
+ yield node.header.id;
701
+ }
702
+ getEntry(path) {
703
+ return path.leafNode.entries[path.leafIndex];
704
+ }
705
+ updateEntry(path, entry) {
706
+ apply(this.store, path.leafNode, [entries$, path.leafIndex, 1, [entry]]);
707
+ }
708
+ }
709
+ class Split {
710
+ key;
711
+ right;
712
+ indexDelta;
713
+ constructor(key, right, indexDelta) {
714
+ this.key = key;
715
+ this.right = right;
716
+ this.indexDelta = indexDelta;
717
+ }
718
+ }
719
+ function newLeafNode(store, entries) {
720
+ const header = store.createBlockHeader(TreeLeafBlockType);
721
+ return { header, entries };
722
+ }
723
+ function newBranchNode(store, partitions, nodes) {
724
+ const header = store.createBlockHeader(TreeBranchBlockType);
725
+ return { header, partitions, nodes };
726
+ }
727
+ //# sourceMappingURL=btree.js.map