Skip to content

Commit

Permalink
Query support for constant lists and list vs list (#5663)
Browse files Browse the repository at this point in the history
Co-authored-by: Jørgen Edelbo <jorgen.edelbo@mongodb.com>
  • Loading branch information
ironage and jedelbo authored Aug 4, 2022
1 parent a7dce8b commit e62f7c9
Show file tree
Hide file tree
Showing 19 changed files with 1,219 additions and 539 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# NEXT RELEASE

### Enhancements
* <New feature description> (PR [#????](https://github.com/realm/realm-core/pull/????))
* Allow multiple anonymous sessions. ([PR #5693](https://github.com/realm/realm-core/pull/5693)).
* Introducing query parser support for constant list expressions such as `fruit IN {'apple', 'orange'}`. This also includes general query support for list vs list matching such as `NONE fruits IN {'apple', 'orange'}`. ([Issue #4266](https://github.com/realm/realm-core/issues/4266))

### Fixed
* Fix error message when validating outgoing links from asymmetric objects to non-embedded objects. ([PR #5702](https://github.com/realm/realm-core/pull/5702))
Expand Down
13 changes: 9 additions & 4 deletions src/realm.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,11 @@ typedef struct realm_key_path_array {
size_t nb_elements;
realm_key_path_t* paths;
} realm_key_path_array_t;
typedef struct realm_query_arg {
size_t nb_args;
bool is_list;
realm_value_t* arg;
} realm_query_arg_t;

typedef struct realm_version_id {
uint64_t version;
Expand Down Expand Up @@ -2186,7 +2191,7 @@ RLM_API realm_dictionary_t* realm_dictionary_from_thread_safe_reference(const re
* exception occurred.
*/
RLM_API realm_query_t* realm_query_parse(const realm_t*, realm_class_key_t target_table, const char* query_string,
size_t num_args, const realm_value_t* args);
size_t num_args, const realm_query_arg_t* args);


/**
Expand All @@ -2213,7 +2218,7 @@ RLM_API const char* realm_query_get_description(realm_query_t*);
* exception occurred.
*/
RLM_API realm_query_t* realm_query_append_query(const realm_query_t*, const char* query_string, size_t num_args,
const realm_value_t* args);
const realm_query_arg_t* args);

/**
* Parse a query string and bind it to a list.
Expand All @@ -2230,7 +2235,7 @@ RLM_API realm_query_t* realm_query_append_query(const realm_query_t*, const char
* exception occurred.
*/
RLM_API realm_query_t* realm_query_parse_for_list(const realm_list_t* target_list, const char* query_string,
size_t num_args, const realm_value_t* args);
size_t num_args, const realm_query_arg_t* args);

/**
* Parse a query string and bind it to another query result.
Expand All @@ -2248,7 +2253,7 @@ RLM_API realm_query_t* realm_query_parse_for_list(const realm_list_t* target_lis
* exception occurred.
*/
RLM_API realm_query_t* realm_query_parse_for_results(const realm_results_t* target_results, const char* query_string,
size_t num_args, const realm_value_t* args);
size_t num_args, const realm_query_arg_t* args);

/**
* Count the number of objects found by this query.
Expand Down
83 changes: 50 additions & 33 deletions src/realm/object-store/c_api/query.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ namespace realm::c_api {

namespace {
struct QueryArgumentsAdapter : query_parser::Arguments {
const realm_value_t* m_args = nullptr;
const realm_query_arg_t* m_args = nullptr;

QueryArgumentsAdapter(size_t num_args, const realm_value_t* args) noexcept
QueryArgumentsAdapter(size_t num_args, const realm_query_arg_t* args) noexcept
: Arguments(num_args)
, m_args(args)
{
Expand All @@ -22,8 +22,8 @@ struct QueryArgumentsAdapter : query_parser::Arguments {
bool bool_for_argument(size_t i) final
{
verify_ndx(i);
if (m_args[i].type == RLM_TYPE_BOOL) {
return m_args[i].boolean;
if (m_args[i].arg[0].type == RLM_TYPE_BOOL) {
return m_args[i].arg[0].boolean;
}
// Note: Unreachable.
throw LogicError{LogicError::type_mismatch}; // LCOV_EXCL_LINE
Expand All @@ -32,8 +32,8 @@ struct QueryArgumentsAdapter : query_parser::Arguments {
long long long_for_argument(size_t i) final
{
verify_ndx(i);
if (m_args[i].type == RLM_TYPE_INT) {
return m_args[i].integer;
if (m_args[i].arg[0].type == RLM_TYPE_INT) {
return m_args[i].arg[0].integer;
}
// Note: Unreachable.
throw LogicError{LogicError::type_mismatch}; // LCOV_EXCL_LINE
Expand All @@ -42,8 +42,8 @@ struct QueryArgumentsAdapter : query_parser::Arguments {
float float_for_argument(size_t i) final
{
verify_ndx(i);
if (m_args[i].type == RLM_TYPE_FLOAT) {
return m_args[i].fnum;
if (m_args[i].arg[0].type == RLM_TYPE_FLOAT) {
return m_args[i].arg[0].fnum;
}
// Note: Unreachable.
throw LogicError{LogicError::type_mismatch}; // LCOV_EXCL_LINE
Expand All @@ -52,8 +52,8 @@ struct QueryArgumentsAdapter : query_parser::Arguments {
double double_for_argument(size_t i) final
{
verify_ndx(i);
if (m_args[i].type == RLM_TYPE_DOUBLE) {
return m_args[i].dnum;
if (m_args[i].arg[0].type == RLM_TYPE_DOUBLE) {
return m_args[i].arg[0].dnum;
}
// Note: Unreachable.
throw LogicError{LogicError::type_mismatch}; // LCOV_EXCL_LINE
Expand All @@ -62,8 +62,8 @@ struct QueryArgumentsAdapter : query_parser::Arguments {
StringData string_for_argument(size_t i) final
{
verify_ndx(i);
if (m_args[i].type == RLM_TYPE_STRING) {
return from_capi(m_args[i].string);
if (m_args[i].arg[0].type == RLM_TYPE_STRING) {
return from_capi(m_args[i].arg[0].string);
}
// Note: Unreachable.
throw LogicError{LogicError::type_mismatch}; // LCOV_EXCL_LINE
Expand All @@ -72,8 +72,8 @@ struct QueryArgumentsAdapter : query_parser::Arguments {
BinaryData binary_for_argument(size_t i) final
{
verify_ndx(i);
if (m_args[i].type == RLM_TYPE_BINARY) {
return from_capi(m_args[i].binary);
if (m_args[i].arg[0].type == RLM_TYPE_BINARY) {
return from_capi(m_args[i].arg[0].binary);
}
// Note: Unreachable.
throw LogicError{LogicError::type_mismatch}; // LCOV_EXCL_LINE
Expand All @@ -82,8 +82,8 @@ struct QueryArgumentsAdapter : query_parser::Arguments {
Timestamp timestamp_for_argument(size_t i) final
{
verify_ndx(i);
if (m_args[i].type == RLM_TYPE_TIMESTAMP) {
return from_capi(m_args[i].timestamp);
if (m_args[i].arg[0].type == RLM_TYPE_TIMESTAMP) {
return from_capi(m_args[i].arg[0].timestamp);
}
// Note: Unreachable.
throw LogicError{LogicError::type_mismatch}; // LCOV_EXCL_LINE
Expand All @@ -92,9 +92,9 @@ struct QueryArgumentsAdapter : query_parser::Arguments {
ObjKey object_index_for_argument(size_t i) final
{
verify_ndx(i);
if (m_args[i].type == RLM_TYPE_LINK) {
if (m_args[i].arg[0].type == RLM_TYPE_LINK) {
// FIXME: Somehow check the target table type?
return from_capi(m_args[i].link).get_obj_key();
return from_capi(m_args[i].arg[0].link).get_obj_key();
}
// Note: Unreachable.
throw LogicError{LogicError::type_mismatch}; // LCOV_EXCL_LINE
Expand All @@ -103,8 +103,8 @@ struct QueryArgumentsAdapter : query_parser::Arguments {
ObjectId objectid_for_argument(size_t i) final
{
verify_ndx(i);
if (m_args[i].type == RLM_TYPE_OBJECT_ID) {
return from_capi(m_args[i].object_id);
if (m_args[i].arg[0].type == RLM_TYPE_OBJECT_ID) {
return from_capi(m_args[i].arg[0].object_id);
}
// Note: Unreachable.
throw LogicError{LogicError::type_mismatch}; // LCOV_EXCL_LINE
Expand All @@ -113,8 +113,8 @@ struct QueryArgumentsAdapter : query_parser::Arguments {
Decimal128 decimal128_for_argument(size_t i) final
{
verify_ndx(i);
if (m_args[i].type == RLM_TYPE_DECIMAL128) {
return from_capi(m_args[i].decimal128);
if (m_args[i].arg[0].type == RLM_TYPE_DECIMAL128) {
return from_capi(m_args[i].arg[0].decimal128);
}
// Note: Unreachable.
throw LogicError{LogicError::type_mismatch}; // LCOV_EXCL_LINE
Expand All @@ -123,8 +123,8 @@ struct QueryArgumentsAdapter : query_parser::Arguments {
UUID uuid_for_argument(size_t i) final
{
verify_ndx(i);
if (m_args[i].type == RLM_TYPE_UUID) {
return from_capi(m_args[i].uuid);
if (m_args[i].arg[0].type == RLM_TYPE_UUID) {
return from_capi(m_args[i].arg[0].uuid);
}
// Note: Unreachable.
throw LogicError{LogicError::type_mismatch}; // LCOV_EXCL_LINE
Expand All @@ -133,22 +133,39 @@ struct QueryArgumentsAdapter : query_parser::Arguments {
ObjLink objlink_for_argument(size_t i) final
{
verify_ndx(i);
if (m_args[i].type == RLM_TYPE_LINK) {
return from_capi(m_args[i].link);
if (m_args[i].arg[0].type == RLM_TYPE_LINK) {
return from_capi(m_args[i].arg[0].link);
}
throw LogicError{LogicError::type_mismatch}; // LCOV_EXCL_LINE
}

bool is_argument_null(size_t i) final
{
verify_ndx(i);
return m_args[i].type == RLM_TYPE_NULL;
return !m_args[i].is_list && m_args[i].arg[0].type == RLM_TYPE_NULL;
}

bool is_argument_list(size_t i) final
{
verify_ndx(i);
return m_args[i].is_list;
}

std::vector<Mixed> list_for_argument(size_t ndx) final
{
verify_ndx(ndx);
REALM_ASSERT(m_args[ndx].is_list);
std::vector<Mixed> list;
list.reserve(m_args[ndx].nb_args);
for (size_t i = 0; i < m_args[ndx].nb_args; ++i) {
list.push_back(from_capi(m_args[ndx].arg[i]));
}
return list;
}
DataType type_for_argument(size_t i) override
{
verify_ndx(i);
switch (m_args[i].type) {
switch (m_args[i].arg[0].type) {
case RLM_TYPE_NULL: // LCOV_EXCL_LINE
REALM_TERMINATE("Query parser did not call is_argument_null()"); // LCOV_EXCL_LINE
case RLM_TYPE_INT:
Expand Down Expand Up @@ -180,7 +197,7 @@ struct QueryArgumentsAdapter : query_parser::Arguments {
} // namespace

static Query parse_and_apply_query(const std::shared_ptr<Realm>& realm, ConstTableRef table, const char* query_string,
size_t num_args, const realm_value_t* args)
size_t num_args, const realm_query_arg_t* args)
{
query_parser::KeyPathMapping mapping;
realm::populate_keypath_mapping(mapping, *realm);
Expand All @@ -190,7 +207,7 @@ static Query parse_and_apply_query(const std::shared_ptr<Realm>& realm, ConstTab
}

RLM_API realm_query_t* realm_query_parse(const realm_t* realm, realm_class_key_t target_table_key,
const char* query_string, size_t num_args, const realm_value_t* args)
const char* query_string, size_t num_args, const realm_query_arg_t* args)
{
return wrap_err([&]() {
auto table = (*realm)->read_group().get_table(TableKey(target_table_key));
Expand All @@ -208,7 +225,7 @@ RLM_API const char* realm_query_get_description(realm_query_t* query)
}

RLM_API realm_query_t* realm_query_append_query(const realm_query_t* existing_query, const char* query_string,
size_t num_args, const realm_value_t* args)
size_t num_args, const realm_query_arg_t* args)
{
return wrap_err([&]() {
auto realm = existing_query->weak_realm.lock();
Expand All @@ -225,7 +242,7 @@ RLM_API realm_query_t* realm_query_append_query(const realm_query_t* existing_qu
}

RLM_API realm_query_t* realm_query_parse_for_list(const realm_list_t* list, const char* query_string, size_t num_args,
const realm_value_t* args)
const realm_query_arg_t* args)
{
return wrap_err([&]() {
auto realm = list->get_realm();
Expand All @@ -237,7 +254,7 @@ RLM_API realm_query_t* realm_query_parse_for_list(const realm_list_t* list, cons
}

RLM_API realm_query_t* realm_query_parse_for_results(const realm_results_t* results, const char* query_string,
size_t num_args, const realm_value_t* args)
size_t num_args, const realm_query_arg_t* args)
{
return wrap_err([&]() {
auto realm = results->get_realm();
Expand Down
Loading

0 comments on commit e62f7c9

Please sign in to comment.