Add support for wrapping a LinkView in a Results

This commit is contained in:
Thomas Goyne 2016-03-16 15:02:24 -07:00 committed by Thomas Goyne
parent 1b48c71932
commit 71911ee221
7 changed files with 128 additions and 12 deletions

View File

@ -28,6 +28,7 @@ ResultsNotifier::ResultsNotifier(Results& target)
: BackgroundCollection(target.get_realm()) : BackgroundCollection(target.get_realm())
, m_target_results(&target) , m_target_results(&target)
, m_sort(target.get_sort()) , m_sort(target.get_sort())
, m_from_linkview(target.get_linkview().get() != nullptr)
{ {
Query q = target.get_query(); Query q = target.get_query();
set_table(*q.get_table()); set_table(*q.get_table());

View File

@ -41,6 +41,7 @@ private:
Results* m_target_results; Results* m_target_results;
const SortOrder m_sort; const SortOrder m_sort;
bool m_from_linkview;
// The source Query, in handover form iff m_sg is null // The source Query, in handover form iff m_sg is null
std::unique_ptr<SharedGroup::Handover<Query>> m_query_handover; std::unique_ptr<SharedGroup::Handover<Query>> m_query_handover;

View File

@ -155,7 +155,14 @@ void List::delete_all()
Results List::sort(SortOrder order) 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 // These definitions rely on that LinkViews are interned by core

View File

@ -67,6 +67,7 @@ public:
void delete_all(); void delete_all();
Results sort(SortOrder order); Results sort(SortOrder order);
Results filter(Query q);
bool operator==(List const& rgt) const noexcept; bool operator==(List const& rgt) const noexcept;

View File

@ -57,6 +57,21 @@ Results::Results(SharedRealm r, const ObjectSchema &o, Table& table)
{ {
} }
Results::Results(SharedRealm r, const ObjectSchema& o, LinkViewRef lv, util::Optional<Query> 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() Results::~Results()
{ {
if (m_notifier) { if (m_notifier) {
@ -72,6 +87,8 @@ void Results::validate_read() const
throw InvalidatedException(); throw InvalidatedException();
if (m_mode == Mode::TableView && !m_table_view.is_attached()) if (m_mode == Mode::TableView && !m_table_view.is_attached())
throw InvalidatedException(); throw InvalidatedException();
if (m_mode == Mode::LinkView && !m_link_view->is_attached())
throw InvalidatedException();
} }
void Results::validate_write() const void Results::validate_write() const
@ -99,6 +116,7 @@ size_t Results::size()
case Mode::Empty: return 0; case Mode::Empty: return 0;
case Mode::Table: return m_table->size(); case Mode::Table: return m_table->size();
case Mode::Query: return m_query.count(); case Mode::Query: return m_query.count();
case Mode::LinkView: return m_link_view->size();
case Mode::TableView: case Mode::TableView:
update_tableview(); update_tableview();
return m_table_view.size(); return m_table_view.size();
@ -120,12 +138,21 @@ RowExpr Results::get(size_t row_ndx)
if (row_ndx < m_table->size()) if (row_ndx < m_table->size())
return m_table->get(row_ndx); return m_table->get(row_ndx);
break; 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::Query:
case Mode::TableView: case Mode::TableView:
update_tableview(); update_tableview();
if (row_ndx < m_table_view.size()) 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; 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()}; throw OutOfBoundsIndexException{row_ndx, size()};
@ -139,6 +166,10 @@ util::Optional<RowExpr> Results::first()
return none; return none;
case Mode::Table: case Mode::Table:
return m_table->size() == 0 ? util::none : util::make_optional(m_table->front()); 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::Query:
case Mode::TableView: case Mode::TableView:
update_tableview(); update_tableview();
@ -155,6 +186,10 @@ util::Optional<RowExpr> Results::last()
return none; return none;
case Mode::Table: case Mode::Table:
return m_table->size() == 0 ? util::none : util::make_optional(m_table->back()); 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::Query:
case Mode::TableView: case Mode::TableView:
update_tableview(); update_tableview();
@ -163,12 +198,24 @@ util::Optional<RowExpr> Results::last()
REALM_UNREACHABLE(); 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() void Results::update_tableview()
{ {
validate_read(); validate_read();
switch (m_mode) { switch (m_mode) {
case Mode::Empty: case Mode::Empty:
case Mode::Table: case Mode::Table:
case Mode::LinkView:
return; return;
case Mode::Query: case Mode::Query:
m_table_view = m_query.find_all(); m_table_view = m_query.find_all();
@ -214,6 +261,10 @@ size_t Results::index_of(size_t row_ndx)
return not_found; return not_found;
case Mode::Table: case Mode::Table:
return row_ndx; return row_ndx;
case Mode::LinkView:
if (update_linkview())
return m_link_view->find(row_ndx);
REALM_FALLTHROUGH;
case Mode::Query: case Mode::Query:
case Mode::TableView: case Mode::TableView:
update_tableview(); update_tableview();
@ -241,6 +292,10 @@ util::Optional<Mixed> Results::aggregate(size_t column, bool return_none_for_emp
if (return_none_for_empty && m_table->size() == 0) if (return_none_for_empty && m_table->size() == 0)
return none; return none;
return util::Optional<Mixed>(getter(*m_table)); return util::Optional<Mixed>(getter(*m_table));
case Mode::LinkView:
m_query = get_query();
m_mode = Mode::Query;
REALM_FALLTHROUGH;
case Mode::Query: case Mode::Query:
case Mode::TableView: case Mode::TableView:
this->update_tableview(); this->update_tableview();
@ -315,6 +370,10 @@ void Results::clear()
update_tableview(); update_tableview();
m_table_view.clear(RemoveMode::unordered); m_table_view.clear(RemoveMode::unordered);
break; 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; return m_query;
case Mode::TableView: case Mode::TableView:
return m_table_view.get_query(); return m_table_view.get_query();
case Mode::LinkView:
return m_table->where(m_link_view);
case Mode::Table: case Mode::Table:
return m_table->where(); return m_table->where();
} }
@ -339,6 +400,10 @@ TableView Results::get_tableview()
switch (m_mode) { switch (m_mode) {
case Mode::Empty: case Mode::Empty:
return {}; return {};
case Mode::LinkView:
if (update_linkview())
return m_table->where(m_link_view).find_all();
REALM_FALLTHROUGH;
case Mode::Query: case Mode::Query:
case Mode::TableView: case Mode::TableView:
update_tableview(); update_tableview();
@ -352,12 +417,16 @@ TableView Results::get_tableview()
Results Results::sort(realm::SortOrder&& sort) const Results Results::sort(realm::SortOrder&& sort) const
{ {
REALM_ASSERT(sort.column_indices.size() == sort.ascending.size()); 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 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() void Results::prepare_async()

View File

@ -53,6 +53,7 @@ public:
Results() = default; Results() = default;
Results(SharedRealm r, const ObjectSchema& o, Table& table); Results(SharedRealm r, const ObjectSchema& o, Table& table);
Results(SharedRealm r, const ObjectSchema& o, Query q, SortOrder s = {}); Results(SharedRealm r, const ObjectSchema& o, Query q, SortOrder s = {});
Results(SharedRealm r, const ObjectSchema& o, LinkViewRef lv, util::Optional<Query> q = {}, SortOrder s = {});
~Results(); ~Results();
// Results is copyable and moveable // Results is copyable and moveable
@ -80,6 +81,9 @@ public:
// Get the object type which will be returned by get() // Get the object type which will be returned by get()
StringData get_object_type() const noexcept; 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 // Set whether the TableView should sync if needed before accessing results
void set_live(bool live); void set_live(bool live);
@ -125,6 +129,7 @@ public:
Empty, // Backed by nothing (for missing tables) Empty, // Backed by nothing (for missing tables)
Table, // Backed directly by a Table Table, // Backed directly by a Table
Query, // Backed by a query that has not yet been turned into a TableView 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 TableView // Backed by a TableView created from a Query
}; };
// Get the currrent mode of the Results // Get the currrent mode of the Results
@ -171,8 +176,6 @@ public:
UnsupportedColumnTypeException(size_t column, const Table* table); UnsupportedColumnTypeException(size_t column, const Table* table);
}; };
void update_tableview();
// Create an async query from this Results // Create an async query from this Results
// The query will be run on a background thread and delivered to the callback, // 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 // and then rerun after each commit (if needed) and redelivered if it changed
@ -193,6 +196,7 @@ private:
const ObjectSchema *m_object_schema; const ObjectSchema *m_object_schema;
Query m_query; Query m_query;
TableView m_table_view; TableView m_table_view;
LinkViewRef m_link_view;
Table* m_table = nullptr; Table* m_table = nullptr;
SortOrder m_sort; SortOrder m_sort;
bool m_live = true; bool m_live = true;
@ -203,6 +207,9 @@ private:
bool m_has_used_table_view = false; bool m_has_used_table_view = false;
bool m_wants_background_updates = true; bool m_wants_background_updates = true;
void update_tableview();
bool update_linkview();
void validate_read() const; void validate_read() const;
void validate_write() const; void validate_write() const;

View File

@ -5,8 +5,9 @@
#include "binding_context.hpp" #include "binding_context.hpp"
#include "list.hpp" #include "list.hpp"
#include "property.hpp"
#include "object_schema.hpp" #include "object_schema.hpp"
#include "property.hpp"
#include "results.hpp"
#include "schema.hpp" #include "schema.hpp"
#include "impl/realm_coordinator.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);
}
}
} }