Add methods to create snapshot of List and Results
The Results class was updated to match the style of List and include a flag (m_live) that determines if it should sync updates. If an object in the static Results is deleted, then it will return null.
This commit is contained in:
parent
602613b992
commit
632f9d737e
|
@ -13,6 +13,12 @@ module.exports = {
|
|||
|
||||
class List {}
|
||||
|
||||
// Non-mutating methods:
|
||||
util.createMethods(List.prototype, constants.propTypes.LIST, [
|
||||
'snapshot',
|
||||
]);
|
||||
|
||||
// Mutating methods:
|
||||
util.createMethods(List.prototype, constants.propTypes.LIST, [
|
||||
'pop',
|
||||
'shift',
|
||||
|
|
|
@ -14,6 +14,7 @@ module.exports = {
|
|||
class Results {}
|
||||
|
||||
util.createMethods(Results.prototype, constants.objectTypes.RESULTS, [
|
||||
'snapshot',
|
||||
'sortByProperty',
|
||||
]);
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "js_list.hpp"
|
||||
#include "js_object.hpp"
|
||||
#include "js_results.hpp"
|
||||
#include "js_util.hpp"
|
||||
#include "object_accessor.hpp"
|
||||
|
||||
|
@ -184,6 +185,22 @@ JSValueRef ListSplice(JSContextRef ctx, JSObjectRef function, JSObjectRef thisOb
|
|||
return NULL;
|
||||
}
|
||||
|
||||
JSValueRef ListStaticResults(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
||||
try {
|
||||
List *list = RJSGetInternal<List *>(thisObject);
|
||||
RJSValidateArgumentCount(argumentCount, 0);
|
||||
|
||||
Query query = list->get_query();
|
||||
return RJSResultsCreate(ctx, list->realm(), list->object_schema, query, false);
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
if (jsException) {
|
||||
*jsException = RJSMakeError(ctx, exp);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JSObjectRef RJSListCreate(JSContextRef ctx, realm::List &list) {
|
||||
return RJSWrapObject<List *>(ctx, RJSListClass(), new List(list));
|
||||
}
|
||||
|
@ -194,6 +211,7 @@ static const JSStaticFunction RJSListFuncs[] = {
|
|||
{"shift", ListShift, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
{"unshift", ListUnshift, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
{"splice", ListSplice, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
{"snapshot", ListStaticResults, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
|
|
|
@ -22,9 +22,12 @@ JSValueRef ResultsGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef
|
|||
return JSValueMakeNumber(ctx, size);
|
||||
}
|
||||
|
||||
return RJSObjectCreate(ctx, Object(results->get_realm(),
|
||||
results->object_schema,
|
||||
results->get(RJSValidatedPositiveIndex(indexStr))));
|
||||
auto row = results->get(RJSValidatedPositiveIndex(indexStr));
|
||||
if (!row) {
|
||||
return JSValueMakeNull(ctx);
|
||||
}
|
||||
|
||||
return RJSObjectCreate(ctx, Object(results->get_realm(), results->object_schema, row));
|
||||
}
|
||||
catch (std::out_of_range &exp) {
|
||||
// getters for nonexistent properties in JS should always return undefined
|
||||
|
@ -62,19 +65,40 @@ bool ResultsSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef proper
|
|||
|
||||
void ResultsPropertyNames(JSContextRef ctx, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames) {
|
||||
Results *results = RJSGetInternal<Results *>(object);
|
||||
size_t size = results->size();
|
||||
|
||||
char str[32];
|
||||
for (int i = 0; i < results->size(); i++) {
|
||||
sprintf(str, "%i", i);
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
sprintf(str, "%zu", i);
|
||||
JSStringRef name = JSStringCreateWithUTF8CString(str);
|
||||
JSPropertyNameAccumulatorAddName(propertyNames, name);
|
||||
JSStringRelease(name);
|
||||
}
|
||||
}
|
||||
|
||||
JSValueRef SortByProperty(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
||||
JSValueRef ResultsStaticCopy(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
||||
try {
|
||||
Results *results = RJSGetInternal<Results *>(thisObject);
|
||||
RJSValidateArgumentCount(argumentCount, 0);
|
||||
|
||||
Results *copy = new Results(*results);
|
||||
copy->set_live(false);
|
||||
|
||||
return RJSWrapObject<Results *>(ctx, RJSResultsClass(), copy);
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
if (jsException) {
|
||||
*jsException = RJSMakeError(ctx, exp);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JSValueRef ResultsSortByProperty(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
||||
try {
|
||||
Results *results = RJSGetInternal<Results *>(thisObject);
|
||||
RJSValidateArgumentRange(argumentCount, 1, 2);
|
||||
|
||||
std::string propName = RJSValidatedStringForValue(ctx, arguments[0]);
|
||||
const Property *prop = results->object_schema.property_for_name(propName);
|
||||
if (!prop) {
|
||||
|
@ -105,7 +129,6 @@ JSObjectRef RJSResultsCreate(JSContextRef ctx, SharedRealm realm, std::string cl
|
|||
return RJSWrapObject<Results *>(ctx, RJSResultsClass(), new Results(realm, *object_schema, *table));
|
||||
}
|
||||
|
||||
|
||||
JSObjectRef RJSResultsCreate(JSContextRef ctx, SharedRealm realm, std::string className, std::string queryString, std::vector<JSValueRef> args) {
|
||||
TableRef table = ObjectStore::table_for_object_type(realm->read_group(), className);
|
||||
Query query = table->where();
|
||||
|
@ -121,8 +144,16 @@ JSObjectRef RJSResultsCreate(JSContextRef ctx, SharedRealm realm, std::string cl
|
|||
return RJSWrapObject<Results *>(ctx, RJSResultsClass(), new Results(realm, *object_schema, std::move(query)));
|
||||
}
|
||||
|
||||
JSObjectRef RJSResultsCreate(JSContextRef ctx, SharedRealm realm, const ObjectSchema &objectSchema, const Query &query, bool live) {
|
||||
Results *results = new Results(realm, objectSchema, query);
|
||||
results->set_live(live);
|
||||
|
||||
return RJSWrapObject<Results *>(ctx, RJSResultsClass(), results);
|
||||
}
|
||||
|
||||
static const JSStaticFunction RJSResultsFuncs[] = {
|
||||
{"sortByProperty", SortByProperty, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
{"snapshot", ResultsStaticCopy, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
{"sortByProperty", ResultsSortByProperty, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
|
||||
namespace realm {
|
||||
class Realm;
|
||||
class Query;
|
||||
typedef std::shared_ptr<Realm> SharedRealm;
|
||||
}
|
||||
|
||||
JSClassRef RJSResultsClass();
|
||||
JSObjectRef RJSResultsCreate(JSContextRef ctx, realm::SharedRealm realm, std::string className);
|
||||
JSObjectRef RJSResultsCreate(JSContextRef ctx, realm::SharedRealm realm, std::string className, std::string query, std::vector<JSValueRef> args);
|
||||
JSObjectRef RJSResultsCreate(JSContextRef ctx, realm::SharedRealm realm, const realm::ObjectSchema &objectSchema, const realm::Query &query, bool live = true);
|
||||
|
|
|
@ -59,6 +59,11 @@ void List::remove(size_t row_ndx) {
|
|||
m_link_view->remove(row_ndx);
|
||||
}
|
||||
|
||||
Query List::get_query() {
|
||||
verify_attached();
|
||||
return m_link_view->get_target_table().where(m_link_view);
|
||||
}
|
||||
|
||||
void List::verify_valid_row(size_t row_ndx, bool insertion) {
|
||||
size_t size = m_link_view->size();
|
||||
if (row_ndx > size || (!insertion && row_ndx == size)) {
|
||||
|
|
|
@ -47,6 +47,8 @@ namespace realm {
|
|||
template<typename ValueType, typename ContextType>
|
||||
void set(ContextType ctx, ValueType value, size_t list_ndx);
|
||||
|
||||
Query get_query();
|
||||
|
||||
void verify_valid_row(size_t row_ndx, bool insertion = false);
|
||||
void verify_attached();
|
||||
void verify_in_tranaction();
|
||||
|
|
|
@ -64,6 +64,17 @@ void Results::validate_write() const
|
|||
throw InvalidTransactionException("Must be in a write transaction");
|
||||
}
|
||||
|
||||
void Results::set_live(bool live)
|
||||
{
|
||||
if (!live && m_mode == Mode::Table) {
|
||||
m_query = m_table->where();
|
||||
m_mode = Mode::Query;
|
||||
}
|
||||
|
||||
update_tableview();
|
||||
m_live = live;
|
||||
}
|
||||
|
||||
size_t Results::size()
|
||||
{
|
||||
validate_read();
|
||||
|
@ -91,7 +102,7 @@ RowExpr Results::get(size_t row_ndx)
|
|||
case Mode::TableView:
|
||||
update_tableview();
|
||||
if (row_ndx < m_table_view.size())
|
||||
return m_table_view.get(row_ndx);
|
||||
return (!m_live && !m_table_view.is_row_attached(row_ndx)) ? RowExpr() : m_table_view.get(row_ndx);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -147,7 +158,9 @@ void Results::update_tableview()
|
|||
m_mode = Mode::TableView;
|
||||
break;
|
||||
case Mode::TableView:
|
||||
m_table_view.sync_if_needed();
|
||||
if (m_live) {
|
||||
m_table_view.sync_if_needed();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,6 +60,9 @@ public:
|
|||
// Get the object type which will be returned by get()
|
||||
StringData get_object_type() const noexcept { return object_schema.name; }
|
||||
|
||||
// Set whether the TableView should sync if needed before accessing results
|
||||
void set_live(bool live);
|
||||
|
||||
// Get the size of this results
|
||||
// Can be either O(1) or O(N) depending on the state of things
|
||||
size_t size();
|
||||
|
@ -153,6 +156,7 @@ private:
|
|||
TableView m_table_view;
|
||||
Table* m_table = nullptr;
|
||||
SortOrder m_sort;
|
||||
bool m_live = true;
|
||||
|
||||
Mode m_mode = Mode::Empty;
|
||||
|
||||
|
|
|
@ -341,4 +341,38 @@ module.exports = BaseTest.extend({
|
|||
TestCase.assertEqual(array.length, 2);
|
||||
TestCase.assertEqual(objects.length, 4);
|
||||
},
|
||||
|
||||
testStaticResults: function() {
|
||||
var realm = new Realm({schema: [schemas.LinkTypes, schemas.TestObject]});
|
||||
var objects = realm.objects('TestObject');
|
||||
var array;
|
||||
|
||||
realm.write(function() {
|
||||
var obj = realm.create('LinkTypesObject', [[1], [2], [[3], [4]]]);
|
||||
array = obj.arrayCol;
|
||||
});
|
||||
|
||||
var objectsCopy = objects.snapshot();
|
||||
var arrayCopy = array.snapshot();
|
||||
|
||||
TestCase.assertEqual(objectsCopy.length, 4);
|
||||
TestCase.assertEqual(arrayCopy.length, 2);
|
||||
|
||||
realm.write(function() {
|
||||
array.push([5]);
|
||||
TestCase.assertEqual(objectsCopy.length, 4);
|
||||
TestCase.assertEqual(arrayCopy.length, 2);
|
||||
|
||||
TestCase.assertEqual(objectsCopy.snapshot().length, 4);
|
||||
TestCase.assertEqual(arrayCopy.snapshot().length, 2);
|
||||
|
||||
TestCase.assertEqual(objects.snapshot().length, 5);
|
||||
TestCase.assertEqual(array.snapshot().length, 3);
|
||||
|
||||
realm.delete(array[0]);
|
||||
TestCase.assertEqual(objectsCopy.length, 4);
|
||||
TestCase.assertEqual(arrayCopy.length, 2);
|
||||
TestCase.assertEqual(arrayCopy[0], null);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue