0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-11-21 20:49:10 +01:00

SERVER-93678: Add a shell utility function to compare strings given a collation object (#26234)

GitOrigin-RevId: 6480e21ac48c379052ece62f0efb9e60771cb2ea
This commit is contained in:
Projjal Chanda 2024-08-27 16:10:55 +05:30 committed by MongoDB Bot
parent 84ca7a7728
commit cfe3e7e4d1
4 changed files with 93 additions and 0 deletions

View File

@ -150,6 +150,7 @@ globals:
_fnvHashToHexString: true
_resultSetsEqualUnordered: true
getStringWidth: true
_compareStringsWithCollation: true
# likely could be replaced with `path`
_copyFileRange: true

View File

@ -0,0 +1,59 @@
/**
* Tests the shell util '_compareStringsWithCollation'
*/
assert.eq(_compareStringsWithCollation("abc", "abc", {locale: "en_US"}), 0);
assert.gt(_compareStringsWithCollation("bcd", "abc", {locale: "en_US"}), 0);
assert.lt(_compareStringsWithCollation("abc", "ABC", {locale: "en_US"}), 0);
// zero length strings and null bytes
assert.eq(_compareStringsWithCollation("", "", {locale: "en_US"}), 0);
assert.gt(_compareStringsWithCollation("abc", "", {locale: "en_US"}), 0);
assert.gt(_compareStringsWithCollation("abc", "", {locale: "en_US", strength: 2}), 0);
assert.eq(_compareStringsWithCollation("\0", "", {locale: "en_US"}), 0);
assert.lt(_compareStringsWithCollation("\0", "ab", {locale: "en_US"}), 0);
assert.gt(_compareStringsWithCollation("a\0c", "a\0b", {locale: "en_US"}), 0);
assert.eq(_compareStringsWithCollation("a", "a\0", {locale: "en_US"}), 0);
// case-level and diatrics
assert.eq(_compareStringsWithCollation("abc", "ABC", {locale: "en_US", strength: 1}), 0);
assert.eq(_compareStringsWithCollation("abc", "ABC", {locale: "en_US", strength: 2}), 0);
assert.lt(_compareStringsWithCollation("abc", "ABC", {locale: "en_US", strength: 3}), 0);
assert.lt(
_compareStringsWithCollation("abc", "ABC", {locale: "en_US", strength: 1, caseLevel: true}), 0);
assert.lt(
_compareStringsWithCollation("abc", "ABC", {locale: "en_US", strength: 2, caseLevel: true}), 0);
assert.eq(_compareStringsWithCollation("eaio", "éáïô", {locale: "en_US", strength: 1}), 0);
assert.lt(_compareStringsWithCollation("eaio", "éáïô", {locale: "en_US", strength: 2}), 0);
assert.gt(_compareStringsWithCollation("abc", "ABC", {locale: "en_US", caseFirst: "upper"}), 0);
assert.lt(_compareStringsWithCollation("abc", "ABC", {locale: "en_US", caseFirst: "lower"}), 0);
// numeric ordering
assert.gt(_compareStringsWithCollation("10", "2", {locale: "en_US", numericOrdering: true}), 0);
assert.lt(_compareStringsWithCollation("10", "2", {locale: "en_US", numericOrdering: false}), 0);
// Ignore whitespace and punctuation
assert.eq(_compareStringsWithCollation("a b, c", "abc", {locale: "en_US", alternate: "shifted"}),
0);
assert.neq(_compareStringsWithCollation(
"a b, c", "abc", {locale: "en_US", strength: 4, alternate: "shifted"}),
0);
assert.eq(_compareStringsWithCollation(
"a b, c", "abc", {locale: "en_US", alternate: "shifted", maxVariable: "punct"}),
0);
assert.neq(_compareStringsWithCollation(
"a b, c", "abc", {locale: "en_US", alternate: "shifted", maxVariable: "space"}),
0);
assert.eq(_compareStringsWithCollation(
"a b c", "abc", {locale: "en_US", alternate: "shifted", maxVariable: "space"}),
0);
// error cases
assert.throwsWithCode(() => _compareStringsWithCollation("", ""), 9367804);
assert.throwsWithCode(() => _compareStringsWithCollation(1, "", {locale: "en_US"}), 9367801);
assert.throwsWithCode(() => _compareStringsWithCollation("", 1, {locale: "en_US"}), 9367803);
assert.throwsWithCode(() => _compareStringsWithCollation({a: ""}, "", {locale: "en_US"}), 9367801);
assert.throwsWithCode(() => _compareStringsWithCollation("", "", ""), 9367805);
assert.throwsWithCode(() => _compareStringsWithCollation("", "", {}), 40414);

View File

@ -116,6 +116,7 @@ env.Library(
LIBDEPS_PRIVATE=[
"$BUILD_DIR/mongo/bson/util/bson_column",
"$BUILD_DIR/mongo/db/auth/security_token_auth",
"$BUILD_DIR/mongo/db/query/collation/collator_icu",
"$BUILD_DIR/mongo/db/storage/record_store_base",
"$BUILD_DIR/mongo/util/icu",
"program_runner",

View File

@ -75,6 +75,7 @@
#include "mongo/db/auth/validated_tenancy_scope_factory.h"
#include "mongo/db/database_name.h"
#include "mongo/db/hasher.h"
#include "mongo/db/query/collation/collator_factory_icu.h"
#include "mongo/platform/decimal128.h"
#include "mongo/platform/mutex.h"
#include "mongo/platform/random.h"
@ -993,6 +994,36 @@ BSONObj _resultSetsEqualUnordered(const BSONObj& input, void*) {
return BSON("" << true);
}
/*
* Takes two strings and a valid collation document and returns the comparison result (a number < 0
* if 'left' is less than 'right', a number > 0 if 'left' is greater than 'right', and 0 if 'left'
* and 'right' are equal) with respect to the collation
* Refer to https://www.mongodb.com/docs/manual/reference/collation and
* https://unicode-org.github.io/icu/userguide/collation for the expected behaviour when collation
* is specified
*/
BSONObj _compareStringsWithCollation(const BSONObj& input, void*) {
BSONObjIterator i(input);
uassert(9367800, "Expected left argument", i.more());
auto left = i.next();
uassert(9367801, "Left argument should be a string", left.type() == BSONType::String);
uassert(9367802, "Expected right argument", i.more());
auto right = i.next();
uassert(9367803, "Right argument should be string", right.type() == BSONType::String);
uassert(9367804, "Expected collation argument", i.more());
auto collatorSpec = i.next();
uassert(9367805, "Expected a collation object", collatorSpec.type() == BSONType::Object);
CollatorFactoryICU collationFactory;
auto collator = uassertStatusOK(collationFactory.makeFromBSON(collatorSpec.Obj()));
int cmp = collator->compare(left.valueStringData(), right.valueStringData());
return BSON("" << cmp);
}
void installShellUtils(Scope& scope) {
scope.injectNative("getMemInfo", JSGetMemInfo);
scope.injectNative("_createSecurityToken", _createSecurityToken);
@ -1016,6 +1047,7 @@ void installShellUtils(Scope& scope) {
scope.injectNative("_buildBsonObj", _buildBsonObj);
scope.injectNative("_fnvHashToHexString", _fnvHashToHexString);
scope.injectNative("_resultSetsEqualUnordered", _resultSetsEqualUnordered);
scope.injectNative("_compareStringsWithCollation", _compareStringsWithCollation);
installShellUtilsLauncher(scope);
installShellUtilsExtended(scope);