Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Try to include the transitive closure of schemas when creating config #1424

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions example/bin/myapp.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions flutter/realm_flutter/example/lib/main.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 10 additions & 10 deletions generator/lib/src/realm_model_info.dart
Original file line number Diff line number Diff line change
Expand Up @@ -114,19 +114,23 @@ class RealmModelInfo {
yield 'static SchemaObject _initSchema() {';
{
yield 'RealmObjectBase.registerFactory($name._);';
yield "return const SchemaObject(ObjectType.${baseType.name}, $name, '$realmName', [";
yield "return SchemaObject(ObjectType.${baseType.name}, $name, '$realmName', [";
{
yield* fields.map((f) {
final namedArgs = {
if (f.name != f.realmName) 'mapTo': f.realmName,
if (f.name != f.realmName) 'mapTo': "'${f.realmName}'",
if (f.optional) 'optional': f.optional,
if (f.isPrimaryKey) 'primaryKey': f.isPrimaryKey,
if (f.indexType != null) 'indexType': f.indexType,
if (f.realmType == RealmPropertyType.object) 'linkTarget': f.basicRealmTypeName,
if (f.realmType == RealmPropertyType.object) ...{
'linkTarget': "'${f.basicRealmTypeName}'",
'linkTargetSchema': '() => ${f.fieldElement.modelType.asNonNullable.basicMappedName}.schema',
},
if (f.realmType == RealmPropertyType.linkingObjects) ...{
'linkOriginProperty': f.linkOriginProperty!,
'linkOriginProperty': "'${f.linkOriginProperty!}'",
'collectionType': RealmCollectionType.list,
'linkTarget': f.basicRealmTypeName,
'linkTarget': "'${f.basicRealmTypeName}'",
'linkTargetSchema': '() => ${f.fieldElement.modelType.asNonNullable.basicMappedName}.schema',
},
if (f.realmCollectionType != RealmCollectionType.none) 'collectionType': f.realmCollectionType,
};
Expand All @@ -145,11 +149,7 @@ extension<K, V> on Map<K, V> {
String toArgsString() {
return () sync* {
for (final e in entries) {
if (e.value is String) {
yield "${e.key}: '${e.value}'";
} else {
yield '${e.key}: ${e.value}';
}
yield '${e.key}: ${e.value}';
}
}()
.join(',');
Expand Down
48 changes: 37 additions & 11 deletions lib/src/configuration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
////////////////////////////////////////////////////////////////////////////////

import 'dart:async';
import 'dart:collection';
import 'dart:ffi';
import 'dart:io';

Expand Down Expand Up @@ -109,16 +110,35 @@ abstract class Configuration implements Finalizable {
static String defaultRealmPath = _path.join(defaultStoragePath, 'default.realm');

Configuration._(
this.schemaObjects, {
Iterable<SchemaObject> schemaObjects, {
String? path,
this.fifoFilesFallbackPath,
this.encryptionKey,
this.maxNumberOfActiveVersions,
}) {
}) : schemaObjects = _getRelatedSchemas(schemaObjects) {
_validateEncryptionKey(encryptionKey);
this.path = path ?? _path.join(_path.dirname(_defaultPath), _path.basename(defaultRealmName));
}

static HashSet<SchemaObject> _getRelatedSchemas(Iterable<SchemaObject> objects) {
final result = HashSet<SchemaObject>();

void addItemAndChildren(SchemaObject obj) {
if (result.add(obj)) {
final linkSchemas = obj.properties.map((e) => e.linkTargetSchema).where((e) => e != null).map((e) => e!);
for (final linkSchema in linkSchemas) {
addItemAndChildren(linkSchema());
}
}
}

for (final obj in objects) {
addItemAndChildren(obj);
}

return result;
}

// allow inheritors to override the _defaultPath value
String get _defaultPath => Configuration.defaultRealmPath;

Expand Down Expand Up @@ -254,7 +274,7 @@ abstract class Configuration implements Finalizable {
/// {@category Configuration}
class LocalConfiguration extends Configuration {
LocalConfiguration._(
super.schemaObjects, {
Iterable<SchemaObject> schemaObjects, {
this.initialDataCallback,
this.schemaVersion = 0,
super.fifoFilesFallbackPath,
Expand All @@ -266,7 +286,7 @@ class LocalConfiguration extends Configuration {
this.migrationCallback,
super.maxNumberOfActiveVersions,
this.shouldDeleteIfMigrationNeeded = false,
}) : super._();
}) : super._(schemaObjects);

/// The schema version used to open the `Realm`. If omitted, the default value is `0`.
///
Expand Down Expand Up @@ -356,15 +376,15 @@ class FlexibleSyncConfiguration extends Configuration {

FlexibleSyncConfiguration._(
this.user,
super.schemaObjects, {
Iterable<SchemaObject> schemaObjects, {
super.fifoFilesFallbackPath,
super.path,
super.encryptionKey,
this.syncErrorHandler = defaultSyncErrorHandler,
this.clientResetHandler = const RecoverOrDiscardUnsyncedChangesHandler(onManualResetFallback: _defaultClientResetHandler),
super.maxNumberOfActiveVersions,
this.shouldCompactCallback,
}) : super._();
}) : super._(schemaObjects);

@override
String get _defaultPath => realmCore.getPathForUser(user);
Expand All @@ -387,12 +407,12 @@ extension FlexibleSyncConfigurationInternal on FlexibleSyncConfiguration {
/// {@category Configuration}
class DisconnectedSyncConfiguration extends Configuration {
DisconnectedSyncConfiguration._(
super.schemaObjects, {
Iterable<SchemaObject> schemaObjects, {
required super.path,
super.fifoFilesFallbackPath,
super.encryptionKey,
super.maxNumberOfActiveVersions,
}) : super._();
}) : super._(schemaObjects);

@override
String get _defaultPath => _path.dirname(path);
Expand All @@ -403,11 +423,11 @@ class DisconnectedSyncConfiguration extends Configuration {
/// {@category Configuration}
class InMemoryConfiguration extends Configuration {
InMemoryConfiguration._(
super.schemaObjects, {
Iterable<SchemaObject> schemaObjects, {
super.fifoFilesFallbackPath,
super.path,
super.maxNumberOfActiveVersions,
}) : super._();
}) : super._(schemaObjects);
}

/// A collection of properties describing the underlying schema of a [RealmObjectBase].
Expand All @@ -428,6 +448,12 @@ class SchemaObject {

/// Creates schema instance with object type and collection of object's properties.
const SchemaObject(this.baseType, this.type, this.name, this.properties);

@override
bool operator ==(Object other) => other is SchemaObject && other.type == type;

@override
int get hashCode => type.hashCode;
}

/// Describes the complete set of classes which may be stored in a `Realm`
Expand Down Expand Up @@ -455,7 +481,7 @@ class RealmSchema extends Iterable<SchemaObject> {

/// @nodoc
extension SchemaObjectInternal on SchemaObject {
bool get isGenericRealmObject => type == RealmObject || type == EmbeddedObject || type == RealmObjectBase;
bool get isGenericRealmObject => type == RealmObject || type == EmbeddedObject || type == RealmObjectBase || type == AsymmetricObject;
}

/// [ClientResetHandler] is triggered if the device and server cannot agree
Expand Down
3 changes: 3 additions & 0 deletions lib/src/realm_property.dart
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ class SchemaProperty {
/// Indicates that the property should be persisted under a different name
String get mapTo => _mapTo ?? name;

final SchemaObject Function()? linkTargetSchema;

/// @nodoc
const SchemaProperty(
this.name,
Expand All @@ -66,5 +68,6 @@ class SchemaProperty {
this.linkTarget,
this.linkOriginProperty,
this.collectionType = RealmCollectionType.none,
this.linkTargetSchema,
}) : _mapTo = mapTo;
}
19 changes: 13 additions & 6 deletions test/backlinks_test.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions test/configuration_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ import '../lib/realm.dart';
import 'test.dart';
import '../flavor_helpers.dart';

part 'configuration_test.g.dart';

@RealmModel()
class _LinkToClassInAnotherFile {
late List<$RemappedClass> listProperty;
}

Future<void> main([List<String>? args]) async {
await setupTests(args);

Expand Down Expand Up @@ -637,4 +644,14 @@ Future<void> main([List<String>? args]) async {
realm.write(() => realm.add(Dog("Foxi2")));
expect(() => realm.write(() {}), throws<RealmException>("Number of active versions (3) in the Realm exceeded the limit of 2"));
});

test('Configuration.local pulls transitive closure of schema', () {
final config = Configuration.local([Team.schema, LinkToClassInAnotherFile.schema]);

expect(config.schemaObjects.length, 4);
expect(config.schemaObjects, contains(Team.schema));
expect(config.schemaObjects, contains(Person.schema));
expect(config.schemaObjects, contains(LinkToClassInAnotherFile.schema));
expect(config.schemaObjects, contains(RemappedClass.schema));
});
}
49 changes: 49 additions & 0 deletions test/configuration_test.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading