Skip to content

Commit 80b2e3c

Browse files
refactor: fallback to modifyOneMethod with query COMPASS-6058 (#4373)
* refactor: fallback to modifyOneMethod with query COMPASS-6058 * refactor: remove unused variable * refactor: bring back comments
1 parent 527952d commit 80b2e3c

File tree

2 files changed

+35
-58
lines changed

2 files changed

+35
-58
lines changed

packages/compass-crud/src/stores/crud-store.spec.ts

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2017,7 +2017,6 @@ describe('store', function () {
20172017
let updateOneFake;
20182018
let replaceOneFake;
20192019

2020-
const document = { _id: 1234, name: 'document_1234' };
20212020
const updatedDocument = { _id: 1234, name: 'document_12345' };
20222021

20232022
beforeEach(function () {
@@ -2123,12 +2122,12 @@ describe('store', function () {
21232122
});
21242123
});
21252124

2126-
it('retries findOneAndUpdate with FLE returnDocument: "after"', async function () {
2125+
it('does updateOne with FLE returnDocument: "after"', async function () {
21272126
const err = Object.assign(new Error('failed'), { code: 6371402 });
21282127
findFake.callsFake(() => Promise.resolve([updatedDocument]));
21292128
findOneAndReplaceFake.resolves({});
21302129
findOneAndUpdateFake.onCall(0).rejects(err);
2131-
findOneAndUpdateFake.onCall(1).resolves(document);
2130+
updateOneFake.onCall(0).resolves({});
21322131
const [error, d] = await findAndModifyWithFLEFallback(
21332132
dataServiceStub,
21342133
'db.coll',
@@ -2138,7 +2137,7 @@ describe('store', function () {
21382137
);
21392138
expect(error).to.equal(undefined);
21402139
expect(d).to.deep.equal(updatedDocument);
2141-
expect(findOneAndUpdateFake).to.have.callCount(2);
2140+
expect(findOneAndUpdateFake).to.have.callCount(1);
21422141

21432142
expect(findOneAndUpdateFake.firstCall.args[0]).to.equal('db.coll');
21442143
expect(findOneAndUpdateFake.firstCall.args[1]).to.deep.equal({
@@ -2152,23 +2151,18 @@ describe('store', function () {
21522151
promoteValues: false,
21532152
});
21542153

2155-
expect(findOneAndUpdateFake.secondCall.args[0]).to.equal('db.coll');
2156-
expect(findOneAndUpdateFake.secondCall.args[1]).to.deep.equal({
2154+
expect(updateOneFake.firstCall.args[0]).to.equal('db.coll');
2155+
expect(updateOneFake.firstCall.args[1]).to.deep.equal({
21572156
_id: 1234,
21582157
});
2159-
expect(findOneAndUpdateFake.secondCall.args[2]).to.deep.equal({
2158+
expect(updateOneFake.firstCall.args[2]).to.deep.equal({
21602159
name: 'document_12345',
21612160
});
2162-
expect(findOneAndUpdateFake.secondCall.args[3]).to.deep.equal({
2163-
returnDocument: 'before',
2164-
promoteValues: false,
2165-
});
21662161

21672162
expect(findFake).to.have.callCount(1);
21682163
expect(findFake.firstCall.args[0]).to.equal('db.coll');
21692164
expect(findFake.firstCall.args[1]).to.deep.equal({ _id: 1234 });
21702165
expect(findFake.firstCall.args[2]).to.deep.equal({
2171-
returnDocument: 'before',
21722166
promoteValues: false,
21732167
});
21742168
});
@@ -2178,7 +2172,7 @@ describe('store', function () {
21782172
findFake.yields(new Error('find failed'));
21792173
findOneAndReplaceFake.resolves({});
21802174
findOneAndUpdateFake.onCall(0).rejects(err);
2181-
findOneAndUpdateFake.onCall(1).resolves(document);
2175+
updateOneFake.onCall(0).resolves({});
21822176
const [error, d] = await findAndModifyWithFLEFallback(
21832177
dataServiceStub,
21842178
'db.coll',
@@ -2188,7 +2182,8 @@ describe('store', function () {
21882182
);
21892183
expect(error).to.equal(err);
21902184
expect(d).to.equal(undefined);
2191-
expect(findOneAndUpdateFake).to.have.callCount(2);
2185+
expect(findOneAndUpdateFake).to.have.callCount(1);
2186+
expect(updateOneFake).to.have.callCount(1);
21922187
expect(findFake).to.have.callCount(1);
21932188
});
21942189

packages/compass-crud/src/stores/crud-store.ts

Lines changed: 26 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1575,67 +1575,49 @@ export async function findAndModifyWithFLEFallback(
15751575
object: { $set?: BSONObject; $unset?: BSONObject } | BSONObject | BSONArray,
15761576
modificationType: 'update' | 'replace'
15771577
): Promise<ErrorOrResult> {
1578-
let options: { returnDocument: 'before' | 'after'; promoteValues: false } = {
1579-
returnDocument: 'after',
1580-
promoteValues: false,
1581-
};
1582-
let error: (Error & { codeName?: string; code?: any }) | undefined;
1583-
let document;
1584-
15851578
const findOneAndModifyMethod =
15861579
modificationType === 'update' ? 'findOneAndUpdate' : 'findOneAndReplace';
1587-
const modifyOneMethod =
1588-
modificationType === 'update' ? 'updateOne' : 'replaceOne';
1580+
let error: (Error & { codeName?: string; code?: any }) | undefined;
15891581

15901582
try {
1591-
document = await ds[findOneAndModifyMethod](ns, query, object, options);
1583+
return [
1584+
undefined,
1585+
await ds[findOneAndModifyMethod](ns, query, object, {
1586+
returnDocument: 'after',
1587+
promoteValues: false,
1588+
}),
1589+
] as ErrorOrResult;
15921590
} catch (e) {
15931591
error = e as Error;
15941592
}
15951593

1596-
if (!error) {
1597-
return [undefined, document] as ErrorOrResult;
1598-
}
1594+
if (
1595+
error.codeName === 'ShardKeyNotFound' ||
1596+
+(error?.code ?? 0) === 63714_02 // 6371402 is "'findAndModify with encryption only supports new: false'"
1597+
) {
1598+
const modifyOneMethod =
1599+
modificationType === 'update' ? 'updateOne' : 'replaceOne';
15991600

1600-
if (error.codeName === 'ShardKeyNotFound') {
16011601
try {
1602-
const docs = await ds.find(ns, query, options);
1603-
[document] = docs;
1602+
await ds[modifyOneMethod](ns, query, object);
16041603
} catch (e) {
1605-
return [e, undefined] as ErrorOrResult;
1606-
}
1607-
1608-
if (document) {
1609-
try {
1610-
await ds[modifyOneMethod](ns, { _id: document._id }, object);
1611-
} catch (e) {
1612-
return [e, undefined] as ErrorOrResult;
1613-
}
1614-
}
1615-
} else if (+(error?.code ?? 0) === 63714_02) {
1616-
// 6371402 is "'findAndModify with encryption only supports new: false'"
1617-
options = {
1618-
returnDocument: 'before',
1619-
promoteValues: false,
1620-
};
1621-
try {
1622-
document = await ds[findOneAndModifyMethod](ns, query, object, options);
1623-
} catch (e) {
1624-
// Return the current findOneAndModify error here
1625-
// since we already know the exact error from the previous attempt
1626-
// and want to know what went wrong with the second attempt with the fallback options,
1604+
// Return the modifyOneMethod error here
1605+
// since we already know the original error from findOneAndModifyMethod
1606+
// and want to know what went wrong with the fallback method,
16271607
// e.g. return the `Found indexed encrypted fields but could not find __safeContent__` error.
16281608
return [e, undefined] as ErrorOrResult;
16291609
}
1630-
}
16311610

1632-
try {
1633-
if (document) {
1634-
const docs = await ds.find(ns, { _id: document._id }, options);
1611+
try {
1612+
const docs = await ds.find(
1613+
ns,
1614+
{ _id: query._id as any },
1615+
{ promoteValues: false }
1616+
);
16351617
return [undefined, docs[0]] as ErrorOrResult;
1618+
} catch (e) {
1619+
/* fallthrough */
16361620
}
1637-
} catch (e) {
1638-
/* fallthrough */
16391621
}
16401622

16411623
// Race condition -- most likely, somebody else

0 commit comments

Comments
 (0)