Skip to content

Commit 229c9a3

Browse files
authored
feat(shell-api): add convertShardKeyToHashed() MONGOSH-1050 (#1364)
1 parent 036245a commit 229c9a3

File tree

6 files changed

+61
-1
lines changed

6 files changed

+61
-1
lines changed

packages/cli-repl/test/e2e.spec.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,13 @@ describe('e2e', function() {
523523
expect(await shell.executeLine('typeof JSON.parse(JSON.stringify(db.test.insertOne({}))).insertedId')).to.include('string');
524524
});
525525

526+
context('post-4.2', () => {
527+
skipIfServerVersion(testServer, '< 4.4');
528+
it('allows calling convertShardKeyToHashed() as a global function', async function() {
529+
expect(await shell.executeLine('convertShardKeyToHashed({foo:"bar"})')).to.include('Long("4975617422686807705")');
530+
});
531+
});
532+
526533
describe('document validation errors', () => {
527534
context('post-4.4', () => {
528535
skipIfServerVersion(testServer, '<= 4.4');

packages/connectivity-tests/test/atlas.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ fi
3838

3939
FAILED=no
4040

41-
CONNECTION_STATUS_COMMAND='db.runCommand({ connectionStatus: 1 }).authInfo.authenticatedUsers'
41+
# convertShardKeyToHashed() may seem weird to include here, but it's the best
42+
# way to make sure that it works in our standard environments we connect to
43+
CONNECTION_STATUS_COMMAND='convertShardKeyToHashed("asdf");db.runCommand({ connectionStatus: 1 }).authInfo.authenticatedUsers'
4244
CONNECTION_STATUS_CHECK_STRING="user: '${ATLAS_USERNAME}'"
4345

4446
function check_failed() {

packages/i18n/src/locales/en_US.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,10 @@ const translations: Catalog = {
168168
},
169169
isInteractive: {
170170
description: 'Returns whether the shell will enter or has entered interactive mode'
171+
},
172+
convertShardKeyToHashed: {
173+
description: 'Returns the hashed value for the input using the same hashing function as a hashed index.',
174+
link: 'https://www.mongodb.com/docs/manual/reference/method/convertShardKeyToHashed/'
171175
}
172176
}
173177
},
@@ -1798,6 +1802,10 @@ const translations: Catalog = {
17981802
getClientEncryption: {
17991803
description: 'Returns the ClientEncryption object for the current database collection. The ClientEncryption object supports explicit (manual) encryption and decryption of field values for Client-Side field level encryption.',
18001804
link: 'https://docs.mongodb.com/manual/reference/method/getClientEncryption/#getClientEncryption'
1805+
},
1806+
convertShardKeyToHashed: {
1807+
description: 'Returns the hashed value for the input using the same hashing function as a hashed index.',
1808+
link: 'https://www.mongodb.com/docs/manual/reference/method/convertShardKeyToHashed/'
18011809
}
18021810
}
18031811
},

packages/shell-api/src/integration.spec.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2047,6 +2047,15 @@ describe('Shell API (integration)', function() {
20472047
}
20482048
});
20492049
});
2050+
describe('convertShardKeyToHashed', () => {
2051+
skipIfServerVersion(testServer, '< 4.4');
2052+
2053+
it('converts a shard key to its hashed representation', async() => {
2054+
const result = await mongo.convertShardKeyToHashed({ foo: 'bar' });
2055+
expect(result.constructor.name).to.equal('Long');
2056+
expect(result.toString()).to.equal('4975617422686807705');
2057+
});
2058+
});
20502059
});
20512060
describe('PlanCache', () => {
20522061
skipIfApiStrict();

packages/shell-api/src/mongo.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,4 +667,33 @@ export default class Mongo extends ShellApiClass {
667667
}
668668
return this._keyVault;
669669
}
670+
671+
@returnsPromise
672+
async convertShardKeyToHashed(value: any): Promise<unknown> {
673+
const pipeline = [
674+
{ $limit: 1 },
675+
{ $project: { _id: { $toHashedIndexKey: { $literal: value } } } }
676+
];
677+
let result;
678+
try {
679+
// Try $documents if available.
680+
result = await (await this.getDB('admin').aggregate([ { $documents: [{}] }, ...pipeline ])).next();
681+
} catch {
682+
try {
683+
// If that fails, try a default collection like admin.system.version.
684+
result = await (await this.getDB('admin').getCollection('system.version').aggregate(pipeline)).next();
685+
} catch {
686+
// If that fails, try using $collStats for local.oplog.rs.
687+
try {
688+
result = await (await this.getDB('local').getCollection('oplog.rs').aggregate([ { $collStats: {} }, ...pipeline ])).next();
689+
} catch { /* throw exception below */ }
690+
}
691+
}
692+
if (!result) {
693+
throw new MongoshRuntimeError(
694+
'Could not find a suitable way to run convertShardKeyToHashed() -- tried $documents and aggregating on admin.system.version and local.oplog.rs',
695+
CommonErrors.CommandFailed);
696+
}
697+
return result._id;
698+
}
670699
}

packages/shell-api/src/shell-api.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,11 @@ export default class ShellApi extends ShellApiClass {
316316
await this._print(origArgs, 'printjson');
317317
}
318318

319+
@returnsPromise
320+
async convertShardKeyToHashed(value: any): Promise<unknown> {
321+
return this._instanceState.currentDb._mongo.convertShardKeyToHashed(value);
322+
}
323+
319324
@directShellCommand
320325
@returnsPromise
321326
async cls(): Promise<void> {

0 commit comments

Comments
 (0)