Skip to content

Commit

Permalink
Merge fcf91a6 into c7b0758
Browse files Browse the repository at this point in the history
  • Loading branch information
desistefanova committed Feb 14, 2022
2 parents c7b0758 + fcf91a6 commit fe895f9
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 6 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ vNext

### Changes
* Primary key annotation no longer requires field to be final.
* `RealmObject.IsValid` can be called to check if a managed object has been deleted and its Realm isn't closed. If RealmObject is no longer valid accessing its properties will throw an exception. ([#183](https://github.com/realm/realm-dart/pull/183))
* `RealmList.IsValid` can be called to check whether the Realm instance hasn't been closed, whether it represents a to-many relationship and it's parent object hasn't been deleted. ([#183](https://github.com/realm/realm-dart/pull/183))

### Enhancements
* Support query on lists of realm objects
Expand Down
2 changes: 1 addition & 1 deletion lib/src/cli/install/install_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ class InstallCommand extends Command<void> {
Future<String> getRealmPackagePath() async {
final packageConfig = await findPackageConfig(Directory.current);
if (packageConfig == null) {
throw Exception("Package configuration not found. "
throw Exception("Package configuration ('package_config.json' or '.packages') not found. "
"Run the 'dart run $packageName install` command from the root directory of your application");
}

Expand Down
9 changes: 8 additions & 1 deletion lib/src/list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ class RealmList<T extends Object> extends collection.ListBase<T> {
void clear() {
realmCore.listClear(this);
}

/// Gets a value indicating whether this collection is still valid to use.
///
/// Indicates whether the [Realm] instance hasn't been closed,
/// if it represents a to-many relationship
/// and it's parent object hasn't been deleted.
bool get isValid => realmCore.listIsValid(this);
}

// The query operations on lists only work for list of objects (core restriction),
Expand All @@ -90,7 +97,7 @@ extension RealmListOfObject<T extends RealmObject> on RealmList<T> {
/// Filters the list and returns a new [RealmResults] according to the provided query.
///
/// Only works for lists of Realm objects.
///
///
/// @param query The query used to filter the list
/// @param args Optional parameters for substitution in the query
///
Expand Down
8 changes: 8 additions & 0 deletions lib/src/native/realm_core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,14 @@ class _RealmCore {
bool equals(RealmObject first, RealmObject second) {
return _realmLib.realm_equals(first.handle._pointer.cast(), second.handle._pointer.cast());
}

bool objectIsValid(RealmObject object) {
return _realmLib.realm_object_is_valid(object.handle._pointer);
}

bool listIsValid(RealmList list) {
return _realmLib.realm_list_is_valid(list.handle._pointer);
}
}

class LastError {
Expand Down
12 changes: 10 additions & 2 deletions lib/src/realm_object.dart
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,9 @@ class RealmCoreAccessor implements RealmAccessor {
/// An object that is persisted in `Realm`.
///
/// `RealmObjects` are generated from Realm data model classes marked with `@RealmModel` annotation and named with an underscore.
///
///
/// A data model class `_MyClass` will have a `RealmObject` generated with name `MyClass`.
///
///
/// [RealmObject] should not be used directly as it is part of the generated class hierarchy. ex: `MyClass extends _MyClass with RealmObject`.
/// {@category Realm}
class RealmObject {
Expand Down Expand Up @@ -224,6 +224,14 @@ class RealmObject {
if (!isManaged || !other.isManaged) return false;
return realmCore.equals(this, other);
}

/// Gets a value indicating whether this object is managed and represents a row in the database.
///
/// If a managed object has been removed from the [Realm], it is no longer valid and accessing properties on it
/// will throw an exception.
/// The Object is not valid if its [Realm] is closed or object is deleted.
/// Unmanaged objects are always considered valid.
bool get isValid => isManaged ? realmCore.objectIsValid(this) : true;
}

/// @nodoc
Expand Down
154 changes: 152 additions & 2 deletions test/realm_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,7 @@ Future<void> main([List<String>? args]) async {
final result = (team.players as RealmList<Person>).query(r'name BEGINSWITH $0', ['K']);

expect(result, [person]);
realm.close();
});

test('Sort result', () {
Expand Down Expand Up @@ -1345,8 +1346,157 @@ Future<void> main([List<String>? args]) async {
expect(read, [person]);
realm.close();
});
});
group('Cycle referenced objects tests:', () {

test('RealmObject isValid', () {
var config = Configuration([Team.schema, Person.schema]);
var realm = Realm(config);

var team = Team("team one");
expect(team.isValid, true);
realm.write(() {
realm.add(team);
});
expect(team.isValid, true);
realm.close();
expect(team.isValid, false);
});

test('List isValid', () {
var config = Configuration([Team.schema, Person.schema]);
var realm = Realm(config);

realm.write(() {
realm.add(Team("Speed Team", players: [
Person("Michael Schumacher"),
Person("Sebastian Vettel"),
Person("Kimi Räikkönen"),
]));
});

var teams = realm.all<Team>();

expect(teams, isNotNull);
expect(teams.length, 1);
final players = teams[0].players as RealmList<Person>;
expect(players.isValid, true);
realm.close();
expect(players.isValid, false);
});

test('Access results after realm closed', () {
var config = Configuration([Team.schema, Person.schema]);
var realm = Realm(config);

var team = Team("TeamOne");
realm.write(() => realm.add(team));
var teams = realm.all<Team>();
realm.close();
expect(() => teams[0], throws<RealmException>("Access to invalidated Results objects"));
});

test('Access deleted object', () {
var config = Configuration([Team.schema, Person.schema]);
var realm = Realm(config);

var team = Team("TeamOne");
realm.write(() => realm.add(team));
var teams = realm.all<Team>();
var teamBeforeDelete = teams[0];
realm.write(() => realm.delete(team));
expect(team.isValid, false);
expect(teamBeforeDelete.isValid, false);
expect(team, teamBeforeDelete);
expect(() => team.name, throws<RealmException>("Accessing object of type Team which has been invalidated or deleted"));
expect(() => teamBeforeDelete.name, throws<RealmException>("Accessing object of type Team which has been invalidated or deleted"));
realm.close();
});

test('Access deleted object collection', () {
var config = Configuration([Team.schema, Person.schema]);
var realm = Realm(config);

var team = Team("TeamOne");
realm.write(() => realm.add(team));
var teams = realm.all<Team>();
realm.write(() => realm.delete(team));
expect(() => team.players, throws<RealmException>("Accessing object of type Team which has been invalidated or deleted"));
realm.close();
});

test('Delete collection of deleted parent', () {
var config = Configuration([Team.schema, Person.schema]);
var realm = Realm(config);

var team = Team("TeamOne");
realm.write(() => realm.add(team));
var players = team.players;
realm.write(() => realm.delete(team));
expect(() => realm.write(() => realm.deleteMany(players)), throws<RealmException>("Access to invalidated Collection object"));
realm.close();
});

test('Add object after realm is closed', () {
var config = Configuration([Car.schema]);
var realm = Realm(config);

final car = Car('Tesla');

realm.close();
expect(() => realm.write(() => realm.add(car)), throws<RealmException>("Cannot access realm that has been closed"));
});

test('Edit object after realm is closed', () {
var config = Configuration([Person.schema]);
var realm = Realm(config);

final person = Person('Markos');

realm.write(() => realm.add(person));
realm.close();
expect(() => realm.write(() => person.name = "Markos Sanches"), throws<RealmException>("Cannot access realm that has been closed"));
});

test('Edit deleted object', () {
var config = Configuration([Person.schema]);
var realm = Realm(config);

final person = Person('Markos');

realm.write(() {
realm.add(person);
realm.delete(person);
});
expect(() => realm.write(() => person.name = "Markos Sanches"),
throws<RealmException>("Accessing object of type Person which has been invalidated or deleted"));
realm.close();
});

test('Get query results length after realm is clodes', () {
var config = Configuration([Team.schema, Person.schema]);
var realm = Realm(config);

var team = Team("TeamOne");
realm.write(() => realm.add(team));
final teams = realm.query<Team>('name BEGINSWITH "Team"');
realm.close();
expect(() => teams.length, throws<RealmException>("Access to invalidated Results objects"));
});

test('Get list length after deleting parent objects', () {
var config = Configuration([Team.schema, Person.schema]);
var realm = Realm(config);

var team = Team("TeamOne")..players.add(Person("Nikos"));
realm.write(() {
realm.add(team);
realm.delete(team);
});
expect(() => team.players.length, throws<RealmException>("Accessing object of type Team which has been invalidated or deleted"));

realm.close();
});


test('Realm adding objects graph', () {
var studentMichele = Student(1)
..name = "Michele Ernesto"
Expand Down

0 comments on commit fe895f9

Please sign in to comment.