Skip to content

Commit

Permalink
fix RQL string comparisons
Browse files Browse the repository at this point in the history
  • Loading branch information
ironage committed Jan 22, 2024
1 parent e2ba874 commit 23d5873
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 40 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

### Enhancements
* <New feature description> (PR [#????](https://github.com/realm/realm-core/pull/????))
* Allow the query builder to construct >, >=, <, <= queries for string constants. This is a case sensitive lexicographical comparison. ([#3939](https://github.com/realm/realm-core/issues/3939), this is a prerequisite for https://github.com/realm/realm-swift/issues/8008)
* Allow the query builder to construct >, >=, <, <= queries for string constants. This is a case sensitive lexicographical comparison. Improved performance of RQL (parsed) queries on a non-linked string property using: >, >=, <, <=, operators and fixed behaviour that a null string should be evaulated as less than everything, previously nulls were not matched. ([#3939](https://github.com/realm/realm-core/issues/3939), this is a prerequisite for https://github.com/realm/realm-swift/issues/8008).

### Fixed
* <How do the end-user experience this issue? what was the impact?> ([#????](https://github.com/realm/realm-core/issues/????), since v?.?.?)
Expand All @@ -17,7 +17,7 @@
-----------

### Internals
* None
* Expressions in `CHECK()` macros are printed to better; strings are quoted and null strings are printed as NULL instead of no output.

----------------------------------------------

Expand Down
2 changes: 1 addition & 1 deletion src/realm/parser/driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ Query RelationalNode::visit(ParserDriver* drv)
case type_Bool:
break;
case type_String:
break;
return drv->simple_query(op, col_key, right->get_mixed().get_string());
case type_Binary:
break;
case type_Timestamp:
Expand Down
34 changes: 10 additions & 24 deletions test/test_query.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -500,16 +500,6 @@ TEST(Query_NextGen_StringConditions)
cnt = table2->column<String>(col_str3).like(realm::null(), false).count();
CHECK_EQUAL(cnt, 1);

auto print_result = [](std::vector<StringData>& results) -> std::string {
std::string print;
for (auto s : results) {
print += print.empty() ? "{" : ", ";
print += util::serializer::print_value(s);
}
print += print.empty() ? "{}" : "}";
return print;
};

auto check_results = [&](Query q, std::vector<StringData>&& matches) {
TableView view = q.find_all();
std::sort(matches.begin(), matches.end());
Expand All @@ -518,24 +508,20 @@ TEST(Query_NextGen_StringConditions)
actual.push_back(view.get_object(i).get<StringData>(col_str3));
}
std::sort(actual.begin(), actual.end());
bool all_matches = true;
if (actual.size() == matches.size()) {
for (size_t i = 0; i < matches.size(); ++i) {
if (actual[i] != matches[i]) {
all_matches = false;
break;
}
}
if (!CHECK_EQUAL(actual, matches)) {
util::format(std::cout, "failed query '%1'\n", q.get_description());
}
else {
all_matches = false;
TableView parsed_results = table2->query(q.get_description()).find_all();
std::vector<StringData> parsed_matches;
for (size_t i = 0; i < parsed_results.size(); ++i) {
parsed_matches.push_back(parsed_results.get_object(i).get<StringData>(col_str3));
}
CHECK(all_matches);
if (!all_matches) {
util::format(std::cout, "mismatch results of '%1': expected: %2 actual: %3\n", q.get_description(),
print_result(matches), print_result(actual));
std::sort(parsed_matches.begin(), parsed_matches.end());
if (!CHECK_EQUAL(parsed_matches, matches)) {
util::format(std::cout, "failed parsed query '%1'\n", q.get_description());
}
};

// greater
check_results((table2->column<String>(col_str3) > StringData("")), {"foo", "bar", "!"});
check_results((table2->column<String>(col_str3) > StringData("b")), {"foo", "bar"});
Expand Down
41 changes: 28 additions & 13 deletions test/util/unit_test.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <realm/util/features.h>
#include <realm/util/logger.hpp>
#include <realm/util/safe_int_ops.hpp>
#include <realm/util/serializer.hpp>


#define TEST(name) TEST_IF(name, true)
Expand Down Expand Up @@ -751,7 +752,6 @@ inline bool definitely_less(long double a, long double b, long double epsilon)
return b - a > std::max(std::abs(a), std::abs(b)) * epsilon;
}


template <class T, bool is_float>
struct SetPrecision {
static void exec(std::ostream&)
Expand All @@ -767,14 +767,21 @@ struct SetPrecision<T, true> {
}
};

template <typename T>
constexpr static bool realm_serializable_types = is_any_v<T, StringData, BinaryData, Timestamp, ObjectId, std::optional<ObjectId>, ObjKey, ObjLink, UUID, std::optional<UUID>, bool, float, std::optional<float>, double, std::optional<double>, realm::null>;

template <class T>
void to_string(const T& value, std::string& str)
{
// FIXME: Put string values in quotes, and escape non-printables as well as '"' and '\\'.
std::ostringstream out;
SetPrecision<T, std::is_floating_point<T>::value>::exec(out);
out << value;
str = out.str();
if constexpr (realm_serializable_types<T>) {
str = util::serializer::print_value(value);
}
else {
std::ostringstream out;
SetPrecision<T, std::is_floating_point<T>::value>::exec(out);
out << value;
str = out.str();
}
}

template <class T>
Expand All @@ -789,7 +796,12 @@ void to_string(const std::vector<T>& value, std::string& str)
if (!first) {
out << ", ";
}
out << v;
if constexpr (realm_serializable_types<T>) {
out << util::serializer::print_value(v);
}
else {
out << v;
}
first = false;
}
out << "}";
Expand All @@ -799,14 +811,17 @@ void to_string(const std::vector<T>& value, std::string& str)
template <class T>
void to_string(const std::optional<T>& value, std::string& str)
{
// FIXME: Put string values in quotes, and escape non-printables as well as '"' and '\\'.
std::ostringstream out;
SetPrecision<T, std::is_floating_point<T>::value>::exec(out);
util::stream_possible_optional(out, value);
str = out.str();
if constexpr (realm_serializable_types<T>) {
str = util::serializer::print_value(value);
}
else {
std::ostringstream out;
SetPrecision<T, std::is_floating_point<T>::value>::exec(out);
util::stream_possible_optional(out, value);
str = out.str();
}
}


inline bool TestContext::check_cond(bool cond, const char* file, long line, const char* macro_name,
const char* cond_text)
{
Expand Down

0 comments on commit 23d5873

Please sign in to comment.