From 3b698400b784ee62892d20b186646df493344a5d Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Tue, 10 Nov 2015 14:24:30 -0800 Subject: [PATCH] support for querying boolean properties --- src/object-store/parser/parser.cpp | 14 ++++++---- src/object-store/parser/parser.hpp | 2 +- src/object-store/parser/query_builder.cpp | 34 +++++++++++------------ tests/RealmTests.js | 8 ++++-- tests/ResultsTests.js | 4 +-- tests/schemas.js | 5 ++-- 6 files changed, 36 insertions(+), 31 deletions(-) diff --git a/src/object-store/parser/parser.cpp b/src/object-store/parser/parser.cpp index 699739db..2479b287 100644 --- a/src/object-store/parser/parser.cpp +++ b/src/object-store/parser/parser.cpp @@ -23,7 +23,6 @@ #include #include #include -#include using namespace pegtl; @@ -56,6 +55,9 @@ struct int_num : plus< digit > {}; struct number : seq< minus, sor< float_num, hex_num, int_num > > {}; +struct true_value : pegtl_istring_t("true") {}; +struct false_value : pegtl_istring_t("false") {}; + // key paths struct key_path : list< seq< sor< alpha, one< '_' > >, star< sor< alnum, one< '_', '-' > > > >, one< '.' > > {}; @@ -64,7 +66,7 @@ struct argument_index : until< at< one< '}' > >, must< digit > > {}; struct argument : seq< one< '{' >, must< argument_index >, any > {}; // expressions and operators -struct expr : sor< dq_string, sq_string, key_path, number, argument > {}; +struct expr : sor< dq_string, sq_string, number, argument, true_value, false_value, key_path > {}; struct eq : sor< two< '=' >, one< '=' > > {}; struct noteq : pegtl::string< '!', '=' > {}; @@ -87,8 +89,8 @@ struct comparison_pred : seq< expr, sor< padded_oper, symbolic_oper >, expr > {} struct pred; struct group_pred : if_must< one< '(' >, pad< pred, blank >, one< ')' > > {}; -struct true_pred : sor< pegtl_istring_t("truepredicate"), pegtl_istring_t("true") > {}; -struct false_pred : sor< pegtl_istring_t("falsepredicate"), pegtl_istring_t("false") > {}; +struct true_pred : pegtl_istring_t("truepredicate") {}; +struct false_pred : pegtl_istring_t("falsepredicate") {}; struct not_pre : sor< seq< one< '!' >, star< blank > >, seq< pegtl_istring_t("not"), plus< blank > > > {}; struct atom_pred : seq< opt< not_pre >, pad< sor< group_pred, true_pred, false_pred, comparison_pred >, blank > > {}; @@ -207,6 +209,8 @@ EXPRESSION_ACTION(dq_string_content, Expression::Type::String) EXPRESSION_ACTION(sq_string_content, Expression::Type::String) EXPRESSION_ACTION(key_path, Expression::Type::KeyPath) EXPRESSION_ACTION(number, Expression::Type::Number) +EXPRESSION_ACTION(true_value, Expression::Type::True) +EXPRESSION_ACTION(false_value, Expression::Type::False) EXPRESSION_ACTION(argument_index, Expression::Type::Argument) @@ -228,7 +232,6 @@ template<> struct action< false_pred > } }; - #define OPERATOR_ACTION(rule, oper) \ template<> struct action< rule > { \ static void apply( const input & in, ParserState & state ) { \ @@ -245,7 +248,6 @@ OPERATOR_ACTION(begins, Predicate::Operator::BeginsWith) OPERATOR_ACTION(ends, Predicate::Operator::EndsWith) OPERATOR_ACTION(contains, Predicate::Operator::Contains) - template<> struct action< one< '(' > > { static void apply( const input & in, ParserState & state ) diff --git a/src/object-store/parser/parser.hpp b/src/object-store/parser/parser.hpp index 568c446b..4792285a 100644 --- a/src/object-store/parser/parser.hpp +++ b/src/object-store/parser/parser.hpp @@ -28,7 +28,7 @@ namespace realm { namespace parser { struct Expression { - enum class Type { Number, String, KeyPath, Argument } type; + enum class Type { Number, String, KeyPath, Argument, True, False } type; std::string s; Expression() {} Expression(Type t, std::string s) : type(t), s(s) {} diff --git a/src/object-store/parser/query_builder.cpp b/src/object-store/parser/query_builder.cpp index 004b821e..8f4aeeee 100644 --- a/src/object-store/parser/query_builder.cpp +++ b/src/object-store/parser/query_builder.cpp @@ -152,7 +152,7 @@ void add_string_constraint_to_query(realm::Query& query, template struct ColumnOfTypeHelper { - static Columns convert(TableGetter&& table, unsigned int idx) + static Columns convert(TableGetter&& table, size_t idx) { return table()->template column(idx); } @@ -160,7 +160,7 @@ struct ColumnOfTypeHelper { template struct ColumnOfTypeHelper { - static Columns convert(TableGetter&& table, unsigned int idx) + static Columns convert(TableGetter&& table, size_t idx) { return table()->template column(idx); } @@ -171,7 +171,7 @@ struct ValueOfTypeHelper; template struct ValueOfTypeHelper { - static Int convert(TableGetter&&, const std::string & value) + static Int convert(TableGetter&&, const parser::Expression & value) { assert(0); } @@ -179,41 +179,41 @@ struct ValueOfTypeHelper { template struct ValueOfTypeHelper { - static bool convert(TableGetter&&, const std::string & value) + static bool convert(TableGetter&&, const parser::Expression & value) { - assert(0); + return value.type == parser::Expression::Type::True; } }; template struct ValueOfTypeHelper { - static Double convert(TableGetter&&, const std::string & value) + static Double convert(TableGetter&&, const parser::Expression & value) { - return std::stod(value); + return std::stod(value.s); } }; template struct ValueOfTypeHelper { - static Float convert(TableGetter&&, const std::string & value) + static Float convert(TableGetter&&, const parser::Expression & value) { - return std::stof(value); + return std::stof(value.s); } }; template struct ValueOfTypeHelper { - static Int convert(TableGetter&&, const std::string & value) + static Int convert(TableGetter&&, const parser::Expression & value) { - return std::stoll(value); + return std::stoll(value.s); } }; template struct ValueOfTypeHelper { - static std::string convert(TableGetter&&, const std::string & value) + static std::string convert(TableGetter&&, const parser::Expression & value) { - return value; + return value.s; } }; @@ -222,8 +222,8 @@ auto value_of_type_for_query(TableGetter&& tables, Value&& value) { const bool isColumnIndex = std::is_same::type>::value; using helper = std::conditional_t, - ValueOfTypeHelper>; + ColumnOfTypeHelper, + ValueOfTypeHelper>; return helper::convert(std::forward(tables), std::forward(value)); } @@ -310,11 +310,11 @@ void add_comparison_to_query(Query &query, Predicate &pred, Schema &schema, Obje 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); + do_add_comparison_to_query(query, schema, object_schema, prop, cmpr.op, indexes, prop->table_column, cmpr.expr[1]); } 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); + do_add_comparison_to_query(query, schema, object_schema, prop, cmpr.op, indexes, cmpr.expr[0], prop->table_column); } else { throw std::runtime_error("Predicate expressions must compare a keypath and another keypath or a constant value"); diff --git a/tests/RealmTests.js b/tests/RealmTests.js index 747f3969..7187fa75 100644 --- a/tests/RealmTests.js +++ b/tests/RealmTests.js @@ -237,10 +237,10 @@ module.exports = BaseTest.extend({ testRealmObjects: function() { var realm = new Realm({schema: [schemas.PersonObject]}); realm.write(function() { - realm.create('PersonObject', ['Ari', 10]); - realm.create('PersonObject', ['Tim', 11]); + realm.create('PersonObject', ['Ari', 10, false]); + realm.create('PersonObject', ['Tim', 11, false]); realm.create('PersonObject', {'name': 'Bjarne', 'age': 12}); - realm.create('PersonObject', {'name': 'Alex', 'age': 12}); + realm.create('PersonObject', {'name': 'Alex', 'age': 12, 'married': true}); }); TestCase.assertThrows(function() { @@ -270,6 +270,8 @@ module.exports = BaseTest.extend({ TestCase.assertEqual(realm.objects('PersonObject', 'age >= 11 && age < 13').length, 3); TestCase.assertEqual(realm.objects('PersonObject', 'name = "Tim"').length, 1); TestCase.assertEqual(realm.objects('PersonObject', 'name = \'Tim\'').length, 1); + TestCase.assertEqual(realm.objects('PersonObject', 'married == TRUE').length, 1); + TestCase.assertEqual(realm.objects('PersonObject', 'married == false').length, 3); }, testNotifications: function() { diff --git a/tests/ResultsTests.js b/tests/ResultsTests.js index 3c82ab00..f26f7633 100644 --- a/tests/ResultsTests.js +++ b/tests/ResultsTests.js @@ -24,8 +24,8 @@ module.exports = BaseTest.extend({ testResultsSubscript: function() { var realm = new Realm({schema: [schemas.PersonObject]}); realm.write(function() { - realm.create('PersonObject', ['name1', 1]); - realm.create('PersonObject', ['name2', 2]); + realm.create('PersonObject', ['name1', 1, false]); + realm.create('PersonObject', ['name2', 2, false]); }); var people = realm.objects('PersonObject'); diff --git a/tests/schemas.js b/tests/schemas.js index fa385476..6cc11815 100644 --- a/tests/schemas.js +++ b/tests/schemas.js @@ -17,8 +17,9 @@ function PersonObject() {} PersonObject.prototype.schema = { name: 'PersonObject', properties: [ - {name: 'name', type: Realm.Types.STRING}, - {name: 'age', type: Realm.Types.DOUBLE}, + {name: 'name', type: Realm.Types.STRING}, + {name: 'age', type: Realm.Types.DOUBLE}, + {name: 'married', type: Realm.Types.BOOL, default: false} ] }; PersonObject.prototype.description = function() {