Add support for wrapping a LinkView in a Results
This commit is contained in:
parent
1b48c71932
commit
71911ee221
|
@ -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());
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
@ -96,9 +113,10 @@ size_t Results::size()
|
||||||
{
|
{
|
||||||
validate_read();
|
validate_read();
|
||||||
switch (m_mode) {
|
switch (m_mode) {
|
||||||
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()
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue