move query building to a separate file
This commit is contained in:
parent
2f1c26ad73
commit
e7e4b6715e
|
@ -53,6 +53,8 @@
|
||||||
029445941BDEDF40006D1617 /* transact_log_handler.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 029445921BDEDF40006D1617 /* transact_log_handler.hpp */; };
|
029445941BDEDF40006D1617 /* transact_log_handler.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 029445921BDEDF40006D1617 /* transact_log_handler.hpp */; };
|
||||||
029445971BDEDF46006D1617 /* external_commit_helper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 029445951BDEDF46006D1617 /* external_commit_helper.cpp */; };
|
029445971BDEDF46006D1617 /* external_commit_helper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 029445951BDEDF46006D1617 /* external_commit_helper.cpp */; };
|
||||||
029445981BDEDF46006D1617 /* external_commit_helper.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 029445961BDEDF46006D1617 /* external_commit_helper.hpp */; };
|
029445981BDEDF46006D1617 /* external_commit_helper.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 029445961BDEDF46006D1617 /* external_commit_helper.hpp */; };
|
||||||
|
0294465E1BF27DE6006D1617 /* query_builder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0294465C1BF27DE6006D1617 /* query_builder.cpp */; };
|
||||||
|
0294465F1BF27DE6006D1617 /* query_builder.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0294465D1BF27DE6006D1617 /* query_builder.hpp */; };
|
||||||
02B29A311B7CF86D008A7E6B /* RealmJS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CB11AE99CEC009B348C /* RealmJS.framework */; };
|
02B29A311B7CF86D008A7E6B /* RealmJS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CB11AE99CEC009B348C /* RealmJS.framework */; };
|
||||||
02B58CCE1AE99D4D009B348C /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */; };
|
02B58CCE1AE99D4D009B348C /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */; };
|
||||||
02C0864E1BCDB27000942F9C /* list.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02C0864C1BCDB27000942F9C /* list.cpp */; };
|
02C0864E1BCDB27000942F9C /* list.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02C0864C1BCDB27000942F9C /* list.cpp */; };
|
||||||
|
@ -208,7 +210,9 @@
|
||||||
029445921BDEDF40006D1617 /* transact_log_handler.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = transact_log_handler.hpp; path = "src/object-store/impl/transact_log_handler.hpp"; sourceTree = "<group>"; };
|
029445921BDEDF40006D1617 /* transact_log_handler.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = transact_log_handler.hpp; path = "src/object-store/impl/transact_log_handler.hpp"; sourceTree = "<group>"; };
|
||||||
029445951BDEDF46006D1617 /* external_commit_helper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = external_commit_helper.cpp; path = "src/object-store/impl/apple/external_commit_helper.cpp"; sourceTree = "<group>"; };
|
029445951BDEDF46006D1617 /* external_commit_helper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = external_commit_helper.cpp; path = "src/object-store/impl/apple/external_commit_helper.cpp"; sourceTree = "<group>"; };
|
||||||
029445961BDEDF46006D1617 /* external_commit_helper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = external_commit_helper.hpp; path = "src/object-store/impl/apple/external_commit_helper.hpp"; sourceTree = "<group>"; };
|
029445961BDEDF46006D1617 /* external_commit_helper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = external_commit_helper.hpp; path = "src/object-store/impl/apple/external_commit_helper.hpp"; sourceTree = "<group>"; };
|
||||||
02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = GCDWebServer.xcodeproj; path = GCDWebServer/GCDWebServer.xcodeproj; sourceTree = "<group>"; };
|
0294465C1BF27DE6006D1617 /* query_builder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = query_builder.cpp; path = "src/object-store/parser/query_builder.cpp"; sourceTree = "<group>"; };
|
||||||
|
0294465D1BF27DE6006D1617 /* query_builder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = query_builder.hpp; path = "src/object-store/parser/query_builder.hpp"; sourceTree = "<group>"; };
|
||||||
|
02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = GCDWebServer.xcodeproj; path = vendor/GCDWebServer/GCDWebServer.xcodeproj; sourceTree = "<group>"; };
|
||||||
02A3C7A41BC4341500B1A7BE /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
|
02A3C7A41BC4341500B1A7BE /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
|
||||||
02B29A161B7CF7C9008A7E6B /* RealmReact.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RealmReact.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
02B29A161B7CF7C9008A7E6B /* RealmReact.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RealmReact.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
02B58CB11AE99CEC009B348C /* RealmJS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RealmJS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
02B58CB11AE99CEC009B348C /* RealmJS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RealmJS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
@ -285,6 +289,8 @@
|
||||||
029445961BDEDF46006D1617 /* external_commit_helper.hpp */,
|
029445961BDEDF46006D1617 /* external_commit_helper.hpp */,
|
||||||
02786E311BF1065000937061 /* parser.cpp */,
|
02786E311BF1065000937061 /* parser.cpp */,
|
||||||
02786E321BF1065000937061 /* parser.hpp */,
|
02786E321BF1065000937061 /* parser.hpp */,
|
||||||
|
0294465C1BF27DE6006D1617 /* query_builder.cpp */,
|
||||||
|
0294465D1BF27DE6006D1617 /* query_builder.hpp */,
|
||||||
0270BC3E1B7CFC0D00010E03 /* RealmJS.h */,
|
0270BC3E1B7CFC0D00010E03 /* RealmJS.h */,
|
||||||
0270BC3F1B7CFC0D00010E03 /* RealmJS.mm */,
|
0270BC3F1B7CFC0D00010E03 /* RealmJS.mm */,
|
||||||
02258FB11BC6E2D00075F13A /* RealmRPC.hpp */,
|
02258FB11BC6E2D00075F13A /* RealmRPC.hpp */,
|
||||||
|
@ -412,6 +418,7 @@
|
||||||
0270BC4C1B7CFC0D00010E03 /* RealmJS.h in Headers */,
|
0270BC4C1B7CFC0D00010E03 /* RealmJS.h in Headers */,
|
||||||
02258FB31BC6E2D00075F13A /* RealmRPC.hpp in Headers */,
|
02258FB31BC6E2D00075F13A /* RealmRPC.hpp in Headers */,
|
||||||
0270BC4F1B7CFC0D00010E03 /* RJSList.hpp in Headers */,
|
0270BC4F1B7CFC0D00010E03 /* RJSList.hpp in Headers */,
|
||||||
|
0294465F1BF27DE6006D1617 /* query_builder.hpp in Headers */,
|
||||||
0270BC541B7CFC0D00010E03 /* RJSResults.hpp in Headers */,
|
0270BC541B7CFC0D00010E03 /* RJSResults.hpp in Headers */,
|
||||||
02D0F23B1BF6C95200B4FC45 /* binding_context.hpp in Headers */,
|
02D0F23B1BF6C95200B4FC45 /* binding_context.hpp in Headers */,
|
||||||
0270BC581B7CFC0D00010E03 /* RJSUtil.hpp in Headers */,
|
0270BC581B7CFC0D00010E03 /* RJSUtil.hpp in Headers */,
|
||||||
|
@ -673,6 +680,7 @@
|
||||||
0270BC551B7CFC0D00010E03 /* RJSResults.mm in Sources */,
|
0270BC551B7CFC0D00010E03 /* RJSResults.mm in Sources */,
|
||||||
02C0864E1BCDB27000942F9C /* list.cpp in Sources */,
|
02C0864E1BCDB27000942F9C /* list.cpp in Sources */,
|
||||||
0270BC6B1B7CFC1C00010E03 /* object_store.cpp in Sources */,
|
0270BC6B1B7CFC1C00010E03 /* object_store.cpp in Sources */,
|
||||||
|
0294465E1BF27DE6006D1617 /* query_builder.cpp in Sources */,
|
||||||
0270BC701B7CFC1C00010E03 /* shared_realm.cpp in Sources */,
|
0270BC701B7CFC1C00010E03 /* shared_realm.cpp in Sources */,
|
||||||
F6BB7DF11BF681BC00D0A69E /* base64.cpp in Sources */,
|
F6BB7DF11BF681BC00D0A69E /* base64.cpp in Sources */,
|
||||||
0270BC4E1B7CFC0D00010E03 /* RJSList.cpp in Sources */,
|
0270BC4E1B7CFC0D00010E03 /* RJSList.cpp in Sources */,
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#import "object_accessor.hpp"
|
#import "object_accessor.hpp"
|
||||||
#import "results.hpp"
|
#import "results.hpp"
|
||||||
#import "parser.hpp"
|
#import "parser.hpp"
|
||||||
|
#import "query_builder.hpp"
|
||||||
|
|
||||||
using namespace realm;
|
using namespace realm;
|
||||||
|
|
||||||
|
@ -113,7 +114,7 @@ JSObjectRef RJSResultsCreate(JSContextRef ctx, SharedRealm realm, std::string cl
|
||||||
throw std::runtime_error("Object type '" + className + "' not present in Realm.");
|
throw std::runtime_error("Object type '" + className + "' not present in Realm.");
|
||||||
}
|
}
|
||||||
parser::Predicate predicate = parser::parse(queryString);
|
parser::Predicate predicate = parser::parse(queryString);
|
||||||
parser::apply_predicate(query, predicate, schema, object_schema->name);
|
query_builder::apply_predicate(query, predicate, schema, object_schema->name);
|
||||||
|
|
||||||
return RJSWrapObject<Results *>(ctx, RJSResultsClass(), new Results(realm, *object_schema, std::move(query)));
|
return RJSWrapObject<Results *>(ctx, RJSResultsClass(), new Results(realm, *object_schema, std::move(query)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,10 +24,6 @@
|
||||||
#include <pegtl/analyze.hh>
|
#include <pegtl/analyze.hh>
|
||||||
#include <pegtl/trace.hh>
|
#include <pegtl/trace.hh>
|
||||||
|
|
||||||
#include <realm.hpp>
|
|
||||||
#include "object_store.hpp"
|
|
||||||
#include "schema.hpp"
|
|
||||||
|
|
||||||
using namespace pegtl;
|
using namespace pegtl;
|
||||||
|
|
||||||
namespace realm {
|
namespace realm {
|
||||||
|
@ -296,355 +292,6 @@ Predicate parse(const std::string &query)
|
||||||
return std::move(out_predicate);
|
return std::move(out_predicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// check a precondition and throw an exception if it is not met
|
|
||||||
// this should be used iff the condition being false indicates a bug in the caller
|
|
||||||
// of the function checking its preconditions
|
|
||||||
static void precondition(bool condition, const std::string message) {
|
|
||||||
if (__builtin_expect(condition, 1)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw std::runtime_error(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: TrueExpression and FalseExpression should be supported by core in some way
|
|
||||||
struct TrueExpression : realm::Expression {
|
|
||||||
size_t find_first(size_t start, size_t end) const override
|
|
||||||
{
|
|
||||||
if (start != end)
|
|
||||||
return start;
|
|
||||||
|
|
||||||
return not_found;
|
|
||||||
}
|
|
||||||
void set_table() override {}
|
|
||||||
const Table* get_table() const override { return nullptr; }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FalseExpression : realm::Expression {
|
|
||||||
size_t find_first(size_t, size_t) const override { return not_found; }
|
|
||||||
void set_table() override {}
|
|
||||||
const Table* get_table() const override { return nullptr; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// add a clause for numeric constraints based on operator type
|
|
||||||
template <typename A, typename B>
|
|
||||||
void add_numeric_constraint_to_query(Query& query,
|
|
||||||
PropertyType datatype,
|
|
||||||
Predicate::Operator operatorType,
|
|
||||||
A lhs,
|
|
||||||
B rhs)
|
|
||||||
{
|
|
||||||
switch (operatorType) {
|
|
||||||
case Predicate::Operator::LessThan:
|
|
||||||
query.and_query(lhs < rhs);
|
|
||||||
break;
|
|
||||||
case Predicate::Operator::LessThanOrEqual:
|
|
||||||
query.and_query(lhs <= rhs);
|
|
||||||
break;
|
|
||||||
case Predicate::Operator::GreaterThan:
|
|
||||||
query.and_query(lhs > rhs);
|
|
||||||
break;
|
|
||||||
case Predicate::Operator::GreaterThanOrEqual:
|
|
||||||
query.and_query(lhs >= rhs);
|
|
||||||
break;
|
|
||||||
case Predicate::Operator::Equal:
|
|
||||||
query.and_query(lhs == rhs);
|
|
||||||
break;
|
|
||||||
case Predicate::Operator::NotEqual:
|
|
||||||
query.and_query(lhs != rhs);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw std::runtime_error("Unsupported operator for numeric queries.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename A, typename B>
|
|
||||||
void add_bool_constraint_to_query(Query &query, Predicate::Operator operatorType, A lhs, B rhs) {
|
|
||||||
switch (operatorType) {
|
|
||||||
case Predicate::Operator::Equal:
|
|
||||||
query.and_query(lhs == rhs);
|
|
||||||
break;
|
|
||||||
case Predicate::Operator::NotEqual:
|
|
||||||
query.and_query(lhs != rhs);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw std::runtime_error("Unsupported operator for numeric queries.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_string_constraint_to_query(Query &query,
|
|
||||||
Predicate::Operator op,
|
|
||||||
Columns<String> &&column,
|
|
||||||
StringData value) {
|
|
||||||
bool case_sensitive = true;
|
|
||||||
StringData sd = value;
|
|
||||||
switch (op) {
|
|
||||||
case Predicate::Operator::BeginsWith:
|
|
||||||
query.and_query(column.begins_with(sd, case_sensitive));
|
|
||||||
break;
|
|
||||||
case Predicate::Operator::EndsWith:
|
|
||||||
query.and_query(column.ends_with(sd, case_sensitive));
|
|
||||||
break;
|
|
||||||
case Predicate::Operator::Contains:
|
|
||||||
query.and_query(column.contains(sd, case_sensitive));
|
|
||||||
break;
|
|
||||||
case Predicate::Operator::Equal:
|
|
||||||
query.and_query(column.equal(sd, case_sensitive));
|
|
||||||
break;
|
|
||||||
case Predicate::Operator::NotEqual:
|
|
||||||
query.and_query(column.not_equal(sd, case_sensitive));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw std::runtime_error("Unsupported operator for string queries.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_string_constraint_to_query(realm::Query& query,
|
|
||||||
Predicate::Operator op,
|
|
||||||
StringData value,
|
|
||||||
Columns<String> &&column) {
|
|
||||||
bool case_sensitive = true;
|
|
||||||
StringData sd = value;
|
|
||||||
switch (op) {
|
|
||||||
case Predicate::Operator::Equal:
|
|
||||||
query.and_query(column.equal(sd, case_sensitive));
|
|
||||||
break;
|
|
||||||
case Predicate::Operator::NotEqual:
|
|
||||||
query.and_query(column.not_equal(sd, case_sensitive));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw std::runtime_error("Substring comparison not supported for keypath substrings.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename RequestedType, typename TableGetter>
|
|
||||||
struct ColumnOfTypeHelper {
|
|
||||||
static Columns<RequestedType> convert(TableGetter&& table, unsigned int idx)
|
|
||||||
{
|
|
||||||
return table()->template column<RequestedType>(idx);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename TableGetter>
|
|
||||||
struct ColumnOfTypeHelper<DateTime, TableGetter> {
|
|
||||||
static Columns<Int> convert(TableGetter&& table, unsigned int idx)
|
|
||||||
{
|
|
||||||
return table()->template column<Int>(idx);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename RequestedType, typename TableGetter>
|
|
||||||
struct ValueOfTypeHelper;
|
|
||||||
|
|
||||||
template <typename TableGetter>
|
|
||||||
struct ValueOfTypeHelper<DateTime, TableGetter> {
|
|
||||||
static Int convert(TableGetter&&, const std::string & value)
|
|
||||||
{
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename TableGetter>
|
|
||||||
struct ValueOfTypeHelper<bool, TableGetter> {
|
|
||||||
static bool convert(TableGetter&&, const std::string & value)
|
|
||||||
{
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename TableGetter>
|
|
||||||
struct ValueOfTypeHelper<Double, TableGetter> {
|
|
||||||
static Double convert(TableGetter&&, const std::string & value)
|
|
||||||
{
|
|
||||||
return std::stod(value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename TableGetter>
|
|
||||||
struct ValueOfTypeHelper<Float, TableGetter> {
|
|
||||||
static Float convert(TableGetter&&, const std::string & value)
|
|
||||||
{
|
|
||||||
return std::stof(value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename TableGetter>
|
|
||||||
struct ValueOfTypeHelper<Int, TableGetter> {
|
|
||||||
static Int convert(TableGetter&&, const std::string & value)
|
|
||||||
{
|
|
||||||
return std::stoll(value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename TableGetter>
|
|
||||||
struct ValueOfTypeHelper<String, TableGetter> {
|
|
||||||
static std::string convert(TableGetter&&, const std::string & value)
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename RequestedType, typename Value, typename TableGetter>
|
|
||||||
auto value_of_type_for_query(TableGetter&& tables, Value&& value)
|
|
||||||
{
|
|
||||||
const bool isColumnIndex = std::is_same<size_t, typename std::remove_reference<Value>::type>::value;
|
|
||||||
using helper = std::conditional_t<isColumnIndex,
|
|
||||||
ColumnOfTypeHelper<RequestedType, TableGetter>,
|
|
||||||
ValueOfTypeHelper<RequestedType, TableGetter>>;
|
|
||||||
return helper::convert(std::forward<TableGetter>(tables), std::forward<Value>(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
|
|
||||||
std::stringstream ss(s);
|
|
||||||
std::string item;
|
|
||||||
while (std::getline(ss, item, delim)) {
|
|
||||||
elems.push_back(item);
|
|
||||||
}
|
|
||||||
return elems;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> split(const std::string &s, char delim) {
|
|
||||||
std::vector<std::string> elems;
|
|
||||||
split(s, delim, elems);
|
|
||||||
return elems;
|
|
||||||
}
|
|
||||||
|
|
||||||
Property *get_property_from_key_path(Schema &schema, ObjectSchema &desc, const std::string &key_path, std::vector<size_t> &indexes)
|
|
||||||
{
|
|
||||||
Property *prop = nullptr;
|
|
||||||
|
|
||||||
auto paths = split(key_path, '.');
|
|
||||||
for (size_t index = 0; index < paths.size(); index++) {
|
|
||||||
if (prop) {
|
|
||||||
precondition(prop->type == PropertyTypeObject || prop->type == PropertyTypeArray,
|
|
||||||
(std::string)"Property '" + paths[index] + "' is not a link in object of type '" + desc.name + "'");
|
|
||||||
indexes.push_back(prop->table_column);
|
|
||||||
|
|
||||||
}
|
|
||||||
prop = desc.property_for_name(paths[index]);
|
|
||||||
precondition(prop != nullptr, "No property '" + paths[index] + "' on object of type '" + desc.name + "'");
|
|
||||||
|
|
||||||
if (prop->object_type.size()) {
|
|
||||||
desc = *schema.find(prop->object_type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return prop;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename... T>
|
|
||||||
void do_add_comparison_to_query(Query &query, Schema &schema, ObjectSchema &object_schema, Property *prop,
|
|
||||||
Predicate::Operator op, const std::vector<size_t>& indexes, T... values)
|
|
||||||
{
|
|
||||||
auto table = [&] {
|
|
||||||
TableRef& tbl = query.get_table();
|
|
||||||
for (size_t col : indexes) {
|
|
||||||
tbl->link(col); // mutates m_link_chain on table
|
|
||||||
}
|
|
||||||
return tbl.get();
|
|
||||||
};
|
|
||||||
|
|
||||||
auto type = prop->type;
|
|
||||||
switch (type) {
|
|
||||||
case PropertyTypeBool:
|
|
||||||
add_bool_constraint_to_query(query, op, value_of_type_for_query<bool>(table, values)...);
|
|
||||||
break;
|
|
||||||
case PropertyTypeDate:
|
|
||||||
add_numeric_constraint_to_query(query, type, op, value_of_type_for_query<DateTime>(table, values)...);
|
|
||||||
break;
|
|
||||||
case PropertyTypeDouble:
|
|
||||||
add_numeric_constraint_to_query(query, type, op, value_of_type_for_query<Double>(table, values)...);
|
|
||||||
break;
|
|
||||||
case PropertyTypeFloat:
|
|
||||||
add_numeric_constraint_to_query(query, type, op, value_of_type_for_query<Float>(table, values)...);
|
|
||||||
break;
|
|
||||||
case PropertyTypeInt:
|
|
||||||
add_numeric_constraint_to_query(query, type, op, value_of_type_for_query<Int>(table, values)...);
|
|
||||||
break;
|
|
||||||
case PropertyTypeString:
|
|
||||||
case PropertyTypeData:
|
|
||||||
add_string_constraint_to_query(query, op, value_of_type_for_query<String>(table, values)...);
|
|
||||||
break;
|
|
||||||
default: {
|
|
||||||
throw std::runtime_error((std::string)"Object type " + string_for_property_type(type) + " not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_comparison_to_query(Query &query, Predicate &pred, Schema &schema, ObjectSchema &object_schema)
|
|
||||||
{
|
|
||||||
std::vector<size_t> indexes;
|
|
||||||
Predicate::Comparison &cmpr = pred.cmpr;
|
|
||||||
auto t0 = cmpr.expr[0].type, t1 = cmpr.expr[1].type;
|
|
||||||
if (t0 == Expression::Type::KeyPath && t1 != Expression::Type::KeyPath) {
|
|
||||||
Property *prop = get_property_from_key_path(schema, object_schema, cmpr.expr[0].s, indexes);
|
|
||||||
do_add_comparison_to_query(query, schema, object_schema, prop, cmpr.op, indexes, prop->table_column, cmpr.expr[1].s);
|
|
||||||
}
|
|
||||||
else if (t0 != Expression::Type::KeyPath && t1 == Expression::Type::KeyPath) {
|
|
||||||
Property *prop = get_property_from_key_path(schema, object_schema, cmpr.expr[1].s, indexes);
|
|
||||||
do_add_comparison_to_query(query, schema, object_schema, prop, cmpr.op, indexes, cmpr.expr[0].s, prop->table_column);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw std::runtime_error("Predicate expressions must compare a keypath and another keypath or a constant value");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void update_query_with_predicate(Query &query, Predicate &pred, Schema &schema, ObjectSchema &object_schema)
|
|
||||||
{
|
|
||||||
if (pred.negate) {
|
|
||||||
query.Not();
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (pred.type) {
|
|
||||||
case Predicate::Type::And:
|
|
||||||
query.group();
|
|
||||||
for (auto &sub : pred.cpnd.sub_predicates) {
|
|
||||||
update_query_with_predicate(query, sub, schema, object_schema);
|
|
||||||
}
|
|
||||||
if (!pred.cpnd.sub_predicates.size()) {
|
|
||||||
query.and_query(new TrueExpression);
|
|
||||||
}
|
|
||||||
query.end_group();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Predicate::Type::Or:
|
|
||||||
query.group();
|
|
||||||
for (auto &sub : pred.cpnd.sub_predicates) {
|
|
||||||
query.Or();
|
|
||||||
update_query_with_predicate(query, sub, schema, object_schema);
|
|
||||||
}
|
|
||||||
if (!pred.cpnd.sub_predicates.size()) {
|
|
||||||
query.and_query(new FalseExpression);
|
|
||||||
}
|
|
||||||
query.end_group();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Predicate::Type::Comparison: {
|
|
||||||
add_comparison_to_query(query, pred, schema, object_schema);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Predicate::Type::True:
|
|
||||||
query.and_query(new TrueExpression);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Predicate::Type::False:
|
|
||||||
query.and_query(new FalseExpression);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw std::runtime_error("Invalid predicate type");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void apply_predicate(Query &query, Predicate &predicate, Schema &schema, std::string objectType) {
|
|
||||||
update_query_with_predicate(query, predicate, schema, *schema.find(objectType));
|
|
||||||
|
|
||||||
// Test the constructed query in core
|
|
||||||
std::string validateMessage = query.validate();
|
|
||||||
precondition(validateMessage.empty(), validateMessage.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,14 +16,13 @@
|
||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifndef REALM_EXTERNAL_COMMIT_HELPER_HPP
|
#ifndef REALM_PARSER_HPP
|
||||||
#define REALM_EXTERNAL_COMMIT_HELPER_HPP
|
#define REALM_PARSER_HPP
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace realm {
|
namespace realm {
|
||||||
class Query;
|
|
||||||
class Schema;
|
class Schema;
|
||||||
|
|
||||||
namespace parser {
|
namespace parser {
|
||||||
|
@ -77,9 +76,7 @@ namespace realm {
|
||||||
};
|
};
|
||||||
|
|
||||||
Predicate parse(const std::string &query);
|
Predicate parse(const std::string &query);
|
||||||
|
|
||||||
void apply_predicate(Query &query, Predicate &predicate, Schema &schema, std::string objectType);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // REALM_EXTERNAL_COMMIT_HELPER_HPP
|
#endif // REALM_PARSER_HPP
|
||||||
|
|
|
@ -0,0 +1,381 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright 2015 Realm Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "query_builder.hpp"
|
||||||
|
#include "parser.hpp"
|
||||||
|
|
||||||
|
#include <realm.hpp>
|
||||||
|
#include "object_store.hpp"
|
||||||
|
#include "schema.hpp"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
namespace realm {
|
||||||
|
namespace query_builder {
|
||||||
|
using namespace parser;
|
||||||
|
|
||||||
|
// check a precondition and throw an exception if it is not met
|
||||||
|
// this should be used iff the condition being false indicates a bug in the caller
|
||||||
|
// of the function checking its preconditions
|
||||||
|
static void precondition(bool condition, const std::string message) {
|
||||||
|
if (__builtin_expect(condition, 1)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw std::runtime_error(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: TrueExpression and FalseExpression should be supported by core in some way
|
||||||
|
struct TrueExpression : realm::Expression {
|
||||||
|
size_t find_first(size_t start, size_t end) const override
|
||||||
|
{
|
||||||
|
if (start != end)
|
||||||
|
return start;
|
||||||
|
|
||||||
|
return not_found;
|
||||||
|
}
|
||||||
|
void set_table() override {}
|
||||||
|
const Table* get_table() const override { return nullptr; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FalseExpression : realm::Expression {
|
||||||
|
size_t find_first(size_t, size_t) const override { return not_found; }
|
||||||
|
void set_table() override {}
|
||||||
|
const Table* get_table() const override { return nullptr; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// add a clause for numeric constraints based on operator type
|
||||||
|
template <typename A, typename B>
|
||||||
|
void add_numeric_constraint_to_query(Query& query,
|
||||||
|
PropertyType datatype,
|
||||||
|
Predicate::Operator operatorType,
|
||||||
|
A lhs,
|
||||||
|
B rhs)
|
||||||
|
{
|
||||||
|
switch (operatorType) {
|
||||||
|
case Predicate::Operator::LessThan:
|
||||||
|
query.and_query(lhs < rhs);
|
||||||
|
break;
|
||||||
|
case Predicate::Operator::LessThanOrEqual:
|
||||||
|
query.and_query(lhs <= rhs);
|
||||||
|
break;
|
||||||
|
case Predicate::Operator::GreaterThan:
|
||||||
|
query.and_query(lhs > rhs);
|
||||||
|
break;
|
||||||
|
case Predicate::Operator::GreaterThanOrEqual:
|
||||||
|
query.and_query(lhs >= rhs);
|
||||||
|
break;
|
||||||
|
case Predicate::Operator::Equal:
|
||||||
|
query.and_query(lhs == rhs);
|
||||||
|
break;
|
||||||
|
case Predicate::Operator::NotEqual:
|
||||||
|
query.and_query(lhs != rhs);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("Unsupported operator for numeric queries.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A, typename B>
|
||||||
|
void add_bool_constraint_to_query(Query &query, Predicate::Operator operatorType, A lhs, B rhs) {
|
||||||
|
switch (operatorType) {
|
||||||
|
case Predicate::Operator::Equal:
|
||||||
|
query.and_query(lhs == rhs);
|
||||||
|
break;
|
||||||
|
case Predicate::Operator::NotEqual:
|
||||||
|
query.and_query(lhs != rhs);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("Unsupported operator for numeric queries.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_string_constraint_to_query(Query &query,
|
||||||
|
Predicate::Operator op,
|
||||||
|
Columns<String> &&column,
|
||||||
|
StringData value) {
|
||||||
|
bool case_sensitive = true;
|
||||||
|
StringData sd = value;
|
||||||
|
switch (op) {
|
||||||
|
case Predicate::Operator::BeginsWith:
|
||||||
|
query.and_query(column.begins_with(sd, case_sensitive));
|
||||||
|
break;
|
||||||
|
case Predicate::Operator::EndsWith:
|
||||||
|
query.and_query(column.ends_with(sd, case_sensitive));
|
||||||
|
break;
|
||||||
|
case Predicate::Operator::Contains:
|
||||||
|
query.and_query(column.contains(sd, case_sensitive));
|
||||||
|
break;
|
||||||
|
case Predicate::Operator::Equal:
|
||||||
|
query.and_query(column.equal(sd, case_sensitive));
|
||||||
|
break;
|
||||||
|
case Predicate::Operator::NotEqual:
|
||||||
|
query.and_query(column.not_equal(sd, case_sensitive));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("Unsupported operator for string queries.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_string_constraint_to_query(realm::Query& query,
|
||||||
|
Predicate::Operator op,
|
||||||
|
StringData value,
|
||||||
|
Columns<String> &&column) {
|
||||||
|
bool case_sensitive = true;
|
||||||
|
StringData sd = value;
|
||||||
|
switch (op) {
|
||||||
|
case Predicate::Operator::Equal:
|
||||||
|
query.and_query(column.equal(sd, case_sensitive));
|
||||||
|
break;
|
||||||
|
case Predicate::Operator::NotEqual:
|
||||||
|
query.and_query(column.not_equal(sd, case_sensitive));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("Substring comparison not supported for keypath substrings.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename RequestedType, typename TableGetter>
|
||||||
|
struct ColumnOfTypeHelper {
|
||||||
|
static Columns<RequestedType> convert(TableGetter&& table, unsigned int idx)
|
||||||
|
{
|
||||||
|
return table()->template column<RequestedType>(idx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TableGetter>
|
||||||
|
struct ColumnOfTypeHelper<DateTime, TableGetter> {
|
||||||
|
static Columns<Int> convert(TableGetter&& table, unsigned int idx)
|
||||||
|
{
|
||||||
|
return table()->template column<Int>(idx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename RequestedType, typename TableGetter>
|
||||||
|
struct ValueOfTypeHelper;
|
||||||
|
|
||||||
|
template <typename TableGetter>
|
||||||
|
struct ValueOfTypeHelper<DateTime, TableGetter> {
|
||||||
|
static Int convert(TableGetter&&, const std::string & value)
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TableGetter>
|
||||||
|
struct ValueOfTypeHelper<bool, TableGetter> {
|
||||||
|
static bool convert(TableGetter&&, const std::string & value)
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TableGetter>
|
||||||
|
struct ValueOfTypeHelper<Double, TableGetter> {
|
||||||
|
static Double convert(TableGetter&&, const std::string & value)
|
||||||
|
{
|
||||||
|
return std::stod(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TableGetter>
|
||||||
|
struct ValueOfTypeHelper<Float, TableGetter> {
|
||||||
|
static Float convert(TableGetter&&, const std::string & value)
|
||||||
|
{
|
||||||
|
return std::stof(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TableGetter>
|
||||||
|
struct ValueOfTypeHelper<Int, TableGetter> {
|
||||||
|
static Int convert(TableGetter&&, const std::string & value)
|
||||||
|
{
|
||||||
|
return std::stoll(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TableGetter>
|
||||||
|
struct ValueOfTypeHelper<String, TableGetter> {
|
||||||
|
static std::string convert(TableGetter&&, const std::string & value)
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename RequestedType, typename Value, typename TableGetter>
|
||||||
|
auto value_of_type_for_query(TableGetter&& tables, Value&& value)
|
||||||
|
{
|
||||||
|
const bool isColumnIndex = std::is_same<size_t, typename std::remove_reference<Value>::type>::value;
|
||||||
|
using helper = std::conditional_t<isColumnIndex,
|
||||||
|
ColumnOfTypeHelper<RequestedType, TableGetter>,
|
||||||
|
ValueOfTypeHelper<RequestedType, TableGetter>>;
|
||||||
|
return helper::convert(std::forward<TableGetter>(tables), std::forward<Value>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
|
||||||
|
std::stringstream ss(s);
|
||||||
|
std::string item;
|
||||||
|
while (std::getline(ss, item, delim)) {
|
||||||
|
elems.push_back(item);
|
||||||
|
}
|
||||||
|
return elems;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> split(const std::string &s, char delim) {
|
||||||
|
std::vector<std::string> elems;
|
||||||
|
split(s, delim, elems);
|
||||||
|
return elems;
|
||||||
|
}
|
||||||
|
|
||||||
|
Property *get_property_from_key_path(Schema &schema, ObjectSchema &desc, const std::string &key_path, std::vector<size_t> &indexes)
|
||||||
|
{
|
||||||
|
Property *prop = nullptr;
|
||||||
|
|
||||||
|
auto paths = split(key_path, '.');
|
||||||
|
for (size_t index = 0; index < paths.size(); index++) {
|
||||||
|
if (prop) {
|
||||||
|
precondition(prop->type == PropertyTypeObject || prop->type == PropertyTypeArray,
|
||||||
|
(std::string)"Property '" + paths[index] + "' is not a link in object of type '" + desc.name + "'");
|
||||||
|
indexes.push_back(prop->table_column);
|
||||||
|
|
||||||
|
}
|
||||||
|
prop = desc.property_for_name(paths[index]);
|
||||||
|
precondition(prop != nullptr, "No property '" + paths[index] + "' on object of type '" + desc.name + "'");
|
||||||
|
|
||||||
|
if (prop->object_type.size()) {
|
||||||
|
desc = *schema.find(prop->object_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... T>
|
||||||
|
void do_add_comparison_to_query(Query &query, Schema &schema, ObjectSchema &object_schema, Property *prop,
|
||||||
|
Predicate::Operator op, const std::vector<size_t>& indexes, T... values)
|
||||||
|
{
|
||||||
|
auto table = [&] {
|
||||||
|
TableRef& tbl = query.get_table();
|
||||||
|
for (size_t col : indexes) {
|
||||||
|
tbl->link(col); // mutates m_link_chain on table
|
||||||
|
}
|
||||||
|
return tbl.get();
|
||||||
|
};
|
||||||
|
|
||||||
|
auto type = prop->type;
|
||||||
|
switch (type) {
|
||||||
|
case PropertyTypeBool:
|
||||||
|
add_bool_constraint_to_query(query, op, value_of_type_for_query<bool>(table, values)...);
|
||||||
|
break;
|
||||||
|
case PropertyTypeDate:
|
||||||
|
add_numeric_constraint_to_query(query, type, op, value_of_type_for_query<DateTime>(table, values)...);
|
||||||
|
break;
|
||||||
|
case PropertyTypeDouble:
|
||||||
|
add_numeric_constraint_to_query(query, type, op, value_of_type_for_query<Double>(table, values)...);
|
||||||
|
break;
|
||||||
|
case PropertyTypeFloat:
|
||||||
|
add_numeric_constraint_to_query(query, type, op, value_of_type_for_query<Float>(table, values)...);
|
||||||
|
break;
|
||||||
|
case PropertyTypeInt:
|
||||||
|
add_numeric_constraint_to_query(query, type, op, value_of_type_for_query<Int>(table, values)...);
|
||||||
|
break;
|
||||||
|
case PropertyTypeString:
|
||||||
|
case PropertyTypeData:
|
||||||
|
add_string_constraint_to_query(query, op, value_of_type_for_query<String>(table, values)...);
|
||||||
|
break;
|
||||||
|
default: {
|
||||||
|
throw std::runtime_error((std::string)"Object type " + string_for_property_type(type) + " not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_comparison_to_query(Query &query, Predicate &pred, Schema &schema, ObjectSchema &object_schema)
|
||||||
|
{
|
||||||
|
std::vector<size_t> indexes;
|
||||||
|
Predicate::Comparison &cmpr = pred.cmpr;
|
||||||
|
auto t0 = cmpr.expr[0].type, t1 = cmpr.expr[1].type;
|
||||||
|
if (t0 == parser::Expression::Type::KeyPath && t1 != parser::Expression::Type::KeyPath) {
|
||||||
|
Property *prop = get_property_from_key_path(schema, object_schema, cmpr.expr[0].s, indexes);
|
||||||
|
do_add_comparison_to_query(query, schema, object_schema, prop, cmpr.op, indexes, prop->table_column, cmpr.expr[1].s);
|
||||||
|
}
|
||||||
|
else if (t0 != parser::Expression::Type::KeyPath && t1 == parser::Expression::Type::KeyPath) {
|
||||||
|
Property *prop = get_property_from_key_path(schema, object_schema, cmpr.expr[1].s, indexes);
|
||||||
|
do_add_comparison_to_query(query, schema, object_schema, prop, cmpr.op, indexes, cmpr.expr[0].s, prop->table_column);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("Predicate expressions must compare a keypath and another keypath or a constant value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_query_with_predicate(Query &query, Predicate &pred, Schema &schema, ObjectSchema &object_schema)
|
||||||
|
{
|
||||||
|
if (pred.negate) {
|
||||||
|
query.Not();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (pred.type) {
|
||||||
|
case Predicate::Type::And:
|
||||||
|
query.group();
|
||||||
|
for (auto &sub : pred.cpnd.sub_predicates) {
|
||||||
|
update_query_with_predicate(query, sub, schema, object_schema);
|
||||||
|
}
|
||||||
|
if (!pred.cpnd.sub_predicates.size()) {
|
||||||
|
query.and_query(new TrueExpression);
|
||||||
|
}
|
||||||
|
query.end_group();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Predicate::Type::Or:
|
||||||
|
query.group();
|
||||||
|
for (auto &sub : pred.cpnd.sub_predicates) {
|
||||||
|
query.Or();
|
||||||
|
update_query_with_predicate(query, sub, schema, object_schema);
|
||||||
|
}
|
||||||
|
if (!pred.cpnd.sub_predicates.size()) {
|
||||||
|
query.and_query(new FalseExpression);
|
||||||
|
}
|
||||||
|
query.end_group();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Predicate::Type::Comparison: {
|
||||||
|
add_comparison_to_query(query, pred, schema, object_schema);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Predicate::Type::True:
|
||||||
|
query.and_query(new TrueExpression);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Predicate::Type::False:
|
||||||
|
query.and_query(new FalseExpression);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("Invalid predicate type");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_predicate(Query &query, Predicate &predicate, Schema &schema, std::string objectType)
|
||||||
|
{
|
||||||
|
update_query_with_predicate(query, predicate, schema, *schema.find(objectType));
|
||||||
|
|
||||||
|
// Test the constructed query in core
|
||||||
|
std::string validateMessage = query.validate();
|
||||||
|
precondition(validateMessage.empty(), validateMessage.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
}}
|
|
@ -0,0 +1,34 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright 2015 Realm Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef REALM_QUERY_BUILDER_HPP
|
||||||
|
#define REALM_QUERY_BUILDER_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "parser.hpp"
|
||||||
|
|
||||||
|
namespace realm {
|
||||||
|
class Query;
|
||||||
|
class Schema;
|
||||||
|
|
||||||
|
namespace query_builder {
|
||||||
|
void apply_predicate(Query &query, parser::Predicate &predicate, Schema &schema, std::string objectType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // REALM_QUERY_BUILDER_HPP
|
Loading…
Reference in New Issue