diff --git a/generator/integration-tests/basics/1.dart b/generator/integration-tests/basics/1.dart index e3f8d093..c35cf8de 100644 --- a/generator/integration-tests/basics/1.dart +++ b/generator/integration-tests/basics/1.dart @@ -33,6 +33,11 @@ void main() { expect(entity(model, 'D').flags, equals(OBXEntityFlags.SYNC_ENABLED)); expect(entity(jsonModel, 'D').flags, equals(OBXEntityFlags.SYNC_ENABLED)); + + expect(entity(model, 'E').flags, + equals(OBXEntityFlags.SYNC_ENABLED | OBXEntityFlags.SHARED_GLOBAL_IDS)); + expect(entity(jsonModel, 'E').flags, + equals(OBXEntityFlags.SYNC_ENABLED | OBXEntityFlags.SHARED_GLOBAL_IDS)); }); test('types', () { diff --git a/generator/integration-tests/basics/lib/lib.dart b/generator/integration-tests/basics/lib/lib.dart index 64b09186..d612ae6a 100644 --- a/generator/integration-tests/basics/lib/lib.dart +++ b/generator/integration-tests/basics/lib/lib.dart @@ -28,6 +28,15 @@ class D { D(); } +@Entity() +@Sync(sharedGlobalIds: true) +class E { + @Id(assignable: true) + int id = 0; + + E({this.id = 0}); +} + @Entity() class T { int? id; diff --git a/generator/lib/src/entity_resolver.dart b/generator/lib/src/entity_resolver.dart index 8af69d52..f5e3d9f7 100644 --- a/generator/lib/src/entity_resolver.dart +++ b/generator/lib/src/entity_resolver.dart @@ -68,10 +68,13 @@ class EntityResolver extends Builder { null, uidRequest: !entityUid.isNull && entityUid.intValue == 0); - // Sync: check if enabled - if (_syncChecker.hasAnnotationOfExact(classElement)) { + // Sync: check if enabled and options + _syncChecker.runIfMatches(classElement, (annotation) { entity.flags |= OBXEntityFlags.SYNC_ENABLED; - } + if (annotation.getField('sharedGlobalIds')!.toBoolValue()!) { + entity.flags |= OBXEntityFlags.SHARED_GLOBAL_IDS; + } + }); log.info(entity); diff --git a/generator/test/code_builder_test.dart b/generator/test/code_builder_test.dart index a4c02ddf..8bfd7b0e 100644 --- a/generator/test/code_builder_test.dart +++ b/generator/test/code_builder_test.dart @@ -352,6 +352,31 @@ void main() { expect(vectorProperty.hnswParams!.reparationBacklinkProbability, 0.95); expect(vectorProperty.hnswParams!.vectorCacheHintSizeKB, 2097152); }); + + test('Sync annotation with shared global IDs', () async { + final source = r''' + library example; + import 'package:objectbox/objectbox.dart'; + + @Entity() + @Sync(sharedGlobalIds: true) + class Example { + @Id(assignable: true) + int id = 0; + } + '''; + + final testEnv = GeneratorTestEnv(); + await testEnv.run(source); + + // Assert final model created by generator + var entity = testEnv.model.entities[0]; + expect(entity.flags & OBXEntityFlags.SYNC_ENABLED != 0, true); + expect(entity.flags & OBXEntityFlags.SHARED_GLOBAL_IDS != 0, true); + // Only a single property + final idProperty = testEnv.model.entities[0].properties[0]; + expect(idProperty.flags & OBXPropertyFlags.ID_SELF_ASSIGNABLE != 0, true); + }); }); } diff --git a/objectbox/CHANGELOG.md b/objectbox/CHANGELOG.md index 81fda078..3e4cd662 100644 --- a/objectbox/CHANGELOG.md +++ b/objectbox/CHANGELOG.md @@ -1,5 +1,7 @@ ## latest +* Sync: support option to enable [shared global IDs](https://sync.objectbox.io/advanced/object-ids#shared-global-ids). + ## 4.0.1 (2024-05-27) * Export `ObjectWithScore` and `IdWithScore` used by the new find with score `Query` methods. [#637](https://github.com/objectbox/objectbox-dart/issues/637) diff --git a/objectbox/lib/src/native/sync.dart b/objectbox/lib/src/native/sync.dart index c43215fd..e09985aa 100644 --- a/objectbox/lib/src/native/sync.dart +++ b/objectbox/lib/src/native/sync.dart @@ -583,13 +583,33 @@ class _SyncListenerGroup { } } +// Note: because in Dart can't have two classes exported with the same name, +// this class doubles as the annotation class (compare annotations.dart) and +// configuration class for Sync. + /// [ObjectBox Sync](https://objectbox.io/sync/) makes data available and /// synchronized across devices, online and offline. /// /// Start a client using [Sync.client()] and connect to a remote server. class Sync { - /// Create a Sync annotation, enabling synchronization for an entity. - const Sync(); + /// Set to `true` to enable shared global IDs for a Sync-enabled entity class. + /// + /// By default, each Sync client has its own local ID space for Objects. + /// IDs are mapped to global IDs when syncing behind the scenes. + /// Turn this on to treat Object IDs as global and turn of ID mapping. + /// The ID of an Object will then be the same on all clients. + /// + /// When using this, it is recommended to use assignable IDs (`@Id(assignable: true)`) + /// to turn off automatically assigned IDs. Without special care, two Sync + /// clients are likely to overwrite each others Objects if IDs are assigned + /// automatically. + final bool sharedGlobalIds; + + /// Enables sync for an `@Entity` class. + /// + /// Note that currently sync can not be enabled or disabled for existing entities. + /// Also synced entities can not have relations to non-synced entities. + const Sync({this.sharedGlobalIds = false}); static final bool _syncAvailable = C.has_feature(OBXFeature.Sync);