Skip to content

Commit

Permalink
Allow using aggregate operations on Mixed properties in queries (#7398)
Browse files Browse the repository at this point in the history
This is something which Cocoa and the query engine supports but the core query
parser did not.
  • Loading branch information
tgoyne authored Mar 1, 2024
1 parent 3d798ca commit e8065ba
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 12 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

### Enhancements
* <New feature description> (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
* <How do the end-user experience this issue? what was the impact?> ([#????](https://github.com/realm/realm-core/issues/????), since v?.?.?)
Expand Down
3 changes: 3 additions & 0 deletions src/realm/parser/driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1146,6 +1146,9 @@ std::unique_ptr<Subexpr> LinkAggrNode::visit(ParserDriver* drv, DataType)
case col_type_Timestamp:
subexpr = link_prop->column<Timestamp>(col_key).clone();
break;
case col_type_Mixed:
subexpr = link_prop->column<Mixed>(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()))));
Expand Down
18 changes: 7 additions & 11 deletions src/realm/query_expression.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -1923,7 +1918,7 @@ class SimpleQuerySupport : public ObjPropertyExpr<T> {
}
}

void evaluate(ObjKey key, ValueBase& destination) override
void evaluate(ObjKey key, ValueBase& destination)
{
Value<T>& d = static_cast<Value<T>&>(destination);
d.set(0, m_link_map.get_target_table()->get_object(key).template get<T>(m_column_key));
Expand Down Expand Up @@ -2015,6 +2010,7 @@ class Columns<Decimal128> : public SimpleQuerySupport<Decimal128> {
template <>
class Columns<Mixed> : public SimpleQuerySupport<Mixed> {
public:
using SimpleQuerySupport::evaluate; // don't hide the ObjKey overload
using SimpleQuerySupport::SimpleQuerySupport;
void evaluate(size_t index, ValueBase& destination) override
{
Expand Down Expand Up @@ -3891,7 +3887,7 @@ class Columns : public ObjPropertyExpr<T> {
}
}

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();
Expand Down Expand Up @@ -3993,7 +3989,7 @@ class SubColumns : public Subexpr, public SubColumnBase {

std::unique_ptr<Subexpr> max_of() override
{
if constexpr (realm::is_any_v<T, Int, Float, Double, Decimal128, Timestamp>) {
if constexpr (realm::is_any_v<T, Int, Float, Double, Decimal128, Timestamp, Mixed>) {
return max().clone();
}
else {
Expand All @@ -4002,7 +3998,7 @@ class SubColumns : public Subexpr, public SubColumnBase {
}
std::unique_ptr<Subexpr> min_of() override
{
if constexpr (realm::is_any_v<T, Int, Float, Double, Decimal128, Timestamp>) {
if constexpr (realm::is_any_v<T, Int, Float, Double, Decimal128, Timestamp, Mixed>) {
return min().clone();
}
else {
Expand All @@ -4011,7 +4007,7 @@ class SubColumns : public Subexpr, public SubColumnBase {
}
std::unique_ptr<Subexpr> sum_of() override
{
if constexpr (realm::is_any_v<T, Int, Float, Double, Decimal128>) {
if constexpr (realm::is_any_v<T, Int, Float, Double, Decimal128, Mixed>) {
return sum().clone();
}
else {
Expand All @@ -4020,7 +4016,7 @@ class SubColumns : public Subexpr, public SubColumnBase {
}
std::unique_ptr<Subexpr> avg_of() override
{
if constexpr (realm::is_any_v<T, Int, Float, Double, Decimal128>) {
if constexpr (realm::is_any_v<T, Int, Float, Double, Decimal128, Mixed>) {
return average().clone();
}
else {
Expand Down
15 changes: 15 additions & 0 deletions test/test_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string, double>;
Expand All @@ -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<int64_t>(item_info[i].second * 10), 0));
}
items->get_object(item_keys[0]).set(item_discount_col, discount_keys[2]); // milk -0.50
Expand All @@ -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();
Expand All @@ -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);
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit e8065ba

Please sign in to comment.