diff --git a/.vscode/settings.json b/.vscode/settings.json index 3db45b23b..ba3780745 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -96,5 +96,6 @@ "flutter/realm_flutter/ios/src/**": true, "flutter/realm_flutter/lib/**": true, "flutter/realm_flutter/test/**": true - } + }, + "dart.lineLength": 160 } \ No newline at end of file diff --git a/lib/src/native/realm_core.dart b/lib/src/native/realm_core.dart index 48cc4ce8e..bad2a7714 100644 --- a/lib/src/native/realm_core.dart +++ b/lib/src/native/realm_core.dart @@ -316,7 +316,7 @@ class _RealmCore { }); } - void removeRealmObject(RealmObject object) { + void deleteRealmObject(RealmObject object) { _realmLib.invokeGetBool(() => _realmLib.realm_object_delete(object.handle._pointer)); } @@ -424,10 +424,17 @@ class _RealmCore { }); } + void listDeleteAll(RealmList list) { + _realmLib.invokeGetBool(() => _realmLib.realm_list_remove_all(list.handle._pointer)); + } + + void resultsDeleteAll(RealmResults results) { + _realmLib.invokeGetBool(() => _realmLib.realm_results_delete_all(results.handle._pointer)); + } + void listClear(RealmList list) { _realmLib.invokeGetBool(() => _realmLib.realm_list_clear(list.handle._pointer)); } - } class LastError { diff --git a/lib/src/realm_class.dart b/lib/src/realm_class.dart index 8eb30922a..d971ccf3c 100644 --- a/lib/src/realm_class.dart +++ b/lib/src/realm_class.dart @@ -83,6 +83,29 @@ class Realm { return object; } + /// Delete given [RealmObject] from Realm database. + /// Throws [RealmException] on error. + void delete(T object) { + try { + realmCore.deleteRealmObject(object); + } catch (e) { + throw RealmException("Error deleting object from databse. Error: $e"); + } + } + + /// Deletes [RealmObject] items in given collection from Realm database. + void deleteMany(Iterable items) { + if (items is RealmResults) { + realmCore.resultsDeleteAll(items); + } else if (items is RealmList) { + realmCore.listDeleteAll(items); + } else { + for (T realmObject in items) { + realmCore.deleteRealmObject(realmObject); + } + } + } + void addAll(Iterable items) { for (final i in items) { add(i); @@ -90,7 +113,7 @@ class Realm { } void remove(T object) { - realmCore.removeRealmObject(object); + realmCore.deleteRealmObject(object); } bool get _isInTransaction => realmCore.getIsWritable(this); diff --git a/lib/src/results.dart b/lib/src/results.dart index 2da3e3d72..f0e0e3637 100644 --- a/lib/src/results.dart +++ b/lib/src/results.dart @@ -91,7 +91,7 @@ class _ResultsList extends collection.ListBase { /// Instances of this class are typically live collections returned by [Realm.objects] /// that will update as new objects are either added to or deleted from the Realm /// that match the underlying query. -class RealmResults { +class RealmResults extends collection.IterableBase { late final RealmResultsHandle _handle; late final Realm _realm; // RealmResults _results; @@ -143,9 +143,11 @@ class RealmResults { // } /// Returns `true` if the Results collection is empty - bool isEmpty() { - return length == 0; - } + @override + bool get isEmpty => length == 0; + + @override + Iterator get iterator => _RealmResultsIterator(this); /// Returns `true` if this Results collection has not been deleted and is part of a valid Realm. /// @@ -153,6 +155,7 @@ class RealmResults { // bool get isValid => _results.isValid(); /// Returns the number of values in the Results collection. + @override int get length => realmCore.getResultsCount(this); /// Returns a human-readable description of the objects contained in the collection. @@ -208,3 +211,29 @@ extension RealmResultsInternal on RealmResults { return RealmResults._(handle, realm); } } + +class _RealmResultsIterator implements Iterator { + final RealmResults _results; + int _index; + T? _current; + + _RealmResultsIterator(RealmResults results) + : _results = results, + _index = -1; + + @override + T get current => _current as T; + + @override + bool moveNext() { + int length = _results.length; + _index++; + if (_index >= length) { + _current = null; + return false; + } + _current = _results[_index]; + + return true; + } +} diff --git a/test/realm_test.dart b/test/realm_test.dart index c9f1a171a..6d075d11a 100644 --- a/test/realm_test.dart +++ b/test/realm_test.dart @@ -439,7 +439,7 @@ Future main([List? args]) async { expect(car, isNull); }); - test('Realm remove object', () { + test('Realm delete object', () { var config = Configuration([Car.schema]); var realm = Realm(config); @@ -449,7 +449,7 @@ Future main([List? args]) async { final car1 = realm.find("SomeNewNonExistingValue"); expect(car1, isNotNull); - realm.write(() => realm.remove(car1!)); + realm.write(() => realm.delete(car1!)); var car2 = realm.find("SomeNewNonExistingValue"); expect(car2, isNull); @@ -475,7 +475,7 @@ Future main([List? args]) async { expect(cars.length, 1); - realm.write(() => realm.remove(car)); + realm.write(() => realm.delete(car)); expect(cars.length, 0); }); @@ -485,16 +485,16 @@ Future main([List? args]) async { var realm = Realm(config); var cars = realm.all(); - expect(cars.isEmpty(), true); + expect(cars.isEmpty, true); final car = Car(); realm.write(() => realm.add(car)); - expect(cars.isEmpty(), false); + expect(cars.isEmpty, false); - realm.write(() => realm.remove(car)); + realm.write(() => realm.delete(car)); - expect(cars.isEmpty(), true); + expect(cars.isEmpty, true); }); test('Results get by index', () { @@ -694,6 +694,7 @@ Future main([List? args]) async { Person()..name = "Sebastian Vettel", Person()..name = "Kimi Räikkönen", ]; + realm.write(() { team.players.addAll(newPlayers); }); @@ -799,7 +800,7 @@ Future main([List? args]) async { expect(allPlayers.length, 1); }); - test('RealmList clear - exception', () { + test('RealmList clear in closed realm - expected exception', () { var config = Configuration([Team.schema, Person.schema]); var realm = Realm(config); @@ -817,7 +818,7 @@ Future main([List? args]) async { expect(teams[0].players.length, 1); var players = teams[0].players; - + realm.close(); expect( () => realm.write(() { @@ -826,13 +827,190 @@ Future main([List? args]) async { throws()); realm = Realm(config); - + //Teams must be reloaded since realm was reopened teams = realm.all(); - + //Ensure that the team is still related to the player expect(teams.length, 1); expect(teams[0].players.length, 1); }); + + test('Realm.deleteMany from list', () { + var config = Configuration([Team.schema, Person.schema]); + var realm = Realm(config); + + //Create two teams + final teamOne = Team()..name = "Team one"; + final teamTwo = Team()..name = "Team two"; + final teamThree = Team()..name = "Team three"; + realm.write(() { + realm.add(teamOne); + realm.add(teamTwo); + realm.add(teamThree); + }); + + //Ensure the teams exist in realm + var teams = realm.all(); + expect(teams.length, 3); + + //Delete teams one and three from realm + realm.write(() => realm.deleteMany([teamOne, teamThree])); + + //Ensure both teams are deleted and only teamTwo has left + expect(teams.length, 1); + expect(teams[0].name, teamTwo.name); + }); + + test('Realm.deleteMany from realmList', () { + var config = Configuration([Team.schema, Person.schema]); + var realm = Realm(config); + + //Create a team + final team = Team()..name = "Ferrari"; + realm.write(() => realm.add(team)); + + //Add players to the team + final newPlayers = [ + Person()..name = "Michael Schumacher", + Person()..name = "Sebastian Vettel", + Person()..name = "Kimi Räikkönen", + ]; + realm.write(() => team.players.addAll(newPlayers)); + + //Ensure the team exists in realm + var teams = realm.all(); + expect(teams.length, 1); + + //Delete team players + realm.write(() => realm.deleteMany(teams[0].players)); + + //Ensure players are deleted from collection + expect(teams[0].players.length, 0); + + //Reload all persons from realm and ensure they are deleted + final allPersons = realm.all(); + expect(allPersons.length, 0); + }); + + test('Realm.deleteMany from realmList referenced by two objects', () { + var config = Configuration([Team.schema, Person.schema]); + var realm = Realm(config); + + //Create two teams + final teamOne = Team()..name = "Ferrari"; + final teamTwo = Team()..name = "Maserati"; + realm.write(() { + realm.add(teamOne); + realm.add(teamTwo); + }); + + //Create common players list for both teams + final newPlayers = [ + Person()..name = "Michael Schumacher", + Person()..name = "Sebastian Vettel", + Person()..name = "Kimi Räikkönen", + ]; + realm.write(() { + teamOne.players.addAll(newPlayers); + teamTwo.players.addAll(newPlayers); + }); + + //Ensule teams exist in realm + var teams = realm.all(); + expect(teams.length, 2); + + //Delete all players in a team from realm + realm.write(() => realm.deleteMany(teams[0].players)); + + //Ensure all players are deleted from collection + expect(teams[0].players.length, 0); + + //Reload all persons from realm and ensure they are deleted + final allPersons = realm.all(); + expect(allPersons.length, 0); + }); + + test('Realm.deleteMany from RealmResults', () { + var config = Configuration([Team.schema, Person.schema]); + var realm = Realm(config); + + //Create two teams + realm.write(() { + realm.add(Team()..name = "Ferrari"); + realm.add(Team()..name = "Maserati"); + }); + + //Ensule teams exist in realm + var teams = realm.all(); + expect(teams.length, 2); + + //Delete all objects in realmResults from realm + realm.write(() => realm.deleteMany(teams)); + expect(teams.length, 0); + + //Reload teams from realm and ensure they are deleted + teams = realm.all(); + expect(teams.length, 0); + }); + + test('Realm.deleteMany from realmList after realm is closed', () { + var config = Configuration([Team.schema, Person.schema]); + var realm = Realm(config); + + //Create a team + final team = Team()..name = "Ferrari"; + realm.write(() => realm.add(team)); + + //Add players to the team + final newPlayers = [ + Person()..name = "Michael Schumacher", + Person()..name = "Sebastian Vettel", + Person()..name = "Kimi Räikkönen", + ]; + realm.write(() => team.players.addAll(newPlayers)); + + //Ensure team exists in realm + var teams = realm.all(); + expect(teams.length, 1); + + //Try to delete team players while realm is closed + final players = teams[0].players; + realm.close(); + expect( + () => realm.write(() { + realm.deleteMany(players); + }), + throws()); + + //Ensure all persons still exists in realm + realm = Realm(config); + final allPersons = realm.all(); + expect(allPersons.length, 3); + }); + + test('RealmResults iteration test', () { + var config = Configuration([Team.schema, Person.schema]); + var realm = Realm(config); + + //Create two teams + realm.write(() { + realm.add(Team()..name = "team One"); + realm.add(Team()..name = "team Two"); + }); + + //Reload teams from realm and ensure they exist + var teams = realm.all(); + expect(teams.length, 2); + + //Iterate through teams and add realm objects to a list + List list = []; + for (Team team in teams) { + list.add(team); + } + + //Ensure list size is the same like teams collection size + expect(list.length, teams.length); + }); }); }