mongodb-ops 0.11.1 → 0.11.2
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/lib/mongodb-ops.js
CHANGED
|
@@ -281,7 +281,7 @@ class MongoDBOps {
|
|
|
281
281
|
}
|
|
282
282
|
return Promise.resolve(result);
|
|
283
283
|
}
|
|
284
|
-
catch (err) { return Promise.reject(err
|
|
284
|
+
catch (err) { return Promise.reject(err); }
|
|
285
285
|
}
|
|
286
286
|
|
|
287
287
|
/**
|
|
@@ -364,7 +364,7 @@ class MongoDBOps {
|
|
|
364
364
|
result = await db.collection(collectionName).bulkWrite(docs, { ordered: ordered });
|
|
365
365
|
return Promise.resolve(result);
|
|
366
366
|
}
|
|
367
|
-
catch (err) { return Promise.reject(err
|
|
367
|
+
catch (err) { return Promise.reject(err); }
|
|
368
368
|
}
|
|
369
369
|
|
|
370
370
|
/**
|
package/package.json
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mongodb-ops",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.2",
|
|
4
4
|
"description": "Read and write ops for MongoDB",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "node --test",
|
|
8
|
-
"lint": "node --check index.js && node --check lib/mongodb-ops.js && node --check test/mongodb-ops.test.js"
|
|
8
|
+
"lint": "node --check index.js && node --check lib/mongodb-ops.js && node --check test/mongodb-ops.test.js && node --check test/mongodb-write-errors.test.js"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"mongodb": "^6.8.0"
|
|
12
12
|
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"mongodb-memory-server": "^11.2.0"
|
|
15
|
+
},
|
|
13
16
|
"repository": {
|
|
14
17
|
"type": "git",
|
|
15
18
|
"url": "git+https://github.com/CompAndSave/mongodb-ops.git"
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Orders Validator
|
|
2
|
+
|
|
3
|
+
`vendor-orders-validator.json` is an unmodified copy of vendor-api's
|
|
4
|
+
`db/validators/orders.json` at commit `303a01b425246b588f027145db04abe53049882e`.
|
|
5
|
+
The real schema is checked in so the integration tests do not depend on a
|
|
6
|
+
separate vendor-api checkout. In particular, `invoice_date: null` must be
|
|
7
|
+
rejected by the same strict validator used by that service.
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$jsonSchema": {
|
|
3
|
+
"bsonType": "object",
|
|
4
|
+
"required": [
|
|
5
|
+
"_id",
|
|
6
|
+
"ts",
|
|
7
|
+
"order_id",
|
|
8
|
+
"vendor",
|
|
9
|
+
"submitted_by",
|
|
10
|
+
"status",
|
|
11
|
+
"address"
|
|
12
|
+
],
|
|
13
|
+
"additionalProperties": false,
|
|
14
|
+
"properties": {
|
|
15
|
+
"_id": {
|
|
16
|
+
"bsonType": "string",
|
|
17
|
+
"pattern": "^EDI-[A-Za-z0-9-]+$",
|
|
18
|
+
"description": "site EDI-<digits> or marketplace EDI-<SELLERCODE>-<rawOrderId>"
|
|
19
|
+
},
|
|
20
|
+
"ts": {
|
|
21
|
+
"bsonType": "date"
|
|
22
|
+
},
|
|
23
|
+
"order_id": {
|
|
24
|
+
"bsonType": "string",
|
|
25
|
+
"pattern": "^[A-Za-z0-9-]+$",
|
|
26
|
+
"description": "site numeric id or marketplace raw order id"
|
|
27
|
+
},
|
|
28
|
+
"vendor": {
|
|
29
|
+
"bsonType": "string",
|
|
30
|
+
"pattern": "^[a-z]+$"
|
|
31
|
+
},
|
|
32
|
+
"vendor_po_num": {
|
|
33
|
+
"bsonType": "string",
|
|
34
|
+
"pattern": "^EDI-[A-Za-z0-9-]+$"
|
|
35
|
+
},
|
|
36
|
+
"submitted_by": {
|
|
37
|
+
"bsonType": "string"
|
|
38
|
+
},
|
|
39
|
+
"status": {
|
|
40
|
+
"bsonType": "string",
|
|
41
|
+
"pattern": "^(?:new|shipped|completed|send_error)$"
|
|
42
|
+
},
|
|
43
|
+
"items": {
|
|
44
|
+
"bsonType": "array",
|
|
45
|
+
"minimum": 1,
|
|
46
|
+
"items": {
|
|
47
|
+
"bsonType": "object",
|
|
48
|
+
"required": [
|
|
49
|
+
"sku",
|
|
50
|
+
"vendor_sku",
|
|
51
|
+
"unit_price",
|
|
52
|
+
"qty"
|
|
53
|
+
],
|
|
54
|
+
"additionalProperties": false,
|
|
55
|
+
"properties": {
|
|
56
|
+
"sku": {
|
|
57
|
+
"bsonType": "string"
|
|
58
|
+
},
|
|
59
|
+
"vendor_sku": {
|
|
60
|
+
"bsonType": "string"
|
|
61
|
+
},
|
|
62
|
+
"unit_price": {
|
|
63
|
+
"bsonType": [
|
|
64
|
+
"int",
|
|
65
|
+
"double"
|
|
66
|
+
]
|
|
67
|
+
},
|
|
68
|
+
"qty": {
|
|
69
|
+
"bsonType": "int"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"total_before_shipping": {
|
|
75
|
+
"bsonType": [
|
|
76
|
+
"int",
|
|
77
|
+
"double"
|
|
78
|
+
]
|
|
79
|
+
},
|
|
80
|
+
"address": {
|
|
81
|
+
"bsonType": "object",
|
|
82
|
+
"required": [
|
|
83
|
+
"company_name",
|
|
84
|
+
"name",
|
|
85
|
+
"address_line1",
|
|
86
|
+
"address_line2",
|
|
87
|
+
"city",
|
|
88
|
+
"state_province",
|
|
89
|
+
"postal_code",
|
|
90
|
+
"country_code"
|
|
91
|
+
],
|
|
92
|
+
"additionalProperties": false,
|
|
93
|
+
"properties": {
|
|
94
|
+
"company_name": {
|
|
95
|
+
"bsonType": "string"
|
|
96
|
+
},
|
|
97
|
+
"name": {
|
|
98
|
+
"bsonType": "string"
|
|
99
|
+
},
|
|
100
|
+
"address_line1": {
|
|
101
|
+
"bsonType": "string"
|
|
102
|
+
},
|
|
103
|
+
"address_line2": {
|
|
104
|
+
"bsonType": "string"
|
|
105
|
+
},
|
|
106
|
+
"city": {
|
|
107
|
+
"bsonType": "string"
|
|
108
|
+
},
|
|
109
|
+
"state_province": {
|
|
110
|
+
"bsonType": "string"
|
|
111
|
+
},
|
|
112
|
+
"postal_code": {
|
|
113
|
+
"bsonType": "string"
|
|
114
|
+
},
|
|
115
|
+
"country_code": {
|
|
116
|
+
"bsonType": "string"
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
"invoice_date": {
|
|
121
|
+
"bsonType": "string",
|
|
122
|
+
"pattern": "^[\\d]{4}-[\\d]{2}-[\\d]{2}$"
|
|
123
|
+
},
|
|
124
|
+
"invoice_id": {
|
|
125
|
+
"bsonType": "string"
|
|
126
|
+
},
|
|
127
|
+
"invoice_total": {
|
|
128
|
+
"bsonType": [
|
|
129
|
+
"int",
|
|
130
|
+
"double"
|
|
131
|
+
]
|
|
132
|
+
},
|
|
133
|
+
"tracking_num": {
|
|
134
|
+
"bsonType": "string"
|
|
135
|
+
},
|
|
136
|
+
"tracking_updated_at": {
|
|
137
|
+
"bsonType": "date",
|
|
138
|
+
"description": "when tracking was last populated on this PO"
|
|
139
|
+
},
|
|
140
|
+
"shipping_cost": {
|
|
141
|
+
"bsonType": [
|
|
142
|
+
"int",
|
|
143
|
+
"double"
|
|
144
|
+
]
|
|
145
|
+
},
|
|
146
|
+
"carrier": {
|
|
147
|
+
"bsonType": "string"
|
|
148
|
+
},
|
|
149
|
+
"signature_requested": {
|
|
150
|
+
"bsonType": "bool"
|
|
151
|
+
},
|
|
152
|
+
"channel": {
|
|
153
|
+
"bsonType": "string"
|
|
154
|
+
},
|
|
155
|
+
"seller_account": {
|
|
156
|
+
"bsonType": [
|
|
157
|
+
"string",
|
|
158
|
+
"null"
|
|
159
|
+
]
|
|
160
|
+
},
|
|
161
|
+
"seller_code": {
|
|
162
|
+
"bsonType": [
|
|
163
|
+
"string",
|
|
164
|
+
"null"
|
|
165
|
+
]
|
|
166
|
+
},
|
|
167
|
+
"marketplace_id": {
|
|
168
|
+
"bsonType": [
|
|
169
|
+
"string",
|
|
170
|
+
"null"
|
|
171
|
+
]
|
|
172
|
+
},
|
|
173
|
+
"raw_order_id": {
|
|
174
|
+
"bsonType": [
|
|
175
|
+
"string",
|
|
176
|
+
"null"
|
|
177
|
+
]
|
|
178
|
+
},
|
|
179
|
+
"source_order_id": {
|
|
180
|
+
"bsonType": "string"
|
|
181
|
+
},
|
|
182
|
+
"send_error": {
|
|
183
|
+
"bsonType": "string"
|
|
184
|
+
},
|
|
185
|
+
"marketplace_writeback_status": {
|
|
186
|
+
"bsonType": "string"
|
|
187
|
+
},
|
|
188
|
+
"marketplace_writeback_attempt_at": {
|
|
189
|
+
"bsonType": "date"
|
|
190
|
+
},
|
|
191
|
+
"marketplace_writeback_channel": {
|
|
192
|
+
"bsonType": "string"
|
|
193
|
+
},
|
|
194
|
+
"marketplace_writeback_error": {
|
|
195
|
+
"bsonType": [
|
|
196
|
+
"string",
|
|
197
|
+
"null"
|
|
198
|
+
]
|
|
199
|
+
},
|
|
200
|
+
"marketplace_writeback_confirmed_at": {
|
|
201
|
+
"bsonType": "date"
|
|
202
|
+
},
|
|
203
|
+
"marketplace_writeback_carrier": {
|
|
204
|
+
"bsonType": "string"
|
|
205
|
+
},
|
|
206
|
+
"marketplace_writeback_tracking_number": {
|
|
207
|
+
"bsonType": "string"
|
|
208
|
+
},
|
|
209
|
+
"marketplace_writeback_failed_at": {
|
|
210
|
+
"bsonType": "date"
|
|
211
|
+
},
|
|
212
|
+
"marketplace_writeback_http_status": {
|
|
213
|
+
"bsonType": [
|
|
214
|
+
"int",
|
|
215
|
+
"double",
|
|
216
|
+
"null"
|
|
217
|
+
]
|
|
218
|
+
},
|
|
219
|
+
"marketplace_writeback_last_error_at": {
|
|
220
|
+
"bsonType": "date"
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const test = require('node:test');
|
|
4
|
+
const assert = require('node:assert/strict');
|
|
5
|
+
const { MongoMemoryServer } = require('mongodb-memory-server');
|
|
6
|
+
const { MongoDBToolSet } = require('..');
|
|
7
|
+
const validator = require('./fixtures/vendor-orders-validator.json');
|
|
8
|
+
|
|
9
|
+
const order = (id) => ({
|
|
10
|
+
_id: id,
|
|
11
|
+
ts: new Date('2026-01-01T00:00:00.000Z'),
|
|
12
|
+
order_id: id.replace(/^EDI-/, ''),
|
|
13
|
+
vendor: 'acm',
|
|
14
|
+
submitted_by: 'test',
|
|
15
|
+
status: 'new',
|
|
16
|
+
address: {
|
|
17
|
+
company_name: '',
|
|
18
|
+
name: 'Test Recipient',
|
|
19
|
+
address_line1: '1 Main St',
|
|
20
|
+
address_line2: '',
|
|
21
|
+
city: 'Los Angeles',
|
|
22
|
+
state_province: 'CA',
|
|
23
|
+
postal_code: '90001',
|
|
24
|
+
country_code: 'US'
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
async function rejection(promise) {
|
|
29
|
+
try {
|
|
30
|
+
await promise;
|
|
31
|
+
} catch (error) {
|
|
32
|
+
return error;
|
|
33
|
+
}
|
|
34
|
+
assert.fail('Expected the real MongoDB write to reject');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
test('real MongoDB write errors retain their diagnostic detail', async (t) => {
|
|
38
|
+
const mongod = await MongoMemoryServer.create();
|
|
39
|
+
try {
|
|
40
|
+
const connString = mongod.getUri('write_error_test');
|
|
41
|
+
const client = await MongoDBToolSet.getDbClient(connString);
|
|
42
|
+
await client.db().createCollection('orders', {
|
|
43
|
+
validator,
|
|
44
|
+
validationLevel: 'strict',
|
|
45
|
+
validationAction: 'error'
|
|
46
|
+
});
|
|
47
|
+
await MongoDBToolSet.insertOne('orders', order('EDI-1001'), connString);
|
|
48
|
+
|
|
49
|
+
const single = await rejection(MongoDBToolSet.updateOne(
|
|
50
|
+
'orders', { $set: { invoice_date: null } }, { _id: 'EDI-1001' }, connString
|
|
51
|
+
));
|
|
52
|
+
const bulk = await rejection(MongoDBToolSet.updateBulkUnOrdered('orders', [{
|
|
53
|
+
filter: { _id: 'EDI-1001' },
|
|
54
|
+
update: { $set: { invoice_date: null } }
|
|
55
|
+
}], connString));
|
|
56
|
+
const duplicate = await rejection(MongoDBToolSet.insertOne(
|
|
57
|
+
'orders', order('EDI-1001'), connString
|
|
58
|
+
));
|
|
59
|
+
|
|
60
|
+
await t.test('G0: single-write rejection is an Error, not a string or copied object', () => {
|
|
61
|
+
assert.ok(single instanceof Error, 'single-write rejection must be an Error');
|
|
62
|
+
});
|
|
63
|
+
await t.test('G0: bulk-write rejection is an Error, not a BulkWriteResult or copied object', () => {
|
|
64
|
+
assert.ok(bulk instanceof Error, 'bulk-write rejection must be an Error');
|
|
65
|
+
});
|
|
66
|
+
await t.test('G1: updateOne retains the real validator field diagnostic', () => {
|
|
67
|
+
const rules = single?.errInfo?.details?.schemaRulesNotSatisfied;
|
|
68
|
+
assert.ok(Array.isArray(rules), 'updateOne must retain errInfo.details.schemaRulesNotSatisfied');
|
|
69
|
+
assert.equal(single.code, 121);
|
|
70
|
+
assert.match(JSON.stringify(rules), /"propertyName":"invoice_date"/);
|
|
71
|
+
});
|
|
72
|
+
await t.test('G2: bulk rejection exposes writeErrors directly with the validator detail', () => {
|
|
73
|
+
assert.ok(Array.isArray(bulk?.writeErrors), 'bulk rejection must expose writeErrors directly');
|
|
74
|
+
assert.equal(bulk.writeErrors.length, 1);
|
|
75
|
+
assert.equal(bulk.writeErrors[0].code, 121);
|
|
76
|
+
const rules = bulk.writeErrors[0].err.errInfo.details.schemaRulesNotSatisfied;
|
|
77
|
+
assert.match(JSON.stringify(rules), /"propertyName":"invoice_date"/);
|
|
78
|
+
});
|
|
79
|
+
await t.test('G3: duplicate-key rejection retains MongoDB code 11000', () => {
|
|
80
|
+
assert.equal(duplicate?.code, 11000, 'duplicate-key rejection must retain code 11000');
|
|
81
|
+
});
|
|
82
|
+
} finally {
|
|
83
|
+
try {
|
|
84
|
+
await MongoDBToolSet.closeDBConn();
|
|
85
|
+
} finally {
|
|
86
|
+
await mongod.stop();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
});
|
package/mongodb-ops-0.11.1.tgz
DELETED
|
Binary file
|