@toa.io/storages.mongodb 1.0.0-alpha.332 → 1.0.0-alpha.335

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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,29 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [1.0.0-alpha.335](https://github.com/toa-io/toa/compare/v1.0.0-alpha.334...v1.0.0-alpha.335) (2026-10-26)
7
+
8
+ **Note:** Version bump only for package @toa.io/storages.mongodb
9
+
10
+
11
+
12
+
13
+
14
+ # [1.0.0-alpha.334](https://github.com/toa-io/toa/compare/v1.0.0-alpha.333...v1.0.0-alpha.334) (2026-10-26)
15
+
16
+ **Note:** Version bump only for package @toa.io/storages.mongodb
17
+
18
+
19
+
20
+
21
+
22
+ # [1.0.0-alpha.333](https://github.com/toa-io/toa/compare/v1.0.0-alpha.332...v1.0.0-alpha.333) (2026-10-26)
23
+
24
+ ### Bug Fixes
25
+
26
+ * **storages.mongodb:** run a set again where it met a commit in flight ([2e293fe](https://github.com/toa-io/toa/commit/2e293fe1b72c3eac65f659f0061e312945829b6e))
27
+
28
+
6
29
  # [1.0.0-alpha.332](https://github.com/toa-io/toa/compare/v1.0.0-alpha.331...v1.0.0-alpha.332) (2026-10-23)
7
30
 
8
31
  ### Bug Fixes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toa.io/storages.mongodb",
3
- "version": "1.0.0-alpha.332",
3
+ "version": "1.0.0-alpha.335",
4
4
  "type": "module",
5
5
  "description": "Toa MongoDB Storage Connector",
6
6
  "author": "temich <tema.gurtovoy@gmail.com>",
@@ -21,12 +21,12 @@
21
21
  },
22
22
  "dependencies": {
23
23
  "@toa.io/conveyor": "1.0.0-alpha.332",
24
- "@toa.io/core": "1.0.0-alpha.332",
25
- "@toa.io/definitions": "1.0.0-alpha.332",
24
+ "@toa.io/core": "1.0.0-alpha.333",
25
+ "@toa.io/definitions": "1.0.0-alpha.335",
26
26
  "@toa.io/generic": "1.0.0-alpha.332",
27
27
  "@toa.io/pointer": "1.0.0-alpha.332",
28
28
  "mongodb": "7.7.0",
29
29
  "openspan": "1.0.0-alpha.330"
30
30
  },
31
- "gitHead": "37dbdefd96c01df050ea0d46a647da7f2f9f93f2"
31
+ "gitHead": "07f9c76f161c9422d9126deaecf468ec50bb54a3"
32
32
  }
package/src/bulk.js ADDED
@@ -0,0 +1,26 @@
1
+ import { MongoClientBulkWriteError, MongoServerError } from 'mongodb'
2
+
3
+ /**
4
+ * The client's bulk write, where a command the server refused is thrown as the server sent it.
5
+ *
6
+ * The driver wraps that refusal in an error that carries none of its labels, and a transaction
7
+ * runs again only what is labelled as worth running again: a write conflict with a commit in
8
+ * flight would end the transaction as a failure of its own. A write the server refused one by
9
+ * one is left as it is, read off `writeErrors`.
10
+ *
11
+ * @param {import('mongodb').MongoClient} client
12
+ * @param {import('mongodb').AnyClientBulkWriteModel[]} operations
13
+ * @param {import('mongodb').ClientBulkWriteOptions} options
14
+ */
15
+ export async function bulkWrite(client, operations, options) {
16
+ try {
17
+ return await client.bulkWrite(operations, options)
18
+ } catch (error) {
19
+ if (
20
+ error instanceof MongoClientBulkWriteError &&
21
+ error.cause instanceof MongoServerError
22
+ )
23
+ throw error.cause
24
+ else throw error
25
+ }
26
+ }
package/src/outbox.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { environment } from '@toa.io/generic'
2
2
  import { index, prune } from './indexes.js'
3
+ import { bulkWrite } from './bulk.js'
3
4
 
4
5
  /**
5
6
  * The outbox rows of one component. Its lifecycle is the Client's, so it is not a Connector.
@@ -30,7 +31,8 @@ export class Outbox {
30
31
  const namespace = this.#collection.namespace
31
32
 
32
33
  // the client's bulk write, not `insertMany`: see `massStore` in ./storage.js
33
- await this.#collection.client.bulkWrite(
34
+ await bulkWrite(
35
+ this.#collection.client,
34
36
  rows.map((row) => ({ name: 'insertOne', namespace, document: to(row) })),
35
37
  { session }
36
38
  )
package/src/storage.js CHANGED
@@ -4,6 +4,7 @@ import { translate } from './translate.js'
4
4
  import { codec } from './record.js'
5
5
  import { Inbox } from './inbox.js'
6
6
  import { Outbox } from './outbox.js'
7
+ import { bulkWrite } from './bulk.js'
7
8
  import { Migrations } from './migrations.js'
8
9
  import { Streams } from './streams.js'
9
10
  import { conflicted, query } from './measurements.js'
@@ -332,7 +333,7 @@ export class Storage extends Connector {
332
333
  // the client's bulk write, not the collection's: the latter takes a `timeoutMS` the
333
334
  // URL sets for one the call passed, and refuses it inside a transaction that has
334
335
  // its own
335
- async () => await this.#collection.client.bulkWrite(operations, { session })
336
+ async () => await bulkWrite(this.#collection.client, operations, { session })
336
337
  )
337
338
  } catch (error) {
338
339
  if (!collidedOnId(firstWriteError(error))) throw error
@@ -0,0 +1,49 @@
1
+ import { describe, it, mock } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+ import { MongoClientBulkWriteError, MongoServerError } from 'mongodb'
4
+
5
+ import { bulkWrite } from '../src/bulk.js'
6
+
7
+ describe('bulkWrite', () => {
8
+ it('should throw what the server refused the command with, labels and all', async () => {
9
+ const conflict = new MongoServerError({
10
+ message: 'Write conflict during plan execution and yielding is disabled.',
11
+ code: 112,
12
+ errorLabels: ['TransientTransactionError']
13
+ })
14
+
15
+ const wrapped = new MongoClientBulkWriteError({
16
+ message: 'Mongo client bulk write encountered an error during execution'
17
+ })
18
+
19
+ wrapped.cause = conflict
20
+
21
+ const client = { bulkWrite: mock.fn(async () => Promise.reject(wrapped)) }
22
+
23
+ await assert.rejects(bulkWrite(client, [], {}), (error) => {
24
+ assert.equal(error, conflict)
25
+ assert.equal(error.hasErrorLabel('TransientTransactionError'), true)
26
+
27
+ return true
28
+ })
29
+ })
30
+
31
+ it('should throw what refused a write one by one as it is', async () => {
32
+ const refused = new MongoClientBulkWriteError({
33
+ message: 'Mongo client bulk write encountered errors during execution'
34
+ })
35
+
36
+ refused.writeErrors.set(0, { code: 11000, message: 'E11000 duplicate key error' })
37
+
38
+ const client = { bulkWrite: mock.fn(async () => Promise.reject(refused)) }
39
+
40
+ await assert.rejects(bulkWrite(client, [], {}), (error) => error === refused)
41
+ })
42
+
43
+ it('should answer what the client answers', async () => {
44
+ const result = { matchedCount: 1, upsertedCount: 0 }
45
+ const client = { bulkWrite: mock.fn(async () => result) }
46
+
47
+ assert.equal(await bulkWrite(client, [], {}), result)
48
+ })
49
+ })