Line data Source code
1 : part of flutter_data; 2 : 3 : /// A [Relationship] that models a to-one ownership. 4 : /// 5 : /// Example: A book that belongs to an author 6 : /// ``` 7 : /// class Book with DataModel<Book> { 8 : /// @override 9 : /// final int id; 10 : /// final String title; 11 : /// final BelongsTo<Author> author; 12 : /// 13 : /// Todo({this.id, this.title, this.author}); 14 : /// } 15 : ///``` 16 : class BelongsTo<E extends DataModel<E>> extends Relationship<E, E?> { 17 : /// Creates a [BelongsTo] relationship, with an optional initial [E] model. 18 : /// 19 : /// Example: 20 : /// ``` 21 : /// final author = Author(name: 'JK Rowling'); 22 : /// final book = Book(id: 1, author: BelongsTo(author)); 23 : /// ``` 24 : /// 25 : /// See also: [DataModelRelationshipExtension<E>.asBelongsTo] 26 3 : BelongsTo([final E? model]) : super(model != null ? {model} : null); 27 : 28 1 : BelongsTo._(String? key, bool _wasOmitted) 29 2 : : super._(key != null ? {key} : {}, _wasOmitted); 30 : 31 2 : BelongsTo.remove() : super._remove(); 32 : 33 : /// For internal use with `json_serializable`. 34 1 : factory BelongsTo.fromJson(final Map<String, dynamic> map) { 35 2 : final key = map['_'][0] as String?; 36 : if (key == null) { 37 2 : final wasOmitted = map['_'][1] as bool; 38 1 : return BelongsTo._(null, wasOmitted); 39 : } 40 1 : return BelongsTo._(key, false); 41 : } 42 : 43 : /// Obtains the single [E] value of this relationship (`null` if not present). 44 2 : E? get value => safeFirst; 45 : 46 : /// Sets the single [E] value of this relationship, replacing any previous [value]. 47 : /// 48 : /// Passing in `null` will remove the existing value from the relationship. 49 1 : set value(E? value) { 50 1 : if (this.value != null || value == null) { 51 2 : super.remove(this.value!); 52 : } 53 : if (value != null) { 54 1 : super.add(value); 55 : } 56 : assert(length <= 1); 57 : } 58 : 59 : /// Returns the [value]'s `key` 60 1 : @protected 61 : @visibleForTesting 62 2 : String? get key => super.keys.safeFirst; 63 : 64 3 : String? get id => super.ids.safeFirst; 65 : 66 : @override 67 1 : Future<Relationship<E, E?>> initialize( 68 : {required final Map<String, RemoteAdapter> adapters, 69 : required final DataModel owner, 70 : required final String name, 71 : final String? inverseName}) async { 72 1 : if (isInitialized && inverseName != null) { 73 1 : addInverse(inverseName, owner); 74 : } 75 1 : return super.initialize( 76 : adapters: adapters, owner: owner, name: name, inverseName: inverseName); 77 : } 78 : 79 : /// Returns a [StateNotifier] which emits the latest [value] of 80 : /// this [BelongsTo] relationship. 81 1 : @override 82 : DelayedStateNotifier<E?> watch() { 83 6 : return _graphEvents.where((e) => e.isNotEmpty).map((e) { 84 1 : return [DataGraphEventType.removeNode, DataGraphEventType.removeEdge] 85 3 : .contains(e.last.type) 86 : ? null 87 1 : : value; 88 : }); 89 : } 90 : 91 1 : void addInverse(String inverseName, DataModel model) { 92 1 : if (value != null) { 93 5 : final _rels = value!.remoteAdapter.localAdapter.relationshipsFor(value!); 94 1 : final inverseMetadata = _rels[inverseName]; 95 : if (inverseMetadata != null) { 96 1 : final inverseRelationship = inverseMetadata['instance'] as Relationship; 97 1 : inverseRelationship.add(model); 98 : } 99 : } 100 : } 101 : 102 1 : @override 103 2 : String toString() => 'BelongsTo<$E>($_prop)'; 104 : } 105 : 106 : extension DataModelRelationshipExtension<T extends DataModel<T>> 107 : on DataModel<T> { 108 : /// Converts a [DataModel<T>] into a [BelongsTo<T>]. 109 : /// 110 : /// Equivalent to using the constructor as `BelongsTo(model)`. 111 2 : BelongsTo<T> get asBelongsTo => BelongsTo<T>(this as T); 112 : }