From 870fe78aad5363f17b51c241932ce33840c302e2 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Thu, 3 Sep 2015 15:46:31 -0700 Subject: [PATCH] support sorting by a single property --- src/RJSResults.mm | 32 +++++++++++++++++++++++++++++++- src/object-store/results.cpp | 18 ++++++++++++++---- src/object-store/results.hpp | 16 +++++++++++++++- tests/ResultsTests.js | 25 +++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 6 deletions(-) diff --git a/src/RJSResults.mm b/src/RJSResults.mm index 0557c1b4..c1ffe118 100644 --- a/src/RJSResults.mm +++ b/src/RJSResults.mm @@ -59,6 +59,32 @@ void ResultsPropertyNames(JSContextRef ctx, JSObjectRef object, JSPropertyNameAc } } +JSValueRef SortByProperty(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { + try { + Results *results = RJSGetInternal(thisObject); + RJSValidateArgumentRange(argumentCount, 1, 2); + std::string propName = RJSValidatedStringForValue(ctx, arguments[0]); + Property *prop = results->object_schema.property_for_name(propName); + if (!prop) { + throw std::runtime_error("Property '" + propName + "' does not exist on object type '" + results->object_schema.name + "'"); + } + + bool ascending = true; + if (argumentCount == 2) { + ascending = RJSValidatedValueToBool(ctx, arguments[1]); + } + + SortOrder sort = {{prop->table_column}, {ascending}}; + results->setSort(sort); + } + catch (std::exception &exp) { + if (jsException) { + *jsException = RJSMakeError(ctx, exp); + } + } + return NULL; +} + JSObjectRef RJSResultsCreate(JSContextRef ctx, SharedRealm realm, std::string className) { TableRef table = ObjectStore::table_for_object_type(realm->read_group(), className); return RJSWrapObject(ctx, RJSResultsClass(), new Results(realm, realm->config().schema->at(className), table->where())); @@ -83,6 +109,10 @@ JSObjectRef RJSResultsCreate(JSContextRef ctx, SharedRealm realm, std::string cl JSClassRef RJSResultsClass() { - static JSClassRef s_objectClass = RJSCreateWrapperClass("Results", ResultsGetProperty, NULL, NULL, NULL, ResultsPropertyNames); + const JSStaticFunction resultsFuncs[] = { + {"sortByProperty", SortByProperty, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, + {NULL, NULL}, + }; + static JSClassRef s_objectClass = RJSCreateWrapperClass("Results", ResultsGetProperty, NULL, resultsFuncs, NULL, ResultsPropertyNames); return s_objectClass; } diff --git a/src/object-store/results.cpp b/src/object-store/results.cpp index 6b240f59..f33fc465 100644 --- a/src/object-store/results.cpp +++ b/src/object-store/results.cpp @@ -21,17 +21,26 @@ using namespace realm; -Results::Results(SharedRealm &r, ObjectSchema &o, Query q) : +Results::Results(SharedRealm &r, ObjectSchema &o, Query q, SortOrder s) : realm(r), object_schema(o), backing_query(q), table_view(backing_query.find_all()) { + setSort(std::move(s)); } -size_t Results::size() { +size_t Results::size() +{ verify_attached(); return table_view.size(); } -Row Results::get(std::size_t row_ndx) { +void Results::setSort(SortOrder s) +{ + sort_order = std::make_unique(std::move(s)); + table_view.sort(sort_order->columnIndices, sort_order->ascending); +} + +Row Results::get(std::size_t row_ndx) +{ verify_attached(); if (row_ndx >= table_view.size()) { throw std::range_error(std::string("Index ") + std::to_string(row_ndx) + " is outside of range 0..." + @@ -40,7 +49,8 @@ Row Results::get(std::size_t row_ndx) { return table_view.get(row_ndx); } -void Results::verify_attached() { +void Results::verify_attached() +{ if (!table_view.is_attached()) { throw std::runtime_error("Tableview is not attached"); } diff --git a/src/object-store/results.hpp b/src/object-store/results.hpp index a58136c9..fcb3e894 100644 --- a/src/object-store/results.hpp +++ b/src/object-store/results.hpp @@ -23,8 +23,19 @@ #import namespace realm { + struct SortOrder { + std::vector columnIndices; + std::vector ascending; + + explicit operator bool() const { + return !columnIndices.empty(); + } + }; + + static SortOrder s_defaultSort = {{}, {}}; + struct Results { - Results(SharedRealm &r, ObjectSchema &o, Query q); + Results(SharedRealm &r, ObjectSchema &o, Query q, SortOrder s = s_defaultSort); size_t size(); Row get(std::size_t row_ndx); void verify_attached(); @@ -33,6 +44,9 @@ namespace realm { ObjectSchema &object_schema; Query backing_query; TableView table_view; + std::unique_ptr sort_order; + + void setSort(SortOrder s); }; } diff --git a/tests/ResultsTests.js b/tests/ResultsTests.js index ebd4e2ed..7c953bb5 100644 --- a/tests/ResultsTests.js +++ b/tests/ResultsTests.js @@ -74,4 +74,29 @@ var ResultsTests = { } TestCase.assertEqual(1, count); }, + testSort: function() { + var realm = new Realm({schema: [TestObjectSchema]}); + var objects = realm.objects('TestObject'); + realm.write(function() { + realm.create('TestObject', [2]); + realm.create('TestObject', [3]); + realm.create('TestObject', [1]); + realm.create('TestObject', [4]); + realm.create('TestObject', [0]); + }); + + objects.sortByProperty('doubleCol'); + TestCase.assertEqual(objects[0].doubleCol, 0); + TestCase.assertEqual(objects[1].doubleCol, 1); + TestCase.assertEqual(objects[2].doubleCol, 2); + TestCase.assertEqual(objects[3].doubleCol, 3); + TestCase.assertEqual(objects[4].doubleCol, 4); + + objects.sortByProperty('doubleCol', false); + TestCase.assertEqual(objects[0].doubleCol, 4); + TestCase.assertEqual(objects[1].doubleCol, 3); + TestCase.assertEqual(objects[2].doubleCol, 2); + TestCase.assertEqual(objects[3].doubleCol, 1); + TestCase.assertEqual(objects[4].doubleCol, 0); + }, }