Skip to content

Commit

Permalink
Support backlinks
Browse files Browse the repository at this point in the history
  • Loading branch information
nielsenko committed Oct 27, 2022
1 parent 74994ef commit 50889d4
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 26 deletions.
21 changes: 15 additions & 6 deletions lib/src/native/realm_core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import 'dart:io';
import 'dart:typed_data';

import 'package:cancellation_token/cancellation_token.dart';
import 'package:collection/collection.dart';
// Hide StringUtf8Pointer.toNativeUtf8 and StringUtf16Pointer since these allows silently allocating memory. Use toUtf8Ptr instead
import 'package:ffi/ffi.dart' hide StringUtf8Pointer, StringUtf16Pointer;
import 'package:logging/logging.dart';
Expand Down Expand Up @@ -120,15 +121,17 @@ class _RealmCore {
for (var i = 0; i < classCount; i++) {
final schemaObject = schema.elementAt(i);
final classInfo = schemaClasses.elementAt(i).ref;
final propertiesCount = schemaObject.properties.length;
final computedCount = schemaObject.properties.where((p) => p.isComputed).length;
final persistedCount = propertiesCount - computedCount;

classInfo.name = schemaObject.name.toCharPtr(arena);
classInfo.primary_key = "".toCharPtr(arena);
classInfo.num_properties = schemaObject.properties.length;
classInfo.num_computed_properties = 0;
classInfo.num_properties = persistedCount;
classInfo.num_computed_properties = computedCount;
classInfo.key = RLM_INVALID_CLASS_KEY;
classInfo.flags = schemaObject.baseType.flags;

final propertiesCount = schemaObject.properties.length;
final properties = arena<realm_property_info_t>(propertiesCount);

for (var j = 0; j < propertiesCount; j++) {
Expand All @@ -138,7 +141,7 @@ class _RealmCore {
//TODO: Assign the correct public name value https://github.com/realm/realm-dart/issues/697
propInfo.public_name = "".toCharPtr(arena);
propInfo.link_target = (schemaProperty.linkTarget ?? "").toCharPtr(arena);
propInfo.link_origin_property_name = "".toCharPtr(arena);
propInfo.link_origin_property_name = (schemaProperty.linkOriginProperty ?? "").toCharPtr(arena);
propInfo.type = schemaProperty.propertyType.index;
propInfo.collection_type = schemaProperty.collectionType.index;
propInfo.flags = realm_property_flags.RLM_PROPERTY_NORMAL;
Expand Down Expand Up @@ -695,10 +698,11 @@ class _RealmCore {
final property = propertiesPtr.elementAt(i);
final propertyName = property.ref.name.cast<Utf8>().toRealmDartString()!;
final objectType = property.ref.link_target.cast<Utf8>().toRealmDartString(treatEmptyAsNull: true);
final linkOriginProperty = property.ref.link_origin_property_name.cast<Utf8>().toRealmDartString(treatEmptyAsNull: true);
final isNullable = property.ref.flags & realm_property_flags.RLM_PROPERTY_NULLABLE != 0;
final isPrimaryKey = propertyName == primaryKeyName;
final propertyMeta = RealmPropertyMetadata(property.ref.key, objectType, RealmPropertyType.values.elementAt(property.ref.type), isNullable,
isPrimaryKey, RealmCollectionType.values.elementAt(property.ref.collection_type));
final propertyMeta = RealmPropertyMetadata(property.ref.key, objectType, linkOriginProperty, RealmPropertyType.values.elementAt(property.ref.type),
isNullable, isPrimaryKey, RealmCollectionType.values.elementAt(property.ref.collection_type));
result[propertyName] = propertyMeta;
}
return result;
Expand Down Expand Up @@ -967,6 +971,11 @@ class _RealmCore {
return RealmListHandle._(pointer, object.realm.handle);
}

RealmResultsHandle getBacklinks(RealmObjectBase object, int sourceTableKey, int propertyKey) {
final pointer = _realmLib.invokeGetPointer(() => _realmLib.realm_get_backlinks(object.handle._pointer, sourceTableKey, propertyKey));
return RealmResultsHandle._(pointer, object.realm.handle);
}

int getListSize(RealmListHandle handle) {
return using((Arena arena) {
final size = arena<Size>();
Expand Down
45 changes: 27 additions & 18 deletions lib/src/realm_object.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ import 'dart:ffi';

import 'package:collection/collection.dart';

import 'configuration.dart';
import 'list.dart';
import 'native/realm_core.dart';
import 'realm_class.dart';
import 'configuration.dart';
import 'results.dart';

typedef DartDynamic = dynamic;

Expand Down Expand Up @@ -126,8 +127,9 @@ class RealmPropertyMetadata {
final RealmPropertyType propertyType;
final bool isNullable;
final String? objectType;
final String? linkOriginProperty;
final bool isPrimaryKey;
const RealmPropertyMetadata(this.key, this.objectType, this.propertyType, this.isNullable, this.isPrimaryKey,
const RealmPropertyMetadata(this.key, this.objectType, this.linkOriginProperty, this.propertyType, this.isNullable, this.isPrimaryKey,
[this.collectionType = RealmCollectionType.none]);
}

Expand All @@ -142,24 +144,31 @@ class RealmCoreAccessor implements RealmAccessor {
try {
final propertyMeta = metadata[name];
if (propertyMeta.collectionType == RealmCollectionType.list) {
final handle = realmCore.getListProperty(object, propertyMeta.key);
final listMetadata = propertyMeta.objectType == null ? null : object.realm.metadata.getByName(propertyMeta.objectType!);

// listMetadata is not null when we have list of RealmObjects. If the API was
// called with a generic object arg - get<Object> we construct a list of
// RealmObjects since we don't know the type of the object.
if (listMetadata != null && _isTypeGenericObject<T>()) {
switch (listMetadata.schema.baseType) {
case ObjectType.realmObject:
return object.realm.createList<RealmObject>(handle, listMetadata);
case ObjectType.embeddedObject:
return object.realm.createList<EmbeddedObject>(handle, listMetadata);
default:
throw RealmError('List of ${listMetadata.schema.baseType} is not supported yet');
if (propertyMeta.propertyType == RealmPropertyType.linkingObjects) {
final sourceMeta = object.realm.metadata.getByName(propertyMeta.objectType!);
final sourceProperty = sourceMeta[propertyMeta.linkOriginProperty!];
final handle = realmCore.getBacklinks(object, sourceMeta.classKey, sourceProperty.key);
return RealmResultsInternal.create<T>(handle, object.realm, metadata);
} else {
final handle = realmCore.getListProperty(object, propertyMeta.key);
final listMetadata = propertyMeta.objectType == null ? null : object.realm.metadata.getByName(propertyMeta.objectType!);

// listMetadata is not null when we have list of RealmObjects. If the API was
// called with a generic object arg - get<Object> we construct a list of
// RealmObjects since we don't know the type of the object.
if (listMetadata != null && _isTypeGenericObject<T>()) {
switch (listMetadata.schema.baseType) {
case ObjectType.realmObject:
return object.realm.createList<RealmObject>(handle, listMetadata);
case ObjectType.embeddedObject:
return object.realm.createList<EmbeddedObject>(handle, listMetadata);
default:
throw RealmError('List of ${listMetadata.schema.baseType} is not supported yet');
}
}
}

return object.realm.createList<T>(handle, listMetadata);
return object.realm.createList<T>(handle, listMetadata);
}
}

Object? value = realmCore.getProperty(object, propertyMeta.key);
Expand Down
17 changes: 15 additions & 2 deletions lib/src/realm_property.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ class SchemaProperty {

final String? linkTarget;

final String? linkOriginProperty;

/// Defines the `Realm` collection type if this property is a collection
final RealmCollectionType collectionType;

Expand All @@ -35,13 +37,24 @@ class SchemaProperty {
/// The `Realm` type of the property
final RealmPropertyType propertyType;

/// `true` if the property is computed
bool get isComputed => propertyType == RealmPropertyType.linkingObjects;

/// `true` if the property is optional
final bool optional;

/// Indicates that the property should be persisted under a different name
final String? mapTo;

/// @nodoc
const SchemaProperty(this.name, this.propertyType,
{this.optional = false, this.mapTo, this.primaryKey = false, this.linkTarget, this.collectionType = RealmCollectionType.none});
const SchemaProperty(
this.name,
this.propertyType, {
this.optional = false,
this.mapTo,
this.primaryKey = false,
this.linkTarget,
this.linkOriginProperty,
this.collectionType = RealmCollectionType.none,
});
}

0 comments on commit 50889d4

Please sign in to comment.