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:
parent
beda604425
commit
db4e184524
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -30,7 +30,8 @@ createMethods(List.prototype, objectTypes.LIST, [
|
||||||
'filtered',
|
'filtered',
|
||||||
'sorted',
|
'sorted',
|
||||||
'snapshot',
|
'snapshot',
|
||||||
'isValid',
|
'isValid',
|
||||||
|
'indexOf',
|
||||||
'addListener',
|
'addListener',
|
||||||
'removeListener',
|
'removeListener',
|
||||||
'removeAllListeners',
|
'removeAllListeners',
|
||||||
|
|
|
@ -30,6 +30,7 @@ createMethods(Results.prototype, objectTypes.RESULTS, [
|
||||||
'sorted',
|
'sorted',
|
||||||
'snapshot',
|
'snapshot',
|
||||||
'isValid',
|
'isValid',
|
||||||
|
'indexOf',
|
||||||
'addListener',
|
'addListener',
|
||||||
'removeListener',
|
'removeListener',
|
||||||
'removeAllListeners',
|
'removeAllListeners',
|
||||||
|
|
|
@ -36,7 +36,6 @@ Object.defineProperty(iteratorPrototype, Symbol.iterator, {
|
||||||
'concat',
|
'concat',
|
||||||
'join',
|
'join',
|
||||||
'slice',
|
'slice',
|
||||||
'indexOf',
|
|
||||||
'lastIndexOf',
|
'lastIndexOf',
|
||||||
'every',
|
'every',
|
||||||
'some',
|
'some',
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 = {
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue