Added method to find index of object in collections (#1094)

* Added method to find index of object in collections

* rework as the indexOf method
This commit is contained in:
astigsen 2017-06-26 04:43:49 -07:00 committed by Yavor Georgiev
parent beda604425
commit db4e184524
9 changed files with 118 additions and 5 deletions

View File

@ -4,7 +4,7 @@ vNext Release notes (TBD)
* None * None
### Enhancements ### Enhancements
* None. * Added `indexOf()` method on `Realm.Results` and `Realm.List` that returns the index of the object in the collection.
### Bug fixes ### Bug fixes
* Fix opening synced realms with a logged-in admin user. * Fix opening synced realms with a logged-in admin user.

View File

@ -164,6 +164,16 @@ class Collection {
*/ */
findIndex(callback, thisArg) {} findIndex(callback, thisArg) {}
/**
Finds the index of the given object in the collection.
* @param {Realm.Object} [object] - The object to search for in the collection.
* @throws {Error} If the argument does not belong to the realm.
* @returns {number} representing the index where the object was found, or `-1`
* if not in collection.
* @since 1.8.2
*/
indexOf(object) {}
/** /**
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach Array.prototype.forEach} * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach Array.prototype.forEach}
* @param {function} callback - Function to execute on each object in the collection. * @param {function} callback - Function to execute on each object in the collection.

View File

@ -30,7 +30,8 @@ createMethods(List.prototype, objectTypes.LIST, [
'filtered', 'filtered',
'sorted', 'sorted',
'snapshot', 'snapshot',
'isValid', 'isValid',
'indexOf',
'addListener', 'addListener',
'removeListener', 'removeListener',
'removeAllListeners', 'removeAllListeners',

View File

@ -30,6 +30,7 @@ createMethods(Results.prototype, objectTypes.RESULTS, [
'sorted', 'sorted',
'snapshot', 'snapshot',
'isValid', 'isValid',
'indexOf',
'addListener', 'addListener',
'removeListener', 'removeListener',
'removeAllListeners', 'removeAllListeners',

View File

@ -36,7 +36,6 @@ Object.defineProperty(iteratorPrototype, Symbol.iterator, {
'concat', 'concat',
'join', 'join',
'slice', 'slice',
'indexOf',
'lastIndexOf', 'lastIndexOf',
'every', 'every',
'some', 'some',

View File

@ -72,7 +72,8 @@ struct ListClass : ClassDefinition<T, realm::js::List<T>, CollectionClass<T>> {
static void filtered(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &); static void filtered(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void sorted(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &); static void sorted(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void is_valid(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &); static void is_valid(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void index_of(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
// observable // observable
static void add_listener(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &); static void add_listener(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void remove_listener(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &); static void remove_listener(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
@ -90,6 +91,7 @@ struct ListClass : ClassDefinition<T, realm::js::List<T>, CollectionClass<T>> {
{"filtered", wrap<filtered>}, {"filtered", wrap<filtered>},
{"sorted", wrap<sorted>}, {"sorted", wrap<sorted>},
{"isValid", wrap<is_valid>}, {"isValid", wrap<is_valid>},
{"indexOf", wrap<index_of>},
{"addListener", wrap<add_listener>}, {"addListener", wrap<add_listener>},
{"removeListener", wrap<remove_listener>}, {"removeListener", wrap<remove_listener>},
{"removeAllListeners", wrap<remove_all_listeners>}, {"removeAllListeners", wrap<remove_all_listeners>},
@ -256,7 +258,33 @@ template<typename T>
void ListClass<T>::is_valid(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) { void ListClass<T>::is_valid(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
return_value.set(get_internal<T, ListClass<T>>(this_object)->is_valid()); return_value.set(get_internal<T, ListClass<T>>(this_object)->is_valid());
} }
template<typename T>
void ListClass<T>::index_of(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 1);
ObjectType arg = Value::validated_to_object(ctx, arguments[0]);
if (Object::template is_instance<RealmObjectClass<T>>(ctx, arg)) {
auto object = get_internal<T, RealmObjectClass<T>>(arg);
if (!object->is_valid()) {
throw std::runtime_error("Object is invalid. Either it has been previously deleted or the Realm it belongs to has been closed.");
}
auto list = get_internal<T, ListClass<T>>(this_object);
size_t ndx = list->find(object->row());
if (ndx == realm::not_found) {
return_value.set(-1);
}
else {
return_value.set((uint32_t)ndx);
}
}
else {
return_value.set(-1);
}
}
template<typename T> template<typename T>
void ListClass<T>::add_listener(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) { void ListClass<T>::add_listener(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 1); validate_argument_count(argc, 1);

View File

@ -74,6 +74,8 @@ struct ResultsClass : ClassDefinition<T, realm::js::Results<T>, CollectionClass<
static void sorted(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &); static void sorted(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void is_valid(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &); static void is_valid(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void index_of(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
// observable // observable
static void add_listener(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &); static void add_listener(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
static void remove_listener(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &); static void remove_listener(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
@ -89,6 +91,7 @@ struct ResultsClass : ClassDefinition<T, realm::js::Results<T>, CollectionClass<
{"addListener", wrap<add_listener>}, {"addListener", wrap<add_listener>},
{"removeListener", wrap<remove_listener>}, {"removeListener", wrap<remove_listener>},
{"removeAllListeners", wrap<remove_all_listeners>}, {"removeAllListeners", wrap<remove_all_listeners>},
{"indexOf", wrap<index_of>},
}; };
PropertyMap<T> const properties = { PropertyMap<T> const properties = {
@ -238,6 +241,38 @@ void ResultsClass<T>::is_valid(ContextType ctx, FunctionType, ObjectType this_ob
return_value.set(get_internal<T, ResultsClass<T>>(this_object)->is_valid()); return_value.set(get_internal<T, ResultsClass<T>>(this_object)->is_valid());
} }
template<typename T>
void ResultsClass<T>::index_of(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 1);
ObjectType arg = Value::validated_to_object(ctx, arguments[0]);
if (Object::template is_instance<RealmObjectClass<T>>(ctx, arg)) {
auto object = get_internal<T, RealmObjectClass<T>>(arg);
if (!object->is_valid()) {
throw std::runtime_error("Object is invalid. Either it has been previously deleted or the Realm it belongs to has been closed.");
}
size_t ndx;
try {
auto results = get_internal<T, ResultsClass<T>>(this_object);
ndx = results->index_of(object->row());
}
catch (realm::Results::IncorrectTableException &) {
throw std::runtime_error("Object type does not match the type contained in result");
}
if (ndx == realm::not_found) {
return_value.set(-1);
}
else {
return_value.set((uint32_t)ndx);
}
}
else {
return_value.set(-1);
}
}
template<typename T> template<typename T>
void ResultsClass<T>::add_listener(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) { void ResultsClass<T>::add_listener(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 1); validate_argument_count(argc, 1);

View File

@ -583,6 +583,7 @@ module.exports = {
var index = list.findIndex(function(p) {return p.name == 'Tim'}); var index = list.findIndex(function(p) {return p.name == 'Tim'});
TestCase.assertEqual(index, 1); TestCase.assertEqual(index, 1);
TestCase.assertEqual(list.indexOf(list[index]), index);
TestCase.assertEqual(list.reduce(function(n, p) {return n + p.age}, 0), 33); TestCase.assertEqual(list.reduce(function(n, p) {return n + p.age}, 0), 33);
TestCase.assertEqual(list.reduceRight(function(n, p) {return n + p.age}, 0), 33); TestCase.assertEqual(list.reduceRight(function(n, p) {return n + p.age}, 0), 33);

View File

@ -383,6 +383,42 @@ module.exports = {
TestCase.assertEqual(snapshot.length, 0); TestCase.assertEqual(snapshot.length, 0);
}); });
}, },
testResultsFindIndexOfObject: function() {
var realm = new Realm({schema: [schemas.TestObject]});
var object1, object2, object3;
realm.write(function() {
object1 = realm.create('TestObject', {doubleCol: 1});
object2 = realm.create('TestObject', {doubleCol: 2});
object3 = realm.create('TestObject', {doubleCol: 2});
});
// Search in base table
const objects = realm.objects('TestObject');
TestCase.assertEqual(objects.indexOf(object1), 0);
TestCase.assertEqual(objects.indexOf(object2), 1);
TestCase.assertEqual(objects.indexOf(object3), 2);
// Search in filtered query
const results = objects.filtered("doubleCol == 2");
TestCase.assertEqual(results.indexOf(object1), -1);
TestCase.assertEqual(results.indexOf(object2), 0);
TestCase.assertEqual(results.indexOf(object3), 1);
const nonRealmObject = {test: "this is an object"};
TestCase.assertEqual(objects.indexOf(nonRealmObject), -1);
// Searching for object from the wrong realm
var realm2 = new Realm({path: '2.realm', schema: realm.schema});
var object4;
realm2.write(function() {
object4 = realm2.create('TestObject', {doubleCol: 1});
});
TestCase.assertThrows(function() {
objects.indexOf(object4);
});
},
testAddListener: function() { testAddListener: function() {
return new Promise((resolve, _reject) => { return new Promise((resolve, _reject) => {
@ -408,4 +444,6 @@ module.exports = {
}); });
}) })
} }
}; };