Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow keypath to be provided as argument #7210

Merged
merged 3 commits into from
Dec 21, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion 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/????))
* None.
* Property keypath in RQL can be substituted with value given as argument. Use '$P<i>' in query string. (Issue [#7033](https://github.com/realm/realm-core/issues/7033))

### Fixed
* <How do the end-user experience this issue? what was the impact?> ([#????](https://github.com/realm/realm-core/issues/????), since v?.?.?)
Expand Down
34 changes: 34 additions & 0 deletions src/realm/parser/driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -929,6 +929,7 @@ Query TrueOrFalseNode::visit(ParserDriver* drv)

std::unique_ptr<Subexpr> PropertyNode::visit(ParserDriver* drv, DataType)
{
path->resolve_arg(drv);
if (path->path_elems.back().is_key() && path->path_elems.back().get_key() == "@links") {
identifier = "@links";
// This is a backlink aggregate query
Expand Down Expand Up @@ -1610,6 +1611,23 @@ std::unique_ptr<Subexpr> ListNode::visit(ParserDriver* drv, DataType hint)
return ret;
}

void PathNode::resolve_arg(ParserDriver* drv)
{
if (arg.size()) {
if (path_elems.size()) {
throw InvalidQueryError("Key path argument cannot be mixed with other elements");
}
auto arg_str = drv->get_arg_for_key_path(arg);
const char* path = arg_str.data();
do {
auto p = find_chr(path, '.');
StringData elem(path, p - path);
add_element(elem);
path = p;
} while (*path++ == '.');
}
}

LinkChain PathNode::visit(ParserDriver* drv, util::Optional<ExpressionComparisonType> comp_type)
{
LinkChain link_chain(drv->m_base_table, comp_type);
Expand Down Expand Up @@ -1759,6 +1777,22 @@ PathElement ParserDriver::get_arg_for_index(const std::string& i)
}
}

std::string ParserDriver::get_arg_for_key_path(const std::string& i)
{
REALM_ASSERT(i[0] == '$');
REALM_ASSERT(i[1] == 'K');
size_t arg_no = size_t(strtol(i.substr(2).c_str(), nullptr, 10));
if (m_args.is_argument_null(arg_no) || m_args.is_argument_list(arg_no)) {
throw InvalidQueryArgError(util::format("Null or list cannot be used for parameter '%1'", i));
}
auto type = m_args.type_for_argument(arg_no);
if (type != type_String) {
throw InvalidQueryArgError(util::format("Invalid index type for '%1'. Expected a string, but found type '%2'",
i, get_data_type_name(type)));
}
return m_args.string_for_argument(arg_no);
}

double ParserDriver::get_arg_for_coordinate(const std::string& str)
{
REALM_ASSERT(str[0] == '$');
Expand Down
8 changes: 8 additions & 0 deletions src/realm/parser/driver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,13 +278,18 @@ class ListNode : public ValueNode {

class PathNode : public ParserNode {
public:
struct ArgTag {};
Path path_elems;
Path::iterator current_path_elem;

PathNode(const PathElement& first)
{
add_element(first);
}
PathNode(const std::string& arg_str, ArgTag)
: arg(arg_str)
{
}
bool at_end() const
{
return current_path_elem == path_elems.end();
Expand All @@ -298,6 +303,7 @@ class PathNode : public ParserNode {
return path_elems.back().get_key();
}

void resolve_arg(ParserDriver*);
LinkChain visit(ParserDriver*, util::Optional<ExpressionComparisonType> = util::none);
void add_element(const PathElement& elem)
{
Expand Down Expand Up @@ -332,6 +338,7 @@ class PathNode : public ParserNode {
}

private:
std::string arg;
std::string backlink_str;
int backlink = 0;
};
Expand Down Expand Up @@ -664,6 +671,7 @@ class ParserDriver {
}

PathElement get_arg_for_index(const std::string&);
std::string get_arg_for_key_path(const std::string& i);
double get_arg_for_coordinate(const std::string&);

template <class T>
Expand Down
Loading