From 71911ee22112057c83582976467a76a4254cd1ca Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Wed, 16 Mar 2016 15:02:24 -0700 Subject: [PATCH] Add support for wrapping a LinkView in a Results --- src/impl/results_notifier.cpp | 1 + src/impl/results_notifier.hpp | 1 + src/list.cpp | 9 +++- src/list.hpp | 1 + src/results.cpp | 85 +++++++++++++++++++++++++++++++---- src/results.hpp | 11 ++++- tests/list.cpp | 32 ++++++++++++- 7 files changed, 128 insertions(+), 12 deletions(-) diff --git a/src/impl/results_notifier.cpp b/src/impl/results_notifier.cpp index de1ce338..c6b0f65c 100644 --- a/src/impl/results_notifier.cpp +++ b/src/impl/results_notifier.cpp @@ -28,6 +28,7 @@ ResultsNotifier::ResultsNotifier(Results& target) : BackgroundCollection(target.get_realm()) , m_target_results(&target) , m_sort(target.get_sort()) +, m_from_linkview(target.get_linkview().get() != nullptr) { Query q = target.get_query(); set_table(*q.get_table()); diff --git a/src/impl/results_notifier.hpp b/src/impl/results_notifier.hpp index 2482b770..bb4bd024 100644 --- a/src/impl/results_notifier.hpp +++ b/src/impl/results_notifier.hpp @@ -41,6 +41,7 @@ private: Results* m_target_results; const SortOrder m_sort; + bool m_from_linkview; // The source Query, in handover form iff m_sg is null std::unique_ptr> m_query_handover; diff --git a/src/list.cpp b/src/list.cpp index b4b59aa6..b6ac8c61 100644 --- a/src/list.cpp +++ b/src/list.cpp @@ -155,7 +155,14 @@ void List::delete_all() Results List::sort(SortOrder order) { - return Results(m_realm, *m_object_schema, get_query(), std::move(order)); + verify_attached(); + return Results(m_realm, *m_object_schema, m_link_view, util::none, std::move(order)); +} + +Results List::filter(Query q) +{ + verify_attached(); + return Results(m_realm, *m_object_schema, m_link_view, get_query().and_query(std::move(q))); } // These definitions rely on that LinkViews are interned by core diff --git a/src/list.hpp b/src/list.hpp index 43b20a93..1b4f2a07 100644 --- a/src/list.hpp +++ b/src/list.hpp @@ -67,6 +67,7 @@ public: void delete_all(); Results sort(SortOrder order); + Results filter(Query q); bool operator==(List const& rgt) const noexcept; diff --git a/src/results.cpp b/src/results.cpp index acf79aad..525e4b49 100644 --- a/src/results.cpp +++ b/src/results.cpp @@ -57,6 +57,21 @@ Results::Results(SharedRealm r, const ObjectSchema &o, Table& table) { } +Results::Results(SharedRealm r, const ObjectSchema& o, LinkViewRef lv, util::Optional q, SortOrder s) +: m_realm(std::move(r)) +, m_object_schema(&o) +, m_link_view(lv) +, m_table(&lv->get_target_table()) +, m_sort(std::move(s)) +, m_mode(Mode::LinkView) +{ + REALM_ASSERT(m_sort.column_indices.size() == m_sort.ascending.size()); + if (q) { + m_query = std::move(*q); + m_mode = Mode::Query; + } +} + Results::~Results() { if (m_notifier) { @@ -72,6 +87,8 @@ void Results::validate_read() const throw InvalidatedException(); if (m_mode == Mode::TableView && !m_table_view.is_attached()) throw InvalidatedException(); + if (m_mode == Mode::LinkView && !m_link_view->is_attached()) + throw InvalidatedException(); } void Results::validate_write() const @@ -96,9 +113,10 @@ size_t Results::size() { validate_read(); switch (m_mode) { - case Mode::Empty: return 0; - case Mode::Table: return m_table->size(); - case Mode::Query: return m_query.count(); + case Mode::Empty: return 0; + case Mode::Table: return m_table->size(); + case Mode::Query: return m_query.count(); + case Mode::LinkView: return m_link_view->size(); case Mode::TableView: update_tableview(); return m_table_view.size(); @@ -120,12 +138,21 @@ RowExpr Results::get(size_t row_ndx) if (row_ndx < m_table->size()) return m_table->get(row_ndx); break; + case Mode::LinkView: + if (update_linkview()) { + if (row_ndx < m_link_view->size()) + return m_link_view->get(row_ndx); + break; + } + REALM_FALLTHROUGH; case Mode::Query: case Mode::TableView: update_tableview(); - if (row_ndx < m_table_view.size()) - return (!m_live && !m_table_view.is_row_attached(row_ndx)) ? RowExpr() : m_table_view.get(row_ndx); - break; + if (row_ndx >= m_table_view.size()) + break; + if (!m_live && !m_table_view.is_row_attached(row_ndx)) + return {}; + return m_table_view.get(row_ndx); } throw OutOfBoundsIndexException{row_ndx, size()}; @@ -139,6 +166,10 @@ util::Optional Results::first() return none; case Mode::Table: return m_table->size() == 0 ? util::none : util::make_optional(m_table->front()); + case Mode::LinkView: + if (update_linkview()) + return m_link_view->size() == 0 ? util::none : util::make_optional(m_link_view->get(0)); + REALM_FALLTHROUGH; case Mode::Query: case Mode::TableView: update_tableview(); @@ -155,6 +186,10 @@ util::Optional Results::last() return none; case Mode::Table: return m_table->size() == 0 ? util::none : util::make_optional(m_table->back()); + case Mode::LinkView: + if (update_linkview()) + return m_link_view->size() == 0 ? util::none : util::make_optional(m_link_view->get(m_link_view->size() - 1)); + REALM_FALLTHROUGH; case Mode::Query: case Mode::TableView: update_tableview(); @@ -163,12 +198,24 @@ util::Optional Results::last() REALM_UNREACHABLE(); } +bool Results::update_linkview() +{ + if (m_sort) { + m_query = get_query(); + m_mode = Mode::Query; + update_tableview(); + return false; + } + return true; +} + void Results::update_tableview() { validate_read(); switch (m_mode) { case Mode::Empty: case Mode::Table: + case Mode::LinkView: return; case Mode::Query: m_table_view = m_query.find_all(); @@ -214,6 +261,10 @@ size_t Results::index_of(size_t row_ndx) return not_found; case Mode::Table: return row_ndx; + case Mode::LinkView: + if (update_linkview()) + return m_link_view->find(row_ndx); + REALM_FALLTHROUGH; case Mode::Query: case Mode::TableView: update_tableview(); @@ -241,6 +292,10 @@ util::Optional Results::aggregate(size_t column, bool return_none_for_emp if (return_none_for_empty && m_table->size() == 0) return none; return util::Optional(getter(*m_table)); + case Mode::LinkView: + m_query = get_query(); + m_mode = Mode::Query; + REALM_FALLTHROUGH; case Mode::Query: case Mode::TableView: this->update_tableview(); @@ -315,6 +370,10 @@ void Results::clear() update_tableview(); m_table_view.clear(RemoveMode::unordered); break; + case Mode::LinkView: + validate_write(); + m_link_view->remove_all_target_rows(); + break; } } @@ -327,6 +386,8 @@ Query Results::get_query() const return m_query; case Mode::TableView: return m_table_view.get_query(); + case Mode::LinkView: + return m_table->where(m_link_view); case Mode::Table: return m_table->where(); } @@ -339,6 +400,10 @@ TableView Results::get_tableview() switch (m_mode) { case Mode::Empty: return {}; + case Mode::LinkView: + if (update_linkview()) + return m_table->where(m_link_view).find_all(); + REALM_FALLTHROUGH; case Mode::Query: case Mode::TableView: update_tableview(); @@ -352,12 +417,16 @@ TableView Results::get_tableview() Results Results::sort(realm::SortOrder&& sort) const { REALM_ASSERT(sort.column_indices.size() == sort.ascending.size()); - return Results(m_realm, get_object_schema(), get_query(), std::move(sort)); + if (m_link_view) + return Results(m_realm, *m_object_schema, m_link_view, m_query, std::move(sort)); + return Results(m_realm, *m_object_schema, get_query(), std::move(sort)); } Results Results::filter(Query&& q) const { - return Results(m_realm, get_object_schema(), get_query().and_query(std::move(q)), get_sort()); + if (m_link_view) + return Results(m_realm, *m_object_schema, m_link_view, get_query().and_query(std::move(q)), m_sort); + return Results(m_realm, *m_object_schema, get_query().and_query(std::move(q)), m_sort); } void Results::prepare_async() diff --git a/src/results.hpp b/src/results.hpp index 7c6f53cf..65a971df 100644 --- a/src/results.hpp +++ b/src/results.hpp @@ -53,6 +53,7 @@ public: Results() = default; Results(SharedRealm r, const ObjectSchema& o, Table& table); Results(SharedRealm r, const ObjectSchema& o, Query q, SortOrder s = {}); + Results(SharedRealm r, const ObjectSchema& o, LinkViewRef lv, util::Optional q = {}, SortOrder s = {}); ~Results(); // Results is copyable and moveable @@ -80,6 +81,9 @@ public: // Get the object type which will be returned by get() StringData get_object_type() const noexcept; + // Get the LinkView this Results is derived from, if any + LinkViewRef get_linkview() const { return m_link_view; } + // Set whether the TableView should sync if needed before accessing results void set_live(bool live); @@ -125,6 +129,7 @@ public: Empty, // Backed by nothing (for missing tables) Table, // Backed directly by a Table Query, // Backed by a query that has not yet been turned into a TableView + LinkView, // Backed directly by a LinkView TableView // Backed by a TableView created from a Query }; // Get the currrent mode of the Results @@ -171,8 +176,6 @@ public: UnsupportedColumnTypeException(size_t column, const Table* table); }; - void update_tableview(); - // Create an async query from this Results // The query will be run on a background thread and delivered to the callback, // and then rerun after each commit (if needed) and redelivered if it changed @@ -193,6 +196,7 @@ private: const ObjectSchema *m_object_schema; Query m_query; TableView m_table_view; + LinkViewRef m_link_view; Table* m_table = nullptr; SortOrder m_sort; bool m_live = true; @@ -203,6 +207,9 @@ private: bool m_has_used_table_view = false; bool m_wants_background_updates = true; + void update_tableview(); + bool update_linkview(); + void validate_read() const; void validate_write() const; diff --git a/tests/list.cpp b/tests/list.cpp index e0d15ccb..2ccdf65a 100644 --- a/tests/list.cpp +++ b/tests/list.cpp @@ -5,8 +5,9 @@ #include "binding_context.hpp" #include "list.hpp" -#include "property.hpp" #include "object_schema.hpp" +#include "property.hpp" +#include "results.hpp" #include "schema.hpp" #include "impl/realm_coordinator.hpp" @@ -219,4 +220,33 @@ TEST_CASE("list") { } } } + + SECTION("sort()") { + auto objectschema = &*r->config().schema->find("origin"); + List list(r, *objectschema, lv); + auto results = list.sort({{0}, {false}}); + + REQUIRE(&results.get_object_schema() == objectschema); + REQUIRE(results.get_mode() == Results::Mode::LinkView); + REQUIRE(results.size() == 10); + REQUIRE(results.sum(0) == 45); + + for (size_t i = 0; i < 10; ++i) { + REQUIRE(results.get(i).get_index() == 9 - i); + } + } + + SECTION("filter()") { + auto objectschema = &*r->config().schema->find("origin"); + List list(r, *objectschema, lv); + auto results = list.filter(target->where().greater(0, 5)); + + REQUIRE(&results.get_object_schema() == objectschema); + REQUIRE(results.get_mode() == Results::Mode::Query); + REQUIRE(results.size() == 4); + + for (size_t i = 0; i < 4; ++i) { + REQUIRE(results.get(i).get_index() == i + 6); + } + } }