@connecttomahdi/rxdb 17.0.0-beta.17 → 17.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 (379) hide show
  1. package/AGENTS.md +4 -0
  2. package/CHANGELOG.md +47 -4
  3. package/CLAUDE.md +2 -0
  4. package/dist/cjs/change-event-buffer.js +2 -1
  5. package/dist/cjs/change-event-buffer.js.map +1 -1
  6. package/dist/cjs/custom-index.js +85 -12
  7. package/dist/cjs/custom-index.js.map +1 -1
  8. package/dist/cjs/doc-cache.js +117 -35
  9. package/dist/cjs/doc-cache.js.map +1 -1
  10. package/dist/cjs/event-reduce.js +10 -1
  11. package/dist/cjs/event-reduce.js.map +1 -1
  12. package/dist/cjs/plugin-helpers.js +16 -0
  13. package/dist/cjs/plugin-helpers.js.map +1 -1
  14. package/dist/cjs/plugins/attachments/index.js +3 -3
  15. package/dist/cjs/plugins/attachments/index.js.map +1 -1
  16. package/dist/cjs/plugins/cleanup/cleanup.js +5 -3
  17. package/dist/cjs/plugins/cleanup/cleanup.js.map +1 -1
  18. package/dist/cjs/plugins/crdt/index.js +52 -0
  19. package/dist/cjs/plugins/crdt/index.js.map +1 -1
  20. package/dist/cjs/plugins/dev-mode/check-query.js +7 -1
  21. package/dist/cjs/plugins/dev-mode/check-query.js.map +1 -1
  22. package/dist/cjs/plugins/dev-mode/check-schema.js +2 -1
  23. package/dist/cjs/plugins/dev-mode/check-schema.js.map +1 -1
  24. package/dist/cjs/plugins/dev-mode/error-messages.js +43 -5
  25. package/dist/cjs/plugins/dev-mode/error-messages.js.map +1 -1
  26. package/dist/cjs/plugins/encryption-crypto-js/index.js +22 -6
  27. package/dist/cjs/plugins/encryption-crypto-js/index.js.map +1 -1
  28. package/dist/cjs/plugins/leader-election/index.js +5 -5
  29. package/dist/cjs/plugins/leader-election/index.js.map +1 -1
  30. package/dist/cjs/plugins/local-documents/local-documents.js +20 -13
  31. package/dist/cjs/plugins/local-documents/local-documents.js.map +1 -1
  32. package/dist/cjs/plugins/migration-schema/migration-helpers.js +3 -0
  33. package/dist/cjs/plugins/migration-schema/migration-helpers.js.map +1 -1
  34. package/dist/cjs/plugins/migration-schema/rx-migration-state.js +1 -1
  35. package/dist/cjs/plugins/migration-schema/rx-migration-state.js.map +1 -1
  36. package/dist/cjs/plugins/pipeline/rx-pipeline.js +5 -1
  37. package/dist/cjs/plugins/pipeline/rx-pipeline.js.map +1 -1
  38. package/dist/cjs/plugins/query-builder/mquery/nosql-query-builder.js +4 -2
  39. package/dist/cjs/plugins/query-builder/mquery/nosql-query-builder.js.map +1 -1
  40. package/dist/cjs/plugins/replication/index.js +40 -2
  41. package/dist/cjs/plugins/replication/index.js.map +1 -1
  42. package/dist/cjs/plugins/replication-google-drive/document-handling.js +17 -6
  43. package/dist/cjs/plugins/replication-google-drive/document-handling.js.map +1 -1
  44. package/dist/cjs/plugins/replication-google-drive/google-drive-helper.js +1 -1
  45. package/dist/cjs/plugins/replication-google-drive/google-drive-helper.js.map +1 -1
  46. package/dist/cjs/plugins/replication-google-drive/google-drive-types.js.map +1 -1
  47. package/dist/cjs/plugins/replication-google-drive/signaling.js +4 -1
  48. package/dist/cjs/plugins/replication-google-drive/signaling.js.map +1 -1
  49. package/dist/cjs/plugins/replication-google-drive/upstream.js +7 -4
  50. package/dist/cjs/plugins/replication-google-drive/upstream.js.map +1 -1
  51. package/dist/cjs/plugins/replication-microsoft-onedrive/signaling.js +4 -1
  52. package/dist/cjs/plugins/replication-microsoft-onedrive/signaling.js.map +1 -1
  53. package/dist/cjs/plugins/state/rx-state.js +14 -3
  54. package/dist/cjs/plugins/state/rx-state.js.map +1 -1
  55. package/dist/cjs/plugins/storage-dexie/rx-storage-instance-dexie.js +10 -17
  56. package/dist/cjs/plugins/storage-dexie/rx-storage-instance-dexie.js.map +1 -1
  57. package/dist/cjs/plugins/storage-memory/binary-search-bounds.js +112 -40
  58. package/dist/cjs/plugins/storage-memory/binary-search-bounds.js.map +1 -1
  59. package/dist/cjs/plugins/storage-memory/memory-helper.js +127 -40
  60. package/dist/cjs/plugins/storage-memory/memory-helper.js.map +1 -1
  61. package/dist/cjs/plugins/storage-memory/memory-indexes.js +1 -0
  62. package/dist/cjs/plugins/storage-memory/memory-indexes.js.map +1 -1
  63. package/dist/cjs/plugins/storage-memory/memory-types.js.map +1 -1
  64. package/dist/cjs/plugins/storage-memory/rx-storage-instance-memory.js +97 -37
  65. package/dist/cjs/plugins/storage-memory/rx-storage-instance-memory.js.map +1 -1
  66. package/dist/cjs/plugins/storage-mongodb/mongodb-helper.js +42 -1
  67. package/dist/cjs/plugins/storage-mongodb/mongodb-helper.js.map +1 -1
  68. package/dist/cjs/plugins/storage-mongodb/rx-storage-instance-mongodb.js +7 -7
  69. package/dist/cjs/plugins/storage-mongodb/rx-storage-instance-mongodb.js.map +1 -1
  70. package/dist/cjs/plugins/test-utils/config.js +1 -1
  71. package/dist/cjs/plugins/test-utils/config.js.map +1 -1
  72. package/dist/cjs/plugins/test-utils/performance.js +122 -92
  73. package/dist/cjs/plugins/test-utils/performance.js.map +1 -1
  74. package/dist/cjs/plugins/test-utils/schema-objects.js +1 -1
  75. package/dist/cjs/plugins/test-utils/schema-objects.js.map +1 -1
  76. package/dist/cjs/plugins/test-utils/test-util.js +62 -0
  77. package/dist/cjs/plugins/test-utils/test-util.js.map +1 -1
  78. package/dist/cjs/plugins/utils/utils-map.js +2 -2
  79. package/dist/cjs/plugins/utils/utils-map.js.map +1 -1
  80. package/dist/cjs/plugins/utils/utils-object-deep-equal.js +3 -2
  81. package/dist/cjs/plugins/utils/utils-object-deep-equal.js.map +1 -1
  82. package/dist/cjs/plugins/utils/utils-object-dot-prop.js +25 -0
  83. package/dist/cjs/plugins/utils/utils-object-dot-prop.js.map +1 -1
  84. package/dist/cjs/plugins/utils/utils-object.js +102 -27
  85. package/dist/cjs/plugins/utils/utils-object.js.map +1 -1
  86. package/dist/cjs/plugins/utils/utils-other.js +9 -4
  87. package/dist/cjs/plugins/utils/utils-other.js.map +1 -1
  88. package/dist/cjs/plugins/utils/utils-premium.js +1 -19
  89. package/dist/cjs/plugins/utils/utils-premium.js.map +1 -1
  90. package/dist/cjs/plugins/utils/utils-revision.js +20 -10
  91. package/dist/cjs/plugins/utils/utils-revision.js.map +1 -1
  92. package/dist/cjs/plugins/utils/utils-rxdb-version.js +1 -1
  93. package/dist/cjs/plugins/utils/utils-rxdb-version.js.map +1 -1
  94. package/dist/cjs/plugins/utils/utils-string.js +11 -8
  95. package/dist/cjs/plugins/utils/utils-string.js.map +1 -1
  96. package/dist/cjs/plugins/utils/utils-time.js +21 -16
  97. package/dist/cjs/plugins/utils/utils-time.js.map +1 -1
  98. package/dist/cjs/query-cache.js +6 -4
  99. package/dist/cjs/query-cache.js.map +1 -1
  100. package/dist/cjs/query-planner.js +2 -2
  101. package/dist/cjs/query-planner.js.map +1 -1
  102. package/dist/cjs/replication-protocol/downstream.js +1 -1
  103. package/dist/cjs/replication-protocol/downstream.js.map +1 -1
  104. package/dist/cjs/rx-collection-helper.js +11 -6
  105. package/dist/cjs/rx-collection-helper.js.map +1 -1
  106. package/dist/cjs/rx-collection.js +34 -6
  107. package/dist/cjs/rx-collection.js.map +1 -1
  108. package/dist/cjs/rx-database.js +40 -7
  109. package/dist/cjs/rx-database.js.map +1 -1
  110. package/dist/cjs/rx-document.js +10 -3
  111. package/dist/cjs/rx-document.js.map +1 -1
  112. package/dist/cjs/rx-query-helper.js +35 -12
  113. package/dist/cjs/rx-query-helper.js.map +1 -1
  114. package/dist/cjs/rx-query-single-result.js +9 -2
  115. package/dist/cjs/rx-query-single-result.js.map +1 -1
  116. package/dist/cjs/rx-query.js +72 -29
  117. package/dist/cjs/rx-query.js.map +1 -1
  118. package/dist/cjs/rx-schema-helper.js +9 -3
  119. package/dist/cjs/rx-schema-helper.js.map +1 -1
  120. package/dist/cjs/rx-schema.js +1 -0
  121. package/dist/cjs/rx-schema.js.map +1 -1
  122. package/dist/cjs/rx-storage-helper.js +212 -129
  123. package/dist/cjs/rx-storage-helper.js.map +1 -1
  124. package/dist/cjs/types/rx-error.d.js.map +1 -1
  125. package/dist/cjs/types/rx-schema.d.js.map +1 -1
  126. package/dist/esm/change-event-buffer.js +2 -1
  127. package/dist/esm/change-event-buffer.js.map +1 -1
  128. package/dist/esm/custom-index.js +85 -12
  129. package/dist/esm/custom-index.js.map +1 -1
  130. package/dist/esm/doc-cache.js +118 -36
  131. package/dist/esm/doc-cache.js.map +1 -1
  132. package/dist/esm/event-reduce.js +10 -1
  133. package/dist/esm/event-reduce.js.map +1 -1
  134. package/dist/esm/plugin-helpers.js +16 -0
  135. package/dist/esm/plugin-helpers.js.map +1 -1
  136. package/dist/esm/plugins/attachments/index.js +3 -3
  137. package/dist/esm/plugins/attachments/index.js.map +1 -1
  138. package/dist/esm/plugins/cleanup/cleanup.js +5 -3
  139. package/dist/esm/plugins/cleanup/cleanup.js.map +1 -1
  140. package/dist/esm/plugins/crdt/index.js +52 -0
  141. package/dist/esm/plugins/crdt/index.js.map +1 -1
  142. package/dist/esm/plugins/dev-mode/check-query.js +7 -1
  143. package/dist/esm/plugins/dev-mode/check-query.js.map +1 -1
  144. package/dist/esm/plugins/dev-mode/check-schema.js +2 -1
  145. package/dist/esm/plugins/dev-mode/check-schema.js.map +1 -1
  146. package/dist/esm/plugins/dev-mode/error-messages.js +43 -5
  147. package/dist/esm/plugins/dev-mode/error-messages.js.map +1 -1
  148. package/dist/esm/plugins/encryption-crypto-js/index.js +22 -6
  149. package/dist/esm/plugins/encryption-crypto-js/index.js.map +1 -1
  150. package/dist/esm/plugins/leader-election/index.js +4 -4
  151. package/dist/esm/plugins/leader-election/index.js.map +1 -1
  152. package/dist/esm/plugins/local-documents/local-documents.js +20 -13
  153. package/dist/esm/plugins/local-documents/local-documents.js.map +1 -1
  154. package/dist/esm/plugins/migration-schema/migration-helpers.js +3 -0
  155. package/dist/esm/plugins/migration-schema/migration-helpers.js.map +1 -1
  156. package/dist/esm/plugins/migration-schema/rx-migration-state.js +1 -1
  157. package/dist/esm/plugins/migration-schema/rx-migration-state.js.map +1 -1
  158. package/dist/esm/plugins/pipeline/rx-pipeline.js +5 -1
  159. package/dist/esm/plugins/pipeline/rx-pipeline.js.map +1 -1
  160. package/dist/esm/plugins/query-builder/mquery/nosql-query-builder.js +4 -2
  161. package/dist/esm/plugins/query-builder/mquery/nosql-query-builder.js.map +1 -1
  162. package/dist/esm/plugins/replication/index.js +40 -2
  163. package/dist/esm/plugins/replication/index.js.map +1 -1
  164. package/dist/esm/plugins/replication-google-drive/document-handling.js +17 -6
  165. package/dist/esm/plugins/replication-google-drive/document-handling.js.map +1 -1
  166. package/dist/esm/plugins/replication-google-drive/google-drive-helper.js +1 -1
  167. package/dist/esm/plugins/replication-google-drive/google-drive-helper.js.map +1 -1
  168. package/dist/esm/plugins/replication-google-drive/google-drive-types.js.map +1 -1
  169. package/dist/esm/plugins/replication-google-drive/signaling.js +4 -1
  170. package/dist/esm/plugins/replication-google-drive/signaling.js.map +1 -1
  171. package/dist/esm/plugins/replication-google-drive/upstream.js +7 -4
  172. package/dist/esm/plugins/replication-google-drive/upstream.js.map +1 -1
  173. package/dist/esm/plugins/replication-microsoft-onedrive/signaling.js +4 -1
  174. package/dist/esm/plugins/replication-microsoft-onedrive/signaling.js.map +1 -1
  175. package/dist/esm/plugins/state/rx-state.js +15 -4
  176. package/dist/esm/plugins/state/rx-state.js.map +1 -1
  177. package/dist/esm/plugins/storage-dexie/rx-storage-instance-dexie.js +11 -18
  178. package/dist/esm/plugins/storage-dexie/rx-storage-instance-dexie.js.map +1 -1
  179. package/dist/esm/plugins/storage-memory/binary-search-bounds.js +107 -40
  180. package/dist/esm/plugins/storage-memory/binary-search-bounds.js.map +1 -1
  181. package/dist/esm/plugins/storage-memory/memory-helper.js +128 -41
  182. package/dist/esm/plugins/storage-memory/memory-helper.js.map +1 -1
  183. package/dist/esm/plugins/storage-memory/memory-indexes.js +1 -0
  184. package/dist/esm/plugins/storage-memory/memory-indexes.js.map +1 -1
  185. package/dist/esm/plugins/storage-memory/memory-types.js.map +1 -1
  186. package/dist/esm/plugins/storage-memory/rx-storage-instance-memory.js +90 -30
  187. package/dist/esm/plugins/storage-memory/rx-storage-instance-memory.js.map +1 -1
  188. package/dist/esm/plugins/storage-mongodb/mongodb-helper.js +39 -0
  189. package/dist/esm/plugins/storage-mongodb/mongodb-helper.js.map +1 -1
  190. package/dist/esm/plugins/storage-mongodb/rx-storage-instance-mongodb.js +8 -8
  191. package/dist/esm/plugins/storage-mongodb/rx-storage-instance-mongodb.js.map +1 -1
  192. package/dist/esm/plugins/test-utils/config.js +1 -1
  193. package/dist/esm/plugins/test-utils/config.js.map +1 -1
  194. package/dist/esm/plugins/test-utils/performance.js +122 -92
  195. package/dist/esm/plugins/test-utils/performance.js.map +1 -1
  196. package/dist/esm/plugins/test-utils/schema-objects.js +1 -1
  197. package/dist/esm/plugins/test-utils/schema-objects.js.map +1 -1
  198. package/dist/esm/plugins/test-utils/test-util.js +59 -0
  199. package/dist/esm/plugins/test-utils/test-util.js.map +1 -1
  200. package/dist/esm/plugins/utils/utils-map.js +2 -2
  201. package/dist/esm/plugins/utils/utils-map.js.map +1 -1
  202. package/dist/esm/plugins/utils/utils-object-deep-equal.js +3 -2
  203. package/dist/esm/plugins/utils/utils-object-deep-equal.js.map +1 -1
  204. package/dist/esm/plugins/utils/utils-object-dot-prop.js +25 -0
  205. package/dist/esm/plugins/utils/utils-object-dot-prop.js.map +1 -1
  206. package/dist/esm/plugins/utils/utils-object.js +102 -27
  207. package/dist/esm/plugins/utils/utils-object.js.map +1 -1
  208. package/dist/esm/plugins/utils/utils-other.js +9 -4
  209. package/dist/esm/plugins/utils/utils-other.js.map +1 -1
  210. package/dist/esm/plugins/utils/utils-premium.js +1 -19
  211. package/dist/esm/plugins/utils/utils-premium.js.map +1 -1
  212. package/dist/esm/plugins/utils/utils-revision.js +20 -10
  213. package/dist/esm/plugins/utils/utils-revision.js.map +1 -1
  214. package/dist/esm/plugins/utils/utils-rxdb-version.js +1 -1
  215. package/dist/esm/plugins/utils/utils-rxdb-version.js.map +1 -1
  216. package/dist/esm/plugins/utils/utils-string.js +11 -8
  217. package/dist/esm/plugins/utils/utils-string.js.map +1 -1
  218. package/dist/esm/plugins/utils/utils-time.js +21 -16
  219. package/dist/esm/plugins/utils/utils-time.js.map +1 -1
  220. package/dist/esm/query-cache.js +7 -5
  221. package/dist/esm/query-cache.js.map +1 -1
  222. package/dist/esm/query-planner.js +2 -2
  223. package/dist/esm/query-planner.js.map +1 -1
  224. package/dist/esm/replication-protocol/downstream.js +1 -1
  225. package/dist/esm/replication-protocol/downstream.js.map +1 -1
  226. package/dist/esm/rx-collection-helper.js +12 -7
  227. package/dist/esm/rx-collection-helper.js.map +1 -1
  228. package/dist/esm/rx-collection.js +35 -7
  229. package/dist/esm/rx-collection.js.map +1 -1
  230. package/dist/esm/rx-database.js +40 -7
  231. package/dist/esm/rx-database.js.map +1 -1
  232. package/dist/esm/rx-document.js +11 -4
  233. package/dist/esm/rx-document.js.map +1 -1
  234. package/dist/esm/rx-query-helper.js +35 -12
  235. package/dist/esm/rx-query-helper.js.map +1 -1
  236. package/dist/esm/rx-query-single-result.js +10 -3
  237. package/dist/esm/rx-query-single-result.js.map +1 -1
  238. package/dist/esm/rx-query.js +72 -29
  239. package/dist/esm/rx-query.js.map +1 -1
  240. package/dist/esm/rx-schema-helper.js +9 -3
  241. package/dist/esm/rx-schema-helper.js.map +1 -1
  242. package/dist/esm/rx-schema.js +1 -0
  243. package/dist/esm/rx-schema.js.map +1 -1
  244. package/dist/esm/rx-storage-helper.js +176 -94
  245. package/dist/esm/rx-storage-helper.js.map +1 -1
  246. package/dist/esm/types/rx-error.d.js.map +1 -1
  247. package/dist/esm/types/rx-schema.d.js.map +1 -1
  248. package/dist/types/custom-index.d.ts +5 -0
  249. package/dist/types/doc-cache.d.ts +1 -1
  250. package/dist/types/index.d.ts +25 -26
  251. package/dist/types/plugins/dev-mode/error-messages.d.ts +36 -0
  252. package/dist/types/plugins/leader-election/index.d.ts +1 -0
  253. package/dist/types/plugins/replication-google-drive/document-handling.d.ts +4 -1
  254. package/dist/types/plugins/replication-google-drive/google-drive-types.d.ts +1 -0
  255. package/dist/types/plugins/state/rx-state.d.ts +1 -1
  256. package/dist/types/plugins/storage-denokv/index.d.ts +1 -1
  257. package/dist/types/plugins/storage-dexie/rx-storage-dexie.d.ts +1 -1
  258. package/dist/types/plugins/storage-localstorage/index.d.ts +1 -1
  259. package/dist/types/plugins/storage-memory/binary-search-bounds.d.ts +21 -10
  260. package/dist/types/plugins/storage-memory/memory-helper.d.ts +7 -3
  261. package/dist/types/plugins/storage-memory/memory-types.d.ts +5 -0
  262. package/dist/types/plugins/storage-mongodb/mongodb-helper.d.ts +9 -1
  263. package/dist/types/plugins/storage-mongodb/rx-storage-instance-mongodb.d.ts +2 -2
  264. package/dist/types/plugins/storage-mongodb/rx-storage-mongodb.d.ts +1 -1
  265. package/dist/types/plugins/storage-remote/rx-storage-remote.d.ts +1 -1
  266. package/dist/types/plugins/storage-sqlite/index.d.ts +1 -1
  267. package/dist/types/plugins/test-utils/performance.d.ts +36 -0
  268. package/dist/types/plugins/test-utils/test-util.d.ts +17 -0
  269. package/dist/types/plugins/utils/utils-object.d.ts +8 -3
  270. package/dist/types/plugins/utils/utils-premium.d.ts +0 -2
  271. package/dist/types/plugins/utils/utils-rxdb-version.d.ts +1 -1
  272. package/dist/types/rx-database.d.ts +1 -1
  273. package/dist/types/rx-query-single-result.d.ts +1 -1
  274. package/dist/types/rx-query.d.ts +3 -2
  275. package/dist/types/rx-storage-helper.d.ts +15 -0
  276. package/eslint.config.mjs +2 -1
  277. package/package.json +732 -729
  278. package/scripts/check-code-block-line-length.js +91 -0
  279. package/scripts/check-em-dashes.js +53 -0
  280. package/scripts/docs-fetch-git-history.mjs +36 -0
  281. package/scripts/install-foundationdb.sh +0 -6
  282. package/scripts/notify-indexnow.mjs +171 -0
  283. package/scripts/start-foundationdb-docker.sh +73 -0
  284. package/src/change-event-buffer.ts +4 -1
  285. package/src/custom-index.ts +93 -16
  286. package/src/doc-cache.ts +117 -41
  287. package/src/event-reduce.ts +10 -1
  288. package/src/plugin-helpers.ts +10 -0
  289. package/src/plugins/attachments/index.ts +10 -12
  290. package/src/plugins/cleanup/cleanup.ts +5 -3
  291. package/src/plugins/crdt/index.ts +55 -0
  292. package/src/plugins/dev-mode/check-query.ts +7 -1
  293. package/src/plugins/dev-mode/check-schema.ts +2 -1
  294. package/src/plugins/dev-mode/error-messages.ts +45 -5
  295. package/src/plugins/encryption-crypto-js/index.ts +18 -6
  296. package/src/plugins/leader-election/index.ts +9 -8
  297. package/src/plugins/local-documents/local-documents.ts +21 -12
  298. package/src/plugins/migration-schema/migration-helpers.ts +3 -0
  299. package/src/plugins/migration-schema/rx-migration-state.ts +1 -1
  300. package/src/plugins/pipeline/rx-pipeline.ts +5 -1
  301. package/src/plugins/query-builder/mquery/nosql-query-builder.ts +8 -2
  302. package/src/plugins/replication/index.ts +41 -3
  303. package/src/plugins/replication-google-drive/document-handling.ts +17 -5
  304. package/src/plugins/replication-google-drive/google-drive-helper.ts +1 -1
  305. package/src/plugins/replication-google-drive/google-drive-types.ts +1 -0
  306. package/src/plugins/replication-google-drive/signaling.ts +4 -1
  307. package/src/plugins/replication-google-drive/upstream.ts +7 -4
  308. package/src/plugins/replication-microsoft-onedrive/signaling.ts +4 -1
  309. package/src/plugins/state/rx-state.ts +17 -5
  310. package/src/plugins/storage-dexie/rx-storage-instance-dexie.ts +0 -27
  311. package/src/plugins/storage-memory/binary-search-bounds.ts +105 -40
  312. package/src/plugins/storage-memory/memory-helper.ts +158 -67
  313. package/src/plugins/storage-memory/memory-indexes.ts +1 -0
  314. package/src/plugins/storage-memory/memory-types.ts +5 -0
  315. package/src/plugins/storage-memory/rx-storage-instance-memory.ts +104 -53
  316. package/src/plugins/storage-mongodb/mongodb-helper.ts +43 -1
  317. package/src/plugins/storage-mongodb/rx-storage-instance-mongodb.ts +11 -9
  318. package/src/plugins/test-utils/config.ts +2 -1
  319. package/src/plugins/test-utils/performance.ts +159 -85
  320. package/src/plugins/test-utils/schema-objects.ts +1 -1
  321. package/src/plugins/test-utils/test-util.ts +71 -0
  322. package/src/plugins/utils/utils-map.ts +2 -2
  323. package/src/plugins/utils/utils-object-deep-equal.ts +2 -4
  324. package/src/plugins/utils/utils-object-dot-prop.ts +25 -0
  325. package/src/plugins/utils/utils-object.ts +103 -28
  326. package/src/plugins/utils/utils-other.ts +9 -4
  327. package/src/plugins/utils/utils-premium.ts +11 -37
  328. package/src/plugins/utils/utils-revision.ts +20 -9
  329. package/src/plugins/utils/utils-rxdb-version.ts +1 -1
  330. package/src/plugins/utils/utils-string.ts +11 -9
  331. package/src/plugins/utils/utils-time.ts +21 -17
  332. package/src/query-cache.ts +6 -5
  333. package/src/query-planner.ts +2 -2
  334. package/src/replication-protocol/downstream.ts +1 -1
  335. package/src/rx-collection-helper.ts +12 -6
  336. package/src/rx-collection.ts +39 -8
  337. package/src/rx-database.ts +49 -17
  338. package/src/rx-document.ts +12 -3
  339. package/src/rx-query-helper.ts +36 -15
  340. package/src/rx-query-single-result.ts +10 -3
  341. package/src/rx-query.ts +48 -8
  342. package/src/rx-schema-helper.ts +7 -4
  343. package/src/rx-schema.ts +1 -0
  344. package/src/rx-storage-helper.ts +210 -139
  345. package/src/types/rx-error.d.ts +3 -0
  346. package/src/types/rx-schema.d.ts +5 -0
  347. package/dist/esm/package.json +0 -1
  348. package/dist/types/types/conflict-handling.d.ts +0 -48
  349. package/dist/types/types/couchdb.d.ts +0 -293
  350. package/dist/types/types/index.d.ts +0 -32
  351. package/dist/types/types/modules/index.d.ts +0 -0
  352. package/dist/types/types/modules/mocha.parallel.d.ts +0 -1
  353. package/dist/types/types/plugins/backup.d.ts +0 -35
  354. package/dist/types/types/plugins/cleanup.d.ts +0 -38
  355. package/dist/types/types/plugins/crdt.d.ts +0 -76
  356. package/dist/types/types/plugins/dexie.d.ts +0 -30
  357. package/dist/types/types/plugins/local-documents.d.ts +0 -49
  358. package/dist/types/types/plugins/migration.d.ts +0 -14
  359. package/dist/types/types/plugins/reactivity.d.ts +0 -40
  360. package/dist/types/types/plugins/replication-graphql.d.ts +0 -98
  361. package/dist/types/types/plugins/replication.d.ts +0 -175
  362. package/dist/types/types/plugins/state.d.ts +0 -4
  363. package/dist/types/types/plugins/update.d.ts +0 -23
  364. package/dist/types/types/plugins/webmcp.d.ts +0 -40
  365. package/dist/types/types/query-planner.d.ts +0 -47
  366. package/dist/types/types/replication-protocol.d.ts +0 -296
  367. package/dist/types/types/rx-attachment.d.ts +0 -46
  368. package/dist/types/types/rx-change-event.d.ts +0 -85
  369. package/dist/types/types/rx-collection.d.ts +0 -117
  370. package/dist/types/types/rx-database-internal-store.d.ts +0 -54
  371. package/dist/types/types/rx-database.d.ts +0 -124
  372. package/dist/types/types/rx-document.d.ts +0 -160
  373. package/dist/types/types/rx-error.d.ts +0 -222
  374. package/dist/types/types/rx-plugin.d.ts +0 -167
  375. package/dist/types/types/rx-query.d.ts +0 -144
  376. package/dist/types/types/rx-schema.d.ts +0 -209
  377. package/dist/types/types/rx-storage.d.ts +0 -347
  378. package/dist/types/types/rx-storage.interface.d.ts +0 -312
  379. package/dist/types/types/util.d.ts +0 -180
@@ -1,5 +1,4 @@
1
1
  import type {
2
- BulkWriteRow,
3
2
  RxDocumentData,
4
3
  RxJsonSchema
5
4
  } from '../../types/index.d.ts';
@@ -13,7 +12,7 @@ import {
13
12
  pushAtSortPosition
14
13
  } from 'array-push-at-sort-position';
15
14
  import { newRxError } from '../../rx-error.ts';
16
- import { boundEQ } from './binary-search-bounds.ts';
15
+ import { boundEQByIndexString } from './binary-search-bounds.ts';
17
16
 
18
17
 
19
18
  export function getMemoryCollectionKey(
@@ -46,6 +45,14 @@ export function attachmentMapKey(documentId: string, attachmentId: string): stri
46
45
  }
47
46
 
48
47
 
48
+ /**
49
+ * @performance
50
+ * Threshold for using in-place splice vs. full merge-sort when inserting
51
+ * documents into indexes. Below this batch size, in-place binary search + splice
52
+ * is faster because it avoids allocating a new full-size array and copying all elements.
53
+ */
54
+ const IN_PLACE_INSERT_THRESHOLD = 64;
55
+
49
56
  function sortByIndexStringComparator<RxDocType>(a: DocWithIndexString<RxDocType>, b: DocWithIndexString<RxDocType>) {
50
57
  if (a[0] < b[0]) {
51
58
  return -1;
@@ -67,38 +74,65 @@ export function putWriteRowToState<RxDocType>(
67
74
  docInState?: RxDocumentData<RxDocType>
68
75
  ) {
69
76
  state.documents.set(docId, document as any);
70
- for (let i = 0; i < stateByIndex.length; ++i) {
77
+ const stateByIndexLength = stateByIndex.length;
78
+ for (let i = 0; i < stateByIndexLength; ++i) {
71
79
  const byIndex = stateByIndex[i];
72
80
  const docsWithIndex = byIndex.docsWithIndex;
73
81
  const getIndexableString = byIndex.getIndexableString;
74
82
  const newIndexString = getIndexableString(document as any);
75
- const insertPosition = pushAtSortPosition(
76
- docsWithIndex,
77
- [
78
- newIndexString,
79
- document,
80
- docId,
81
- ],
82
- sortByIndexStringComparator,
83
- 0
84
- );
85
83
 
86
84
  /**
87
- * Remove previous if it was in the state
85
+ * @performance
86
+ * When updating a document, first compute whether the index changed.
87
+ * If it did not change, we only need to update the document reference
88
+ * in-place without any splice operations.
88
89
  */
89
90
  if (docInState) {
90
91
  const previousIndexString = getIndexableString(docInState);
91
92
  if (previousIndexString === newIndexString) {
92
93
  /**
93
94
  * Performance shortcut.
94
- * If index was not changed -> The old doc must be before or after the new one.
95
+ * Index did not change, so the old entry is at the same position.
96
+ * We can find it by string-specialized binary search and update in-place.
95
97
  */
96
- const prev = docsWithIndex[insertPosition - 1];
97
- if (prev && prev[2] === docId) {
98
+ const eqPos = boundEQByIndexString(
99
+ docsWithIndex,
100
+ previousIndexString
101
+ );
102
+ if (eqPos !== -1) {
103
+ /**
104
+ * There might be multiple entries with the same index string
105
+ * (e.g. different documents). Search around eqPos for ours.
106
+ */
107
+ if (docsWithIndex[eqPos][2] === docId) {
108
+ docsWithIndex[eqPos][1] = document;
109
+ continue;
110
+ }
111
+ // Check neighbors
112
+ const prev = docsWithIndex[eqPos - 1];
113
+ if (prev && prev[0] === previousIndexString && prev[2] === docId) {
114
+ docsWithIndex[eqPos - 1][1] = document;
115
+ continue;
116
+ }
117
+ const next = docsWithIndex[eqPos + 1];
118
+ if (next && next[0] === previousIndexString && next[2] === docId) {
119
+ docsWithIndex[eqPos + 1][1] = document;
120
+ continue;
121
+ }
122
+ }
123
+ // Fallback: use the old insert+remove approach
124
+ const insertPosition = pushAtSortPosition(
125
+ docsWithIndex,
126
+ [newIndexString, document, docId],
127
+ sortByIndexStringComparator,
128
+ 0
129
+ );
130
+ const prevEntry = docsWithIndex[insertPosition - 1];
131
+ if (prevEntry && prevEntry[2] === docId) {
98
132
  docsWithIndex.splice(insertPosition - 1, 1);
99
133
  } else {
100
- const next = docsWithIndex[insertPosition + 1];
101
- if (next[2] === docId) {
134
+ const nextEntry = docsWithIndex[insertPosition + 1];
135
+ if (nextEntry[2] === docId) {
102
136
  docsWithIndex.splice(insertPosition + 1, 1);
103
137
  } else {
104
138
  throw newRxError('SNH', {
@@ -109,20 +143,27 @@ export function putWriteRowToState<RxDocType>(
109
143
  });
110
144
  }
111
145
  }
146
+ continue;
112
147
  } else {
113
148
  /**
114
- * Index changed, we must search for the old one and remove it.
149
+ * Index changed, we must remove the old entry and insert the new one.
115
150
  */
116
- const indexBefore = boundEQ(
151
+ const indexBefore = boundEQByIndexString(
117
152
  docsWithIndex,
118
- [
119
- previousIndexString
120
- ] as any,
121
- compareDocsWithIndex
153
+ previousIndexString
122
154
  );
123
- docsWithIndex.splice(indexBefore, 1);
155
+ if (indexBefore !== -1) {
156
+ docsWithIndex.splice(indexBefore, 1);
157
+ }
124
158
  }
125
159
  }
160
+
161
+ pushAtSortPosition(
162
+ docsWithIndex,
163
+ [newIndexString, document, docId],
164
+ sortByIndexStringComparator,
165
+ 0
166
+ );
126
167
  }
127
168
  }
128
169
 
@@ -130,9 +171,13 @@ export function putWriteRowToState<RxDocType>(
130
171
  /**
131
172
  * @hotPath
132
173
  * Efficiently inserts multiple documents into the state at once.
133
- * Instead of inserting one-by-one with Array.splice() (O(n) per insert),
134
- * this pre-computes all index entries, sorts them, and merges them into
135
- * the existing sorted arrays in a single pass (O(n log n + n + m)).
174
+ *
175
+ * Uses two strategies based on batch size:
176
+ * - For small batches (relative to existing index size), uses in-place
177
+ * binary search + splice per document. This avoids allocating a new
178
+ * full-size array and copying all elements, reducing GC pressure.
179
+ * - For large batches (or empty indexes), pre-computes all index entries,
180
+ * sorts them, and merges into the existing sorted arrays in a single pass.
136
181
  */
137
182
  export function bulkInsertToState<RxDocType>(
138
183
  primaryPath: string,
@@ -141,6 +186,7 @@ export function bulkInsertToState<RxDocType>(
141
186
  docs: { document: RxDocumentData<RxDocType> }[]
142
187
  ) {
143
188
  const docsLength = docs.length;
189
+ const stateByIndexLength = stateByIndex.length;
144
190
 
145
191
  // Extract documents and docIds once, store in Map
146
192
  const documents: RxDocumentData<RxDocType>[] = new Array(docsLength);
@@ -153,55 +199,99 @@ export function bulkInsertToState<RxDocType>(
153
199
  state.documents.set(docId, doc as any);
154
200
  }
155
201
 
156
- // For each index, batch-compute entries, sort, and merge
157
- for (let indexI = 0; indexI < stateByIndex.length; ++indexI) {
158
- const byIndex = stateByIndex[indexI];
159
- const docsWithIndex = byIndex.docsWithIndex;
160
- const getIndexableString = byIndex.getIndexableString;
202
+ /**
203
+ * @performance
204
+ * For small batch sizes, use in-place binary search + splice
205
+ * instead of creating a full merged array copy. This is faster
206
+ * for serial inserts and small bulk inserts because it avoids:
207
+ * - Allocating a new array of size n+m
208
+ * - Copying all n existing elements
209
+ * - GC pressure from discarding the old array
210
+ *
211
+ * The threshold is based on when the merge approach becomes more
212
+ * efficient than individual splices.
213
+ */
214
+ const useInPlaceInsert = docsLength < IN_PLACE_INSERT_THRESHOLD;
215
+
216
+ if (useInPlaceInsert) {
217
+ for (let indexI = 0; indexI < stateByIndexLength; ++indexI) {
218
+ const byIndex = stateByIndex[indexI];
219
+ const docsWithIndex = byIndex.docsWithIndex;
220
+ const getIndexableString = byIndex.getIndexableString;
161
221
 
162
- // Build new entries
163
- const newEntries: DocWithIndexString<RxDocType>[] = new Array(docsLength);
164
- for (let i = 0; i < docsLength; ++i) {
165
- const doc = documents[i];
166
- newEntries[i] = [
167
- getIndexableString(doc as any),
168
- doc,
169
- docIds[i]
170
- ];
222
+ if (docsWithIndex.length === 0) {
223
+ for (let i = 0; i < docsLength; ++i) {
224
+ const doc = documents[i];
225
+ const indexString = getIndexableString(doc as any);
226
+ docsWithIndex.push([indexString, doc, docIds[i]]);
227
+ }
228
+ docsWithIndex.sort(sortByIndexStringComparator);
229
+ } else {
230
+ for (let i = 0; i < docsLength; ++i) {
231
+ const doc = documents[i];
232
+ const indexString = getIndexableString(doc as any);
233
+ const newEntry: DocWithIndexString<RxDocType> = [indexString, doc, docIds[i]];
234
+ pushAtSortPosition(
235
+ docsWithIndex,
236
+ newEntry,
237
+ sortByIndexStringComparator,
238
+ 0
239
+ );
240
+ }
241
+ }
171
242
  }
243
+ } else {
244
+ // For each index, batch-compute entries, sort, and merge
245
+ for (let indexI = 0; indexI < stateByIndexLength; ++indexI) {
246
+ const byIndex = stateByIndex[indexI];
247
+ const docsWithIndex = byIndex.docsWithIndex;
248
+ const getIndexableString = byIndex.getIndexableString;
172
249
 
173
- // Sort by index string
174
- newEntries.sort(sortByIndexStringComparator);
250
+ // Build new entries
251
+ const newEntries: DocWithIndexString<RxDocType>[] = new Array(docsLength);
252
+ for (let i = 0; i < docsLength; ++i) {
253
+ const doc = documents[i];
254
+ newEntries[i] = [
255
+ getIndexableString(doc as any),
256
+ doc,
257
+ docIds[i]
258
+ ];
259
+ }
175
260
 
176
- if (docsWithIndex.length === 0) {
177
- // Index is empty, just assign sorted entries
178
- byIndex.docsWithIndex = newEntries;
179
- } else {
180
- // Merge sorted arrays
181
- byIndex.docsWithIndex = mergeSortedArrays(docsWithIndex, newEntries, sortByIndexStringComparator);
261
+ // Sort by index string
262
+ newEntries.sort(sortByIndexStringComparator);
263
+
264
+ if (docsWithIndex.length === 0) {
265
+ // Index is empty, just assign sorted entries
266
+ byIndex.docsWithIndex = newEntries;
267
+ } else {
268
+ // Merge sorted arrays
269
+ byIndex.docsWithIndex = mergeSortedArrays(docsWithIndex, newEntries);
270
+ }
182
271
  }
183
272
  }
184
273
  }
185
274
 
186
275
 
187
276
  /**
188
- * Merges two sorted arrays into a single sorted array.
277
+ * Merges two sorted DocWithIndexString arrays into a single sorted array.
189
278
  * Runs in O(n + m) where n and m are the lengths of the input arrays.
279
+ * @performance Comparator is inlined to avoid function call overhead
280
+ * per comparison, which is significant for large arrays.
190
281
  */
191
- function mergeSortedArrays<T>(
192
- a: T[],
193
- b: T[],
194
- comparator: (x: T, y: T) => number
195
- ): T[] {
282
+ function mergeSortedArrays<RxDocType>(
283
+ a: DocWithIndexString<RxDocType>[],
284
+ b: DocWithIndexString<RxDocType>[]
285
+ ): DocWithIndexString<RxDocType>[] {
196
286
  const aLen = a.length;
197
287
  const bLen = b.length;
198
- const result: T[] = new Array(aLen + bLen);
288
+ const result: DocWithIndexString<RxDocType>[] = new Array(aLen + bLen);
199
289
  let ai = 0;
200
290
  let bi = 0;
201
291
  let ri = 0;
202
292
 
203
293
  while (ai < aLen && bi < bLen) {
204
- if (comparator(a[ai], b[bi]) <= 0) {
294
+ if (a[ai][0] <= b[bi][0]) {
205
295
  result[ri++] = a[ai++];
206
296
  } else {
207
297
  result[ri++] = b[bi++];
@@ -227,19 +317,20 @@ export function removeDocFromState<RxDocType>(
227
317
  const docId: string = (doc as any)[primaryPath];
228
318
  state.documents.delete(docId);
229
319
 
230
- Object.values(state.byIndex).forEach(byIndex => {
320
+ const stateByIndex = state.byIndexArray;
321
+ for (let i = 0; i < stateByIndex.length; ++i) {
322
+ const byIndex = stateByIndex[i];
231
323
  const docsWithIndex = byIndex.docsWithIndex;
232
324
  const indexString = byIndex.getIndexableString(doc);
233
325
 
234
- const positionInIndex = boundEQ(
326
+ const positionInIndex = boundEQByIndexString(
235
327
  docsWithIndex,
236
- [
237
- indexString
238
- ] as any,
239
- compareDocsWithIndex
328
+ indexString
240
329
  );
241
- docsWithIndex.splice(positionInIndex, 1);
242
- });
330
+ if (positionInIndex !== -1) {
331
+ docsWithIndex.splice(positionInIndex, 1);
332
+ }
333
+ }
243
334
  }
244
335
 
245
336
 
@@ -26,6 +26,7 @@ export function addIndexesToInternalsState<RxDocType>(
26
26
  getIndexableString: getIndexableStringMonad(schema, indexAr)
27
27
  };
28
28
  });
29
+ state.byIndexArray = Object.values(state.byIndex);
29
30
  }
30
31
 
31
32
 
@@ -73,6 +73,11 @@ export type MemoryStorageInternals<RxDocType> = {
73
73
  */
74
74
  [indexName: string]: MemoryStorageInternalsByIndex<RxDocType>;
75
75
  };
76
+ /**
77
+ * Cached array of all MemoryStorageInternalsByIndex values.
78
+ * Avoids calling Object.values(byIndex) on every write operation.
79
+ */
80
+ byIndexArray: MemoryStorageInternalsByIndex<RxDocType>[];
76
81
 
77
82
  /**
78
83
  * We need these to do lazy writes.
@@ -37,15 +37,14 @@ import {
37
37
  requestIdlePromiseNoQueue
38
38
  } from '../../plugins/utils/index.ts';
39
39
  import {
40
- boundGE,
41
- boundGT,
42
- boundLE,
43
- boundLT
40
+ boundGEByIndexString,
41
+ boundGTByIndexString,
42
+ boundLEByIndexString,
43
+ boundLTByIndexString
44
44
  } from './binary-search-bounds.ts';
45
45
  import {
46
46
  attachmentMapKey,
47
47
  bulkInsertToState,
48
- compareDocsWithIndex,
49
48
  ensureNotRemoved,
50
49
  getMemoryCollectionKey,
51
50
  putWriteRowToState,
@@ -170,7 +169,6 @@ export class RxStorageInstanceMemory<RxDocType> implements RxStorageInstance<
170
169
  return;
171
170
  }
172
171
  const internals = this.internals;
173
- const documentsById = this.internals.documents;
174
172
  const primaryPath = this.primaryPath;
175
173
 
176
174
  const categorized = this.internals.ensurePersistenceTask;
@@ -178,8 +176,9 @@ export class RxStorageInstanceMemory<RxDocType> implements RxStorageInstance<
178
176
 
179
177
  /**
180
178
  * Do inserts/updates
179
+ * @performance Use cached byIndexArray instead of Object.values()
181
180
  */
182
- const stateByIndex = Object.values(this.internals.byIndex);
181
+ const stateByIndex = internals.byIndexArray;
183
182
 
184
183
  /**
185
184
  * @performance Use batch insert for bulk inserts to avoid
@@ -202,12 +201,19 @@ export class RxStorageInstanceMemory<RxDocType> implements RxStorageInstance<
202
201
  const writeRow = bulkUpdateDocs[i];
203
202
  const doc = writeRow.document;
204
203
  const docId = doc[primaryPath];
204
+ /**
205
+ * @performance
206
+ * Pass writeRow.previous directly as the old document state
207
+ * instead of re-looking it up from the documents Map.
208
+ * This is safe because categorizeBulkWriteRows already verified
209
+ * that previous._rev matches the document in the Map (conflict check).
210
+ */
205
211
  putWriteRowToState(
206
212
  docId as any,
207
213
  internals,
208
214
  stateByIndex,
209
215
  doc,
210
- documentsById.get(docId as any)
216
+ writeRow.previous
211
217
  );
212
218
  }
213
219
 
@@ -254,17 +260,23 @@ export class RxStorageInstanceMemory<RxDocType> implements RxStorageInstance<
254
260
  if (documentsById.size === 0) {
255
261
  return Promise.resolve(ret);
256
262
  }
257
- for (let i = 0; i < docIds.length; ++i) {
258
- const docId = docIds[i];
259
- const docInDb = documentsById.get(docId);
260
- if (
261
- docInDb &&
262
- (
263
- !docInDb._deleted ||
264
- withDeleted
265
- )
266
- ) {
267
- ret.push(docInDb);
263
+ /**
264
+ * @performance
265
+ * Split into two paths to avoid checking withDeleted on every iteration.
266
+ */
267
+ if (withDeleted) {
268
+ for (let i = 0; i < docIds.length; ++i) {
269
+ const docInDb = documentsById.get(docIds[i]);
270
+ if (docInDb) {
271
+ ret.push(docInDb);
272
+ }
273
+ }
274
+ } else {
275
+ for (let i = 0; i < docIds.length; ++i) {
276
+ const docInDb = documentsById.get(docIds[i]);
277
+ if (docInDb && !docInDb._deleted) {
278
+ ret.push(docInDb);
279
+ }
268
280
  }
269
281
  }
270
282
  return Promise.resolve(ret);
@@ -314,22 +326,17 @@ export class RxStorageInstanceMemory<RxDocType> implements RxStorageInstance<
314
326
  const docsWithIndex = this.internals.byIndex[indexName].docsWithIndex;
315
327
 
316
328
 
329
+ /**
330
+ * @performance Use string-specialized binary search to avoid
331
+ * temporary array allocations on every query.
332
+ */
333
+ let indexOfLower = queryPlan.inclusiveStart
334
+ ? boundGEByIndexString(docsWithIndex, lowerBoundString)
335
+ : boundGTByIndexString(docsWithIndex, lowerBoundString);
317
336
 
318
- let indexOfLower = (queryPlan.inclusiveStart ? boundGE : boundGT)(
319
- docsWithIndex,
320
- [
321
- lowerBoundString
322
- ] as any,
323
- compareDocsWithIndex
324
- );
325
-
326
- const indexOfUpper = (queryPlan.inclusiveEnd ? boundLE : boundLT)(
327
- docsWithIndex,
328
- [
329
- upperBoundString
330
- ] as any,
331
- compareDocsWithIndex
332
- );
337
+ const indexOfUpper = queryPlan.inclusiveEnd
338
+ ? boundLEByIndexString(docsWithIndex, upperBoundString)
339
+ : boundLTByIndexString(docsWithIndex, upperBoundString);
333
340
 
334
341
  let rows: RxDocumentData<RxDocType>[] = [];
335
342
 
@@ -405,6 +412,7 @@ export class RxStorageInstanceMemory<RxDocType> implements RxStorageInstance<
405
412
  * If the selector is satisfied by the index,
406
413
  * we can compute the count directly from the index range
407
414
  * without extracting document data into an array.
415
+ * Uses string-specialized binary search to avoid allocations.
408
416
  */
409
417
  if (queryPlan.selectorSatisfiedByIndex) {
410
418
  const queryPlanFields: string[] = queryPlan.index;
@@ -428,17 +436,13 @@ export class RxStorageInstanceMemory<RxDocType> implements RxStorageInstance<
428
436
  }
429
437
  const docsWithIndex = this.internals.byIndex[indexName].docsWithIndex;
430
438
 
431
- const indexOfLower = (queryPlan.inclusiveStart ? boundGE : boundGT)(
432
- docsWithIndex,
433
- [lowerBoundString] as any,
434
- compareDocsWithIndex
435
- );
439
+ const indexOfLower = queryPlan.inclusiveStart
440
+ ? boundGEByIndexString(docsWithIndex, lowerBoundString)
441
+ : boundGTByIndexString(docsWithIndex, lowerBoundString);
436
442
 
437
- const indexOfUpper = (queryPlan.inclusiveEnd ? boundLE : boundLT)(
438
- docsWithIndex,
439
- [upperBoundString] as any,
440
- compareDocsWithIndex
441
- );
443
+ const indexOfUpper = queryPlan.inclusiveEnd
444
+ ? boundLEByIndexString(docsWithIndex, upperBoundString)
445
+ : boundLTByIndexString(docsWithIndex, upperBoundString);
442
446
 
443
447
  const count = Math.max(0, indexOfUpper - indexOfLower + 1);
444
448
  return Promise.resolve({
@@ -447,10 +451,54 @@ export class RxStorageInstanceMemory<RxDocType> implements RxStorageInstance<
447
451
  });
448
452
  }
449
453
 
450
- return this.query(preparedQuery).then(result => ({
451
- count: result.documents.length,
454
+ const queryMatcher = getQueryMatcher(
455
+ this.schema,
456
+ preparedQuery.query
457
+ );
458
+ const queryPlanFields: string[] = queryPlan.index;
459
+ const index: string[] = queryPlanFields;
460
+ const lowerBound: any[] = queryPlan.startKeys;
461
+ const lowerBoundString = getStartIndexStringFromLowerBound(
462
+ this.schema,
463
+ index,
464
+ lowerBound
465
+ );
466
+ const upperBound: any[] = queryPlan.endKeys;
467
+ const upperBoundString = getStartIndexStringFromUpperBound(
468
+ this.schema,
469
+ index,
470
+ upperBound
471
+ );
472
+ const indexName = getMemoryIndexName(index);
473
+ if (!this.internals.byIndex[indexName]) {
474
+ throw newRxError('SNH', { args: { indexName } });
475
+ }
476
+ const docsWithIndex = this.internals.byIndex[indexName].docsWithIndex;
477
+
478
+ let indexOfLower = queryPlan.inclusiveStart
479
+ ? boundGEByIndexString(docsWithIndex, lowerBoundString)
480
+ : boundGTByIndexString(docsWithIndex, lowerBoundString);
481
+
482
+ const indexOfUpper = queryPlan.inclusiveEnd
483
+ ? boundLEByIndexString(docsWithIndex, upperBoundString)
484
+ : boundLTByIndexString(docsWithIndex, upperBoundString);
485
+
486
+ let count = 0;
487
+ while (indexOfLower <= indexOfUpper) {
488
+ const currentRow = docsWithIndex[indexOfLower];
489
+ if (!currentRow) {
490
+ break;
491
+ }
492
+ if (queryMatcher(currentRow[1])) {
493
+ count++;
494
+ }
495
+ indexOfLower++;
496
+ }
497
+
498
+ return Promise.resolve({
499
+ count,
452
500
  mode: 'fast' as const
453
- }));
501
+ });
454
502
  }
455
503
 
456
504
  cleanup(minimumDeletedTime: number): Promise<boolean> {
@@ -470,12 +518,9 @@ export class RxStorageInstanceMemory<RxDocType> implements RxStorageInstance<
470
518
  ]
471
519
  );
472
520
 
473
- let indexOfLower = boundGT(
521
+ let indexOfLower = boundGTByIndexString(
474
522
  docsWithIndex,
475
- [
476
- lowerBoundString
477
- ] as any,
478
- compareDocsWithIndex
523
+ lowerBoundString
479
524
  );
480
525
 
481
526
  let done = false;
@@ -490,7 +535,12 @@ export class RxStorageInstanceMemory<RxDocType> implements RxStorageInstance<
490
535
  this.internals,
491
536
  currentDoc[1]
492
537
  );
493
- indexOfLower++;
538
+ /**
539
+ * Do NOT increment indexOfLower after removal.
540
+ * removeDocFromState() splices the element out of the array,
541
+ * so the next element shifts into the current position.
542
+ * Incrementing would skip it.
543
+ */
494
544
  }
495
545
  }
496
546
  return PROMISE_RESOLVE_TRUE;
@@ -574,6 +624,7 @@ export function createMemoryStorageInstance<RxDocType>(
574
624
  documents: new Map(),
575
625
  attachments: params.schema.attachments ? new Map() : undefined as any,
576
626
  byIndex: {},
627
+ byIndexArray: [],
577
628
  changes$: new Subject()
578
629
  };
579
630
  addIndexesToInternalsState(internals, params.schema);
@@ -6,7 +6,8 @@ import type {
6
6
  RxJsonSchema
7
7
  } from '../../types/index.d.ts';
8
8
  import {
9
- Sort as MongoSort
9
+ Sort as MongoSort,
10
+ MongoClient
10
11
  } from 'mongodb';
11
12
  import { RXDB_VERSION, flatClone } from '../utils/index.ts';
12
13
  import { MongoDBPreparedQuery, MongoQuerySelector } from './mongodb-types.ts';
@@ -117,3 +118,44 @@ export function swapToMongoSort<RxDocType>(
117
118
  export function getMongoDBIndexName(index: string[]): string {
118
119
  return index.join('|');
119
120
  }
121
+
122
+ export const MONGO_CLIENT_CACHE = new Map<string, { client: MongoClient, refCount: number, promise: Promise<MongoClient>, closeTimeout?: ReturnType<typeof setTimeout> }>();
123
+
124
+ export async function getMongoDBClient(connection: string): Promise<MongoClient> {
125
+ let cached = MONGO_CLIENT_CACHE.get(connection);
126
+ if (!cached) {
127
+ const client = new MongoClient(connection, MONGO_OPTIONS_DRIVER_INFO);
128
+ cached = {
129
+ client,
130
+ refCount: 1,
131
+ promise: client.connect().then(() => client)
132
+ };
133
+ MONGO_CLIENT_CACHE.set(connection, cached);
134
+ return cached.promise;
135
+ }
136
+ cached.refCount++;
137
+ if (cached.closeTimeout) {
138
+ clearTimeout(cached.closeTimeout);
139
+ cached.closeTimeout = undefined;
140
+ }
141
+ return cached.promise;
142
+ }
143
+
144
+ export async function closeMongoDBClient(connection: string): Promise<void> {
145
+ const cached = MONGO_CLIENT_CACHE.get(connection);
146
+ if (cached) {
147
+ cached.refCount--;
148
+ if (cached.refCount === 0) {
149
+ if (cached.closeTimeout) {
150
+ clearTimeout(cached.closeTimeout);
151
+ }
152
+ cached.closeTimeout = setTimeout(() => {
153
+ const innerCached = MONGO_CLIENT_CACHE.get(connection);
154
+ if (innerCached && innerCached.refCount === 0) {
155
+ MONGO_CLIENT_CACHE.delete(connection);
156
+ innerCached.client.close().catch(() => { });
157
+ }
158
+ }, 2000); // 2 second delay to allow reuse
159
+ }
160
+ }
161
+ }