commit
071a65b449
|
@ -8,7 +8,8 @@
|
||||||
* Add common Array methods to List and Results
|
* Add common Array methods to List and Results
|
||||||
* Accept constructor in create() and objects() methods
|
* Accept constructor in create() and objects() methods
|
||||||
* Support relative paths when opening realms
|
* Support relative paths when opening realms
|
||||||
* Support for indexed bool, string, date, and int properties
|
* Support case insensitive queries
|
||||||
|
* Support for indexed bool, string, and int properties
|
||||||
|
|
||||||
### Bugfixes
|
### Bugfixes
|
||||||
* Fix for crash on Android when initializing the Realm module
|
* Fix for crash on Android when initializing the Realm module
|
||||||
|
|
|
@ -66,8 +66,9 @@ struct argument : seq< one< '$' >, must< argument_index > > {};
|
||||||
|
|
||||||
// expressions and operators
|
// expressions and operators
|
||||||
struct expr : sor< dq_string, sq_string, number, argument, true_value, false_value, key_path > {};
|
struct expr : sor< dq_string, sq_string, number, argument, true_value, false_value, key_path > {};
|
||||||
|
struct case_insensitive : pegtl_istring_t("[c]"){};
|
||||||
|
|
||||||
struct eq : sor< two< '=' >, one< '=' > > {};
|
struct eq : seq< sor< two< '=' >, one< '=' > >, opt< case_insensitive > >{};
|
||||||
struct noteq : pegtl::string< '!', '=' > {};
|
struct noteq : pegtl::string< '!', '=' > {};
|
||||||
struct lteq : pegtl::string< '<', '=' > {};
|
struct lteq : pegtl::string< '<', '=' > {};
|
||||||
struct lt : one< '<' > {};
|
struct lt : one< '<' > {};
|
||||||
|
@ -80,7 +81,7 @@ struct ends : pegtl_istring_t("endswith") {};
|
||||||
template<typename A, typename B>
|
template<typename A, typename B>
|
||||||
struct pad_plus : seq< plus< B >, A, plus< B > > {};
|
struct pad_plus : seq< plus< B >, A, plus< B > > {};
|
||||||
|
|
||||||
struct padded_oper : pad_plus< sor< contains, begins, ends >, blank > {};
|
struct padded_oper : pad_plus< seq< sor< contains, begins, ends>, opt< case_insensitive > >, blank > {};
|
||||||
struct symbolic_oper : pad< sor< eq, noteq, lteq, lt, gteq, gt >, blank > {};
|
struct symbolic_oper : pad< sor< eq, noteq, lteq, lt, gteq, gt >, blank > {};
|
||||||
|
|
||||||
// predicates
|
// predicates
|
||||||
|
@ -236,8 +237,7 @@ EXPRESSION_ACTION(number, Expression::Type::Number)
|
||||||
EXPRESSION_ACTION(true_value, Expression::Type::True)
|
EXPRESSION_ACTION(true_value, Expression::Type::True)
|
||||||
EXPRESSION_ACTION(false_value, Expression::Type::False)
|
EXPRESSION_ACTION(false_value, Expression::Type::False)
|
||||||
EXPRESSION_ACTION(argument_index, Expression::Type::Argument)
|
EXPRESSION_ACTION(argument_index, Expression::Type::Argument)
|
||||||
|
|
||||||
|
|
||||||
template<> struct action< true_pred >
|
template<> struct action< true_pred >
|
||||||
{
|
{
|
||||||
static void apply( const input & in, ParserState & state )
|
static void apply( const input & in, ParserState & state )
|
||||||
|
@ -271,7 +271,16 @@ OPERATOR_ACTION(lt, Predicate::Operator::LessThan)
|
||||||
OPERATOR_ACTION(begins, Predicate::Operator::BeginsWith)
|
OPERATOR_ACTION(begins, Predicate::Operator::BeginsWith)
|
||||||
OPERATOR_ACTION(ends, Predicate::Operator::EndsWith)
|
OPERATOR_ACTION(ends, Predicate::Operator::EndsWith)
|
||||||
OPERATOR_ACTION(contains, Predicate::Operator::Contains)
|
OPERATOR_ACTION(contains, Predicate::Operator::Contains)
|
||||||
|
|
||||||
|
template<> struct action< case_insensitive >
|
||||||
|
{
|
||||||
|
static void apply( const input & in, ParserState & state )
|
||||||
|
{
|
||||||
|
DEBUG_PRINT_TOKEN(in.string());
|
||||||
|
state.last_predicate()->cmpr.option = Predicate::OperatorOption::CaseInsensitive;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<> struct action< one< '(' > >
|
template<> struct action< one< '(' > >
|
||||||
{
|
{
|
||||||
static void apply( const input & in, ParserState & state )
|
static void apply( const input & in, ParserState & state )
|
||||||
|
|
|
@ -57,10 +57,17 @@ struct Predicate
|
||||||
EndsWith,
|
EndsWith,
|
||||||
Contains
|
Contains
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class OperatorOption
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
CaseInsensitive,
|
||||||
|
};
|
||||||
|
|
||||||
struct Comparison
|
struct Comparison
|
||||||
{
|
{
|
||||||
Operator op = Operator::None;
|
Operator op = Operator::None;
|
||||||
|
OperatorOption option = OperatorOption::None;
|
||||||
Expression expr[2] = {{Expression::Type::None, ""}, {Expression::Type::None, ""}};
|
Expression expr[2] = {{Expression::Type::None, ""}, {Expression::Type::None, ""}};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -164,11 +164,11 @@ void add_bool_constraint_to_query(Query &query, Predicate::Operator operatorType
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_string_constraint_to_query(Query &query,
|
void add_string_constraint_to_query(Query &query,
|
||||||
Predicate::Operator op,
|
Predicate::Comparison cmp,
|
||||||
Columns<String> &&column,
|
Columns<String> &&column,
|
||||||
std::string &&value) {
|
std::string &&value) {
|
||||||
bool case_sensitive = true;
|
bool case_sensitive = (cmp.option != Predicate::OperatorOption::CaseInsensitive);
|
||||||
switch (op) {
|
switch (cmp.op) {
|
||||||
case Predicate::Operator::BeginsWith:
|
case Predicate::Operator::BeginsWith:
|
||||||
query.and_query(column.begins_with(value, case_sensitive));
|
query.and_query(column.begins_with(value, case_sensitive));
|
||||||
break;
|
break;
|
||||||
|
@ -190,11 +190,11 @@ void add_string_constraint_to_query(Query &query,
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_string_constraint_to_query(realm::Query &query,
|
void add_string_constraint_to_query(realm::Query &query,
|
||||||
Predicate::Operator op,
|
Predicate::Comparison cmp,
|
||||||
std::string &&value,
|
std::string &&value,
|
||||||
Columns<String> &&column) {
|
Columns<String> &&column) {
|
||||||
bool case_sensitive = true;
|
bool case_sensitive = (cmp.option != Predicate::OperatorOption::CaseInsensitive);
|
||||||
switch (op) {
|
switch (cmp.op) {
|
||||||
case Predicate::Operator::Equal:
|
case Predicate::Operator::Equal:
|
||||||
query.and_query(column.equal(value, case_sensitive));
|
query.and_query(column.equal(value, case_sensitive));
|
||||||
break;
|
break;
|
||||||
|
@ -396,42 +396,42 @@ auto value_of_type_for_query(TableGetter&& tables, Value&& value, Arguments &arg
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename A, typename B>
|
template <typename A, typename B>
|
||||||
void do_add_comparison_to_query(Query &query, const Schema &schema, const ObjectSchema &object_schema, Predicate::Operator op,
|
void do_add_comparison_to_query(Query &query, const Schema &schema, const ObjectSchema &object_schema, Predicate::Comparison cmp,
|
||||||
const PropertyExpression &expr, A &lhs, B &rhs, Arguments &args)
|
const PropertyExpression &expr, A &lhs, B &rhs, Arguments &args)
|
||||||
{
|
{
|
||||||
auto type = expr.prop->type;
|
auto type = expr.prop->type;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case PropertyTypeBool:
|
case PropertyTypeBool:
|
||||||
add_bool_constraint_to_query(query, op, value_of_type_for_query<bool>(expr.table_getter, lhs, args),
|
add_bool_constraint_to_query(query, cmp.op, value_of_type_for_query<bool>(expr.table_getter, lhs, args),
|
||||||
value_of_type_for_query<bool>(expr.table_getter, rhs, args));
|
value_of_type_for_query<bool>(expr.table_getter, rhs, args));
|
||||||
break;
|
break;
|
||||||
case PropertyTypeDate:
|
case PropertyTypeDate:
|
||||||
add_numeric_constraint_to_query(query, op, value_of_type_for_query<DateTime>(expr.table_getter, lhs, args),
|
add_numeric_constraint_to_query(query, cmp.op, value_of_type_for_query<DateTime>(expr.table_getter, lhs, args),
|
||||||
value_of_type_for_query<DateTime>(expr.table_getter, rhs, args));
|
value_of_type_for_query<DateTime>(expr.table_getter, rhs, args));
|
||||||
break;
|
break;
|
||||||
case PropertyTypeDouble:
|
case PropertyTypeDouble:
|
||||||
add_numeric_constraint_to_query(query, op, value_of_type_for_query<Double>(expr.table_getter, lhs, args),
|
add_numeric_constraint_to_query(query, cmp.op, value_of_type_for_query<Double>(expr.table_getter, lhs, args),
|
||||||
value_of_type_for_query<Double>(expr.table_getter, rhs, args));
|
value_of_type_for_query<Double>(expr.table_getter, rhs, args));
|
||||||
break;
|
break;
|
||||||
case PropertyTypeFloat:
|
case PropertyTypeFloat:
|
||||||
add_numeric_constraint_to_query(query, op, value_of_type_for_query<Float>(expr.table_getter, lhs, args),
|
add_numeric_constraint_to_query(query, cmp.op, value_of_type_for_query<Float>(expr.table_getter, lhs, args),
|
||||||
value_of_type_for_query<Float>(expr.table_getter, rhs, args));
|
value_of_type_for_query<Float>(expr.table_getter, rhs, args));
|
||||||
break;
|
break;
|
||||||
case PropertyTypeInt:
|
case PropertyTypeInt:
|
||||||
add_numeric_constraint_to_query(query, op, value_of_type_for_query<Int>(expr.table_getter, lhs, args),
|
add_numeric_constraint_to_query(query, cmp.op, value_of_type_for_query<Int>(expr.table_getter, lhs, args),
|
||||||
value_of_type_for_query<Int>(expr.table_getter, rhs, args));
|
value_of_type_for_query<Int>(expr.table_getter, rhs, args));
|
||||||
break;
|
break;
|
||||||
case PropertyTypeString:
|
case PropertyTypeString:
|
||||||
add_string_constraint_to_query(query, op, value_of_type_for_query<String>(expr.table_getter, lhs, args),
|
add_string_constraint_to_query(query, cmp, value_of_type_for_query<String>(expr.table_getter, lhs, args),
|
||||||
value_of_type_for_query<String>(expr.table_getter, rhs, args));
|
value_of_type_for_query<String>(expr.table_getter, rhs, args));
|
||||||
break;
|
break;
|
||||||
case PropertyTypeData:
|
case PropertyTypeData:
|
||||||
add_binary_constraint_to_query(query, op, value_of_type_for_query<Binary>(expr.table_getter, lhs, args),
|
add_binary_constraint_to_query(query, cmp.op, value_of_type_for_query<Binary>(expr.table_getter, lhs, args),
|
||||||
value_of_type_for_query<Binary>(expr.table_getter, rhs, args));
|
value_of_type_for_query<Binary>(expr.table_getter, rhs, args));
|
||||||
break;
|
break;
|
||||||
case PropertyTypeObject:
|
case PropertyTypeObject:
|
||||||
case PropertyTypeArray:
|
case PropertyTypeArray:
|
||||||
add_link_constraint_to_query(query, op, expr, link_argument(lhs, rhs, args));
|
add_link_constraint_to_query(query, cmp.op, expr, link_argument(lhs, rhs, args));
|
||||||
break;
|
break;
|
||||||
default: {
|
default: {
|
||||||
throw std::runtime_error((std::string)"Object type " + string_for_property_type(type) + " not supported");
|
throw std::runtime_error((std::string)"Object type " + string_for_property_type(type) + " not supported");
|
||||||
|
@ -446,11 +446,11 @@ void add_comparison_to_query(Query &query, const Predicate &pred, Arguments &arg
|
||||||
auto object_schema = schema.find(type);
|
auto object_schema = schema.find(type);
|
||||||
if (t0 == parser::Expression::Type::KeyPath && t1 != parser::Expression::Type::KeyPath) {
|
if (t0 == parser::Expression::Type::KeyPath && t1 != parser::Expression::Type::KeyPath) {
|
||||||
PropertyExpression expr(query, schema, object_schema, cmpr.expr[0].s);
|
PropertyExpression expr(query, schema, object_schema, cmpr.expr[0].s);
|
||||||
do_add_comparison_to_query(query, schema, *object_schema, cmpr.op, expr, expr, cmpr.expr[1], args);
|
do_add_comparison_to_query(query, schema, *object_schema, cmpr, expr, expr, cmpr.expr[1], args);
|
||||||
}
|
}
|
||||||
else if (t0 != parser::Expression::Type::KeyPath && t1 == parser::Expression::Type::KeyPath) {
|
else if (t0 != parser::Expression::Type::KeyPath && t1 == parser::Expression::Type::KeyPath) {
|
||||||
PropertyExpression expr(query, schema, object_schema, cmpr.expr[1].s);
|
PropertyExpression expr(query, schema, object_schema, cmpr.expr[1].s);
|
||||||
do_add_comparison_to_query(query, schema, *object_schema, cmpr.op, expr, cmpr.expr[0], expr, args);
|
do_add_comparison_to_query(query, schema, *object_schema, cmpr, expr, cmpr.expr[0], expr, args);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw std::runtime_error("Predicate expressions must compare a keypath and another keypath or a constant value");
|
throw std::runtime_error("Predicate expressions must compare a keypath and another keypath or a constant value");
|
||||||
|
|
|
@ -197,10 +197,10 @@
|
||||||
["QueryThrows", "StringObject", "stringCol == 123"],
|
["QueryThrows", "StringObject", "stringCol == 123"],
|
||||||
["QueryThrows", "StringObject", "stringCol CONTAINS $0", 1],
|
["QueryThrows", "StringObject", "stringCol CONTAINS $0", 1],
|
||||||
|
|
||||||
["Disabled", "QueryCount", 3, "StringObject", "stringCol ==[c] 'a'"],
|
["QueryCount", 3, "StringObject", "stringCol ==[c] 'a'"],
|
||||||
["Disabled", "QueryCount", 5, "StringObject", "stringCol BEGINSWITH[c] 'A'"],
|
["QueryCount", 5, "StringObject", "stringCol BEGINSWITH[c] 'A'"],
|
||||||
["Disabled", "QueryCount", 4, "StringObject", "stringCol ENDSWITH[c] 'c'"],
|
["QueryCount", 4, "StringObject", "stringCol ENDSWITH[c] 'c'"],
|
||||||
["Disabled", "QueryCount", 2, "StringObject", "stringCol CONTAINS[c] 'B'"]
|
["QueryCount", 2, "StringObject", "stringCol CONTAINS[c] 'B'"]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue