Skip to content

Commit

Permalink
Refactor add to accept AsymmetricObject as well
Browse files Browse the repository at this point in the history
  • Loading branch information
nielsenko committed Sep 16, 2023
1 parent 1022370 commit cf7e1af
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 31 deletions.
43 changes: 21 additions & 22 deletions lib/src/realm_class.dart
Original file line number Diff line number Diff line change
Expand Up @@ -249,47 +249,46 @@ class Realm implements Finalizable {
}
}

/// Adds a [RealmObject] to the `Realm`.
/// Adds a [RealmObject] or ingest an [AsymmetricObject].
///
/// When adding a [RealmObject] this `Realm` will start managing the object.
///
/// This `Realm` will start managing the [RealmObject].
/// A [RealmObject] instance can be managed only by one `Realm`.
/// If the object is already managed by this `Realm`, this method does nothing.
/// This method modifies the object in-place as it becomes managed. Managed instances are persisted and become live objects.
/// This method modifies the object in-place as it becomes managed. Managed instances
/// are persisted and become live objects.
///
/// Returns the same instance as managed. This is just meant as a convenience to enable fluent syntax scenarios.
///
/// By setting the [update] flag you can update any existing object with the same primary key.
/// Updating only makes sense for objects with primary keys, and is effectively ignored
/// otherwise.
///
/// Throws [RealmException] when trying to add objects with the same primary key.
/// Ingesting a [AsymmetricObject] is a write only operation. The ingested objects
/// synchronizes to the App Services backend and are deleted from the device. An
/// [AsymmetricObject] can never be read from the Realm. The [update] flag is
/// ignored when adding [AsymmetricObject]s (always `false`).
///
/// Throws [RealmException] when trying to add objects with the same primary key,
/// as an already existing object of the same type in the `Realm`.
///
/// Throws [RealmException] if there is no write transaction created with [write].
T add<T extends RealmObject>(T object, {bool update = false}) {
T add<T extends TopLevelObject>(T object, {bool update = false}) {
_add(object, update: object is AsymmetricObject ? false : update);
return object;
}

void _add(TopLevelObject object, {bool update = false}) {
if (object.isManaged) {
_ensureManagedByThis(object, 'add object to Realm');

return object;
return;
}

final metadata = _metadata.getByType(object.runtimeType);
final handle = _createObject(object, metadata, update);

final accessor = RealmCoreAccessor(metadata, _isInMigration);
object.manage(this, handle, accessor, update);

return object;
}

/// Ingest an [AsymmetricObject] to the [Realm].
///
/// Ingesting is a write only operation. The ingested objects synchronizes to
/// the App Services backend and are deleted from the device. An [AsymmetricObject]
/// can never be read from the Realm.
void ingest<T extends AsymmetricObject>(T object) {
final metadata = _metadata.getByType(object.runtimeType);
final handle = _createObject(object, metadata, false);

final accessor = RealmCoreAccessor(metadata, _isInMigration);
object.manage(this, handle, accessor, false);
}

RealmObjectHandle _createObject(RealmObjectBase object, RealmObjectMetadata metadata, bool update) {
Expand Down
9 changes: 6 additions & 3 deletions lib/src/realm_object.dart
Original file line number Diff line number Diff line change
Expand Up @@ -454,10 +454,10 @@ mixin RealmObjectBase on RealmEntity implements RealmObjectBaseMarker, Finalizab
}

/// @nodoc
mixin RealmObject on RealmObjectBase implements RealmObjectMarker {}
sealed class TopLevelObject with RealmEntity, RealmObjectBase {}

/// @nodoc
mixin EmbeddedObject on RealmObjectBase implements EmbeddedObjectMarker {}
mixin RealmObject on RealmObjectBase implements RealmObjectMarker, TopLevelObject {}

/// Base for any object that can be persisted in a [Realm], but cannot be retrieved,
/// hence cannot be modified.
Expand All @@ -468,7 +468,10 @@ mixin EmbeddedObject on RealmObjectBase implements EmbeddedObjectMarker {}
///
/// Use [AsymmetricObject] when you have a write-/only use case. You use it by
/// parsing [ObjectType.asymmetricObject] to the [RealmModel] annotation.
mixin AsymmetricObject on RealmObjectBase implements AsymmetricObjectMarker {}
mixin AsymmetricObject on RealmObjectBase implements AsymmetricObjectMarker, TopLevelObject {}

/// @nodoc
mixin EmbeddedObject on RealmObjectBase implements EmbeddedObjectMarker {}

extension EmbeddedObjectExtension on EmbeddedObject {
/// Retrieve the [parent] object of this embedded object.
Expand Down
12 changes: 6 additions & 6 deletions test/asymmetric_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Future<void> main([List<String>? args]) async {

final oid = ObjectId();
realm.write(() {
realm.ingest(Asymmetric(oid, embeddedObjects: [1, 2, 3].map(Embedded.new)));
realm.add(Asymmetric(oid, embeddedObjects: [1, 2, 3].map(Embedded.new)));
});

// Find & query on an Asymmetric object is compile time error, but you can cheat with dynamic
Expand All @@ -80,14 +80,14 @@ Future<void> main([List<String>? args]) async {

final oid = ObjectId();
realm.write(() {
realm.ingest(Asymmetric(oid, embeddedObjects: [1, 2, 3].map(Embedded.new)));
expect(() => realm.ingest(Asymmetric(oid, embeddedObjects: [1, 2, 3, 4].map(Embedded.new))),
realm.add(Asymmetric(oid, embeddedObjects: [1, 2, 3].map(Embedded.new)));
expect(() => realm.add(Asymmetric(oid, embeddedObjects: [1, 2, 3, 4].map(Embedded.new))),
throws<RealmException>("Attempting to create an object of type 'Asymmetric' with an existing primary key value"));
});

realm.write(() {
// okay to ingest again in another transaction, because object already dead to us
realm.ingest(Asymmetric(oid, embeddedObjects: [1, 2, 3, 5].map(Embedded.new)));
realm.add(Asymmetric(oid, embeddedObjects: [1, 2, 3, 5].map(Embedded.new)));
});

await realm.syncSession.waitForUpload();
Expand All @@ -104,8 +104,8 @@ Future<void> main([List<String>? args]) async {
final s = realm.add(Symmetric(ObjectId()));
// Since this shenanigan is allowed, I have opened a feature request to allow
// direct links on a symmetric objects. See https://github.com/realm/realm-core/issues/6976.
realm.ingest(Asymmetric(ObjectId(), embeddedObjects: [Embedded(1, symmetric: s)]));
realm.ingest(Asymmetric(ObjectId(), embeddedObjects: [Embedded(1, any: RealmValue.from(s))]));
realm.add(Asymmetric(ObjectId(), embeddedObjects: [Embedded(1, symmetric: s)]));
realm.add(Asymmetric(ObjectId(), embeddedObjects: [Embedded(1, any: RealmValue.from(s))]));
});

await realm.syncSession.waitForUpload();
Expand Down

0 comments on commit cf7e1af

Please sign in to comment.