StatusWith<std::unique_ptr<CollatorInterface>> CollatorFactoryICU::makeFromBSON(
    const BSONObj& spec) {
    // Parse the locale ID out of the spec.
    auto parsedLocaleID = parseLocaleID(spec);
    if (!parsedLocaleID.isOK()) {
        return parsedLocaleID.getStatus();
    }

    // If spec = {locale: "simple"}, return a null pointer. A null CollatorInterface indicates
    // simple binary compare.
    if (parsedLocaleID.getValue() == CollationSpec::kSimpleBinaryComparison) {
        if (spec.nFields() > 1) {
            return {ErrorCodes::FailedToParse,
                    str::stream() << "If " << CollationSpec::kLocaleField << "="
                                  << CollationSpec::kSimpleBinaryComparison
                                  << ", no other fields should be present in: " << spec};
        }
        return {nullptr};
    }

    // Construct an icu::Locale.
    auto userLocale = icu::Locale::createFromName(parsedLocaleID.getValue().c_str());
    if (userLocale.isBogus()) {
        return {ErrorCodes::BadValue,
                str::stream() << "Field '" << CollationSpec::kLocaleField
                              << "' is not valid in: " << spec};
    }

    // Construct an icu::Collator.
    UErrorCode status = U_ZERO_ERROR;
    std::unique_ptr<icu::Collator> icuCollator(icu::Collator::createInstance(userLocale, status));
    if (U_FAILURE(status)) {
        icu::ErrorCode icuError;
        icuError.set(status);
        return {ErrorCodes::OperationFailed,
                str::stream() << "Failed to create collator: " << icuError.errorName()
                              << ". Collation spec: " << spec};
    }

    Status localeValidationStatus = validateLocaleID(spec, parsedLocaleID.getValue(), *icuCollator);
    if (!localeValidationStatus.isOK()) {
        return localeValidationStatus;
    }

    // Construct a CollationSpec using the options provided in spec or the defaults in icuCollator.
    // Use userLocale.getName() for the localeID, since it is canonicalized and includes options.
    auto parsedSpec = parseToCollationSpec(spec, userLocale.getName(), icuCollator.get());
    if (!parsedSpec.isOK()) {
        return parsedSpec.getStatus();
    }

    auto mongoCollator = stdx::make_unique<CollatorInterfaceICU>(std::move(parsedSpec.getValue()),
                                                                 std::move(icuCollator));
    return {std::move(mongoCollator)};
}
Example #2
0
StatusWith<std::unique_ptr<CollatorInterface>> CollatorFactoryICU::makeFromBSON(
    const BSONObj& spec) {
    // Parse the locale ID out of the spec.
    auto parsedLocaleID = parseLocaleID(spec);
    if (!parsedLocaleID.isOK()) {
        return parsedLocaleID.getStatus();
    }

    // Check that the locale ID is recognizable by ICU.
    if (!isValidLocale(parsedLocaleID.getValue())) {
        return {ErrorCodes::BadValue,
                str::stream() << "Field '" << CollationSpec::kLocaleField
                              << "' is not a valid ICU locale in: " << spec};
    }

    // Construct an icu::Locale.
    auto locale = icu::Locale::createFromName(parsedLocaleID.getValue().c_str());

    // Construct an icu::Collator.
    UErrorCode status = U_ZERO_ERROR;
    std::unique_ptr<icu::Collator> icuCollator(icu::Collator::createInstance(locale, status));
    if (U_FAILURE(status)) {
        icu::ErrorCode icuError;
        icuError.set(status);
        return {ErrorCodes::OperationFailed,
                str::stream() << "Failed to create collator: " << icuError.errorName()
                              << ". Collation spec: " << spec};
    }

    // Construct a CollationSpec using the options provided in spec or the defaults in icuCollator.
    // Use locale.getName() for the localeID, since it is canonicalized and includes options.
    auto parsedSpec = parseToCollationSpec(spec, locale.getName(), icuCollator.get());
    if (!parsedSpec.isOK()) {
        return parsedSpec.getStatus();
    }

    auto mongoCollator = stdx::make_unique<CollatorInterfaceICU>(std::move(parsedSpec.getValue()),
                                                                 std::move(icuCollator));
    return {std::move(mongoCollator)};
}