support for querying boolean properties

This commit is contained in:
Ari Lazier 2015-11-10 14:24:30 -08:00
parent bb16ffa7fe
commit 3b698400b7
6 changed files with 36 additions and 31 deletions

View File

@ -23,7 +23,6 @@
#include <pegtl.hh> #include <pegtl.hh>
#include <pegtl/analyze.hh> #include <pegtl/analyze.hh>
#include <pegtl/trace.hh> #include <pegtl/trace.hh>
#include <pegtl/internal/pegtl_string.hh>
using namespace pegtl; using namespace pegtl;
@ -56,6 +55,9 @@ struct int_num : plus< digit > {};
struct number : seq< minus, sor< float_num, hex_num, int_num > > {}; 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 // key paths
struct key_path : list< seq< sor< alpha, one< '_' > >, star< sor< alnum, one< '_', '-' > > > >, one< '.' > > {}; 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 > {}; struct argument : seq< one< '{' >, must< argument_index >, any > {};
// expressions and operators // 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 eq : sor< two< '=' >, one< '=' > > {};
struct noteq : pegtl::string< '!', '=' > {}; struct noteq : pegtl::string< '!', '=' > {};
@ -87,8 +89,8 @@ struct comparison_pred : seq< expr, sor< padded_oper, symbolic_oper >, expr > {}
struct pred; struct pred;
struct group_pred : if_must< one< '(' >, pad< pred, blank >, one< ')' > > {}; struct group_pred : if_must< one< '(' >, pad< pred, blank >, one< ')' > > {};
struct true_pred : sor< pegtl_istring_t("truepredicate"), pegtl_istring_t("true") > {}; struct true_pred : pegtl_istring_t("truepredicate") {};
struct false_pred : sor< pegtl_istring_t("falsepredicate"), pegtl_istring_t("false") > {}; struct false_pred : pegtl_istring_t("falsepredicate") {};
struct not_pre : sor< seq< one< '!' >, star< blank > >, seq< pegtl_istring_t("not"), plus< blank > > > {}; 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 > > {}; 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(sq_string_content, Expression::Type::String)
EXPRESSION_ACTION(key_path, Expression::Type::KeyPath) EXPRESSION_ACTION(key_path, Expression::Type::KeyPath)
EXPRESSION_ACTION(number, Expression::Type::Number) 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) EXPRESSION_ACTION(argument_index, Expression::Type::Argument)
@ -228,7 +232,6 @@ template<> struct action< false_pred >
} }
}; };
#define OPERATOR_ACTION(rule, oper) \ #define OPERATOR_ACTION(rule, oper) \
template<> struct action< rule > { \ template<> struct action< rule > { \
static void apply( const input & in, ParserState & state ) { \ 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(ends, Predicate::Operator::EndsWith)
OPERATOR_ACTION(contains, Predicate::Operator::Contains) OPERATOR_ACTION(contains, Predicate::Operator::Contains)
template<> struct action< one< '(' > > template<> struct action< one< '(' > >
{ {
static void apply( const input & in, ParserState & state ) static void apply( const input & in, ParserState & state )

View File

@ -28,7 +28,7 @@ namespace realm {
namespace parser { namespace parser {
struct Expression struct Expression
{ {
enum class Type { Number, String, KeyPath, Argument } type; enum class Type { Number, String, KeyPath, Argument, True, False } type;
std::string s; std::string s;
Expression() {} Expression() {}
Expression(Type t, std::string s) : type(t), s(s) {} Expression(Type t, std::string s) : type(t), s(s) {}

View File

@ -152,7 +152,7 @@ void add_string_constraint_to_query(realm::Query& query,
template <typename RequestedType, typename TableGetter> template <typename RequestedType, typename TableGetter>
struct ColumnOfTypeHelper { struct ColumnOfTypeHelper {
static Columns<RequestedType> convert(TableGetter&& table, unsigned int idx) static Columns<RequestedType> convert(TableGetter&& table, size_t idx)
{ {
return table()->template column<RequestedType>(idx); return table()->template column<RequestedType>(idx);
} }
@ -160,7 +160,7 @@ struct ColumnOfTypeHelper {
template <typename TableGetter> template <typename TableGetter>
struct ColumnOfTypeHelper<DateTime, TableGetter> { struct ColumnOfTypeHelper<DateTime, TableGetter> {
static Columns<Int> convert(TableGetter&& table, unsigned int idx) static Columns<Int> convert(TableGetter&& table, size_t idx)
{ {
return table()->template column<Int>(idx); return table()->template column<Int>(idx);
} }
@ -171,7 +171,7 @@ struct ValueOfTypeHelper;
template <typename TableGetter> template <typename TableGetter>
struct ValueOfTypeHelper<DateTime, TableGetter> { struct ValueOfTypeHelper<DateTime, TableGetter> {
static Int convert(TableGetter&&, const std::string & value) static Int convert(TableGetter&&, const parser::Expression & value)
{ {
assert(0); assert(0);
} }
@ -179,41 +179,41 @@ struct ValueOfTypeHelper<DateTime, TableGetter> {
template <typename TableGetter> template <typename TableGetter>
struct ValueOfTypeHelper<bool, TableGetter> { struct ValueOfTypeHelper<bool, TableGetter> {
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 <typename TableGetter> template <typename TableGetter>
struct ValueOfTypeHelper<Double, TableGetter> { struct ValueOfTypeHelper<Double, TableGetter> {
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 <typename TableGetter> template <typename TableGetter>
struct ValueOfTypeHelper<Float, TableGetter> { struct ValueOfTypeHelper<Float, TableGetter> {
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 <typename TableGetter> template <typename TableGetter>
struct ValueOfTypeHelper<Int, TableGetter> { struct ValueOfTypeHelper<Int, TableGetter> {
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 <typename TableGetter> template <typename TableGetter>
struct ValueOfTypeHelper<String, TableGetter> { struct ValueOfTypeHelper<String, TableGetter> {
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<size_t, typename std::remove_reference<Value>::type>::value; const bool isColumnIndex = std::is_same<size_t, typename std::remove_reference<Value>::type>::value;
using helper = std::conditional_t<isColumnIndex, using helper = std::conditional_t<isColumnIndex,
ColumnOfTypeHelper<RequestedType, TableGetter>, ColumnOfTypeHelper<RequestedType, TableGetter>,
ValueOfTypeHelper<RequestedType, TableGetter>>; ValueOfTypeHelper<RequestedType, TableGetter>>;
return helper::convert(std::forward<TableGetter>(tables), std::forward<Value>(value)); return helper::convert(std::forward<TableGetter>(tables), std::forward<Value>(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; auto t0 = cmpr.expr[0].type, t1 = cmpr.expr[1].type;
if (t0 == parser::Expression::Type::KeyPath && t1 != parser::Expression::Type::KeyPath) { 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); 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) { 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); 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 { 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");

View File

@ -237,10 +237,10 @@ module.exports = BaseTest.extend({
testRealmObjects: function() { testRealmObjects: function() {
var realm = new Realm({schema: [schemas.PersonObject]}); var realm = new Realm({schema: [schemas.PersonObject]});
realm.write(function() { realm.write(function() {
realm.create('PersonObject', ['Ari', 10]); realm.create('PersonObject', ['Ari', 10, false]);
realm.create('PersonObject', ['Tim', 11]); realm.create('PersonObject', ['Tim', 11, false]);
realm.create('PersonObject', {'name': 'Bjarne', 'age': 12}); 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() { 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', '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', '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() { testNotifications: function() {

View File

@ -24,8 +24,8 @@ module.exports = BaseTest.extend({
testResultsSubscript: function() { testResultsSubscript: function() {
var realm = new Realm({schema: [schemas.PersonObject]}); var realm = new Realm({schema: [schemas.PersonObject]});
realm.write(function() { realm.write(function() {
realm.create('PersonObject', ['name1', 1]); realm.create('PersonObject', ['name1', 1, false]);
realm.create('PersonObject', ['name2', 2]); realm.create('PersonObject', ['name2', 2, false]);
}); });
var people = realm.objects('PersonObject'); var people = realm.objects('PersonObject');

View File

@ -17,8 +17,9 @@ function PersonObject() {}
PersonObject.prototype.schema = { PersonObject.prototype.schema = {
name: 'PersonObject', name: 'PersonObject',
properties: [ properties: [
{name: 'name', type: Realm.Types.STRING}, {name: 'name', type: Realm.Types.STRING},
{name: 'age', type: Realm.Types.DOUBLE}, {name: 'age', type: Realm.Types.DOUBLE},
{name: 'married', type: Realm.Types.BOOL, default: false}
] ]
}; };
PersonObject.prototype.description = function() { PersonObject.prototype.description = function() {