diff --git a/CHANGELOG.md b/CHANGELOG.md index a6fc915f3fa..c6411a408bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ### Enhancements * (PR [#????](https://github.com/realm/realm-core/pull/????)) -* None. +* Add support for using aggregate operations on Mixed properties in queries ([PR #7398](https://github.com/realm/realm-core/pull/7398)) ### Fixed * ([#????](https://github.com/realm/realm-core/issues/????), since v?.?.?) diff --git a/src/realm/parser/driver.cpp b/src/realm/parser/driver.cpp index 6dc9f32ce09..f0861ac9d9e 100644 --- a/src/realm/parser/driver.cpp +++ b/src/realm/parser/driver.cpp @@ -1146,6 +1146,9 @@ std::unique_ptr LinkAggrNode::visit(ParserDriver* drv, DataType) case col_type_Timestamp: subexpr = link_prop->column(col_key).clone(); break; + case col_type_Mixed: + subexpr = link_prop->column(col_key).clone(); + break; default: throw InvalidQueryError(util::format("collection aggregate not supported for type '%1'", get_data_type_name(DataType(col_key.get_type())))); diff --git a/src/realm/query_expression.hpp b/src/realm/query_expression.hpp index e00cfc64fd6..d0b9016b4a7 100644 --- a/src/realm/query_expression.hpp +++ b/src/realm/query_expression.hpp @@ -735,11 +735,6 @@ class Subexpr { virtual DataType get_type() const = 0; virtual void evaluate(size_t index, ValueBase& destination) = 0; - // This function supports SubColumnAggregate - virtual void evaluate(ObjKey, ValueBase&) - { - REALM_ASSERT(false); // Unimplemented - } virtual Mixed get_mixed() const { @@ -1923,7 +1918,7 @@ class SimpleQuerySupport : public ObjPropertyExpr { } } - void evaluate(ObjKey key, ValueBase& destination) override + void evaluate(ObjKey key, ValueBase& destination) { Value& d = static_cast&>(destination); d.set(0, m_link_map.get_target_table()->get_object(key).template get(m_column_key)); @@ -2015,6 +2010,7 @@ class Columns : public SimpleQuerySupport { template <> class Columns : public SimpleQuerySupport { public: + using SimpleQuerySupport::evaluate; // don't hide the ObjKey overload using SimpleQuerySupport::SimpleQuerySupport; void evaluate(size_t index, ValueBase& destination) override { @@ -3891,7 +3887,7 @@ class Columns : public ObjPropertyExpr { } } - void evaluate(ObjKey key, ValueBase& destination) override + void evaluate(ObjKey key, ValueBase& destination) { destination.init(false, 1); auto table = m_link_map.get_target_table(); @@ -3993,7 +3989,7 @@ class SubColumns : public Subexpr, public SubColumnBase { std::unique_ptr max_of() override { - if constexpr (realm::is_any_v) { + if constexpr (realm::is_any_v) { return max().clone(); } else { @@ -4002,7 +3998,7 @@ class SubColumns : public Subexpr, public SubColumnBase { } std::unique_ptr min_of() override { - if constexpr (realm::is_any_v) { + if constexpr (realm::is_any_v) { return min().clone(); } else { @@ -4011,7 +4007,7 @@ class SubColumns : public Subexpr, public SubColumnBase { } std::unique_ptr sum_of() override { - if constexpr (realm::is_any_v) { + if constexpr (realm::is_any_v) { return sum().clone(); } else { @@ -4020,7 +4016,7 @@ class SubColumns : public Subexpr, public SubColumnBase { } std::unique_ptr avg_of() override { - if constexpr (realm::is_any_v) { + if constexpr (realm::is_any_v) { return average().clone(); } else { diff --git a/test/test_parser.cpp b/test/test_parser.cpp index cd6c1665dde..be7a7bd9f6f 100644 --- a/test/test_parser.cpp +++ b/test/test_parser.cpp @@ -1296,6 +1296,7 @@ TEST(Parser_TwoColumnAggregates) ColKey item_price_col = items->add_column(type_Double, "price"); ColKey item_price_float_col = items->add_column(type_Float, "price_float"); ColKey item_price_decimal_col = items->add_column(type_Decimal, "price_decimal"); + ColKey item_price_mixed_col = items->add_column(type_Mixed, "price_mixed"); ColKey item_discount_col = items->add_column(*discounts, "discount"); ColKey item_creation_date = items->add_column(type_Timestamp, "creation_date"); using item_t = std::pair; @@ -1308,6 +1309,7 @@ TEST(Parser_TwoColumnAggregates) obj.set(item_price_col, item_info[i].second); obj.set(item_price_float_col, float(item_info[i].second)); obj.set(item_price_decimal_col, Decimal128(item_info[i].second)); + obj.set(item_price_mixed_col, Mixed(item_info[i].second)); obj.set(item_creation_date, Timestamp(static_cast(item_info[i].second * 10), 0)); } items->get_object(item_keys[0]).set(item_discount_col, discount_keys[2]); // milk -0.50 @@ -1320,6 +1322,7 @@ TEST(Parser_TwoColumnAggregates) ColKey items_col = t->add_column_list(*items, "items"); ColKey account_float_col = t->add_column(type_Float, "account_balance_float"); ColKey account_decimal_col = t->add_column(type_Decimal, "account_balance_decimal"); + ColKey account_mixed_col = t->add_column(type_Mixed, "account_balance_mixed"); ColKey account_creation_date_col = t->add_column(type_Timestamp, "account_creation_date"); Obj person0 = t->create_object(); @@ -1330,16 +1333,19 @@ TEST(Parser_TwoColumnAggregates) person0.set(account_col, double(10.0)); person0.set(account_float_col, float(10.0)); person0.set(account_decimal_col, Decimal128(10.0)); + person0.set(account_mixed_col, Mixed(10.0)); person0.set(account_creation_date_col, Timestamp(30, 0)); person1.set(id_col, int64_t(1)); person1.set(account_col, double(20.0)); person1.set(account_float_col, float(20.0)); person1.set(account_decimal_col, Decimal128(20.0)); + person1.set(account_mixed_col, Mixed(20.0)); person1.set(account_creation_date_col, Timestamp(50, 0)); person2.set(id_col, int64_t(2)); person2.set(account_col, double(30.0)); person2.set(account_float_col, float(30.0)); person2.set(account_decimal_col, Decimal128(30.0)); + person2.set(account_mixed_col, Mixed(30.0)); person2.set(account_creation_date_col, Timestamp(70, 0)); LnkLst list_0 = person0.get_linklist(items_col); @@ -1397,6 +1403,15 @@ TEST(Parser_TwoColumnAggregates) verify_query(test_context, t, "items.@min.price_decimal > account_balance_decimal", 0); verify_query(test_context, t, "items.@max.price_decimal > account_balance_decimal", 0); verify_query(test_context, t, "items.@avg.price_decimal > account_balance_decimal", 0); + // Mixed vs Mixed + verify_query(test_context, t, "items.@sum.price_mixed == 25.5", 2); // person0, person2 + verify_query(test_context, t, "items.@min.price_mixed == 4.0", 1); // person0 + verify_query(test_context, t, "items.@max.price_mixed == 9.5", 2); // person0, person2 + verify_query(test_context, t, "items.@avg.price_mixed == 6.375", 1); // person0 + verify_query(test_context, t, "items.@sum.price_mixed > account_balance_mixed", 2); + verify_query(test_context, t, "items.@min.price_mixed > account_balance_mixed", 0); + verify_query(test_context, t, "items.@max.price_mixed > account_balance_mixed", 0); + verify_query(test_context, t, "items.@avg.price_mixed > account_balance_mixed", 0); // Timestamp vs Timestamp verify_query(test_context, t, "items.@min.creation_date == T40:0", 1); // person0 verify_query(test_context, t, "items.@max.creation_date == T95:0", 2); // person0, person2