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 31 : BelongsTo([E? model]) : super(model != null ? {model} : null); 27 : 28 16 : BelongsTo._(Set<String>? keys) : super._(keys); 29 : 30 4 : BelongsTo.remove() : super._remove(); 31 : 32 : /// For internal use with `json_serializable`. 33 8 : factory BelongsTo.fromJson(final Map<String, dynamic> map) { 34 16 : if (map['_'] == null) return BelongsTo._(null); 35 8 : return BelongsTo._({...map['_']}); 36 : } 37 : 38 : /// Obtains the single [E] value of this relationship (`null` if not present). 39 28 : E? get value => _iterable.isNotEmpty ? _iterable.first : null; 40 : 41 : /// Sets the single [E] value of this relationship, replacing any previous [value]. 42 : /// 43 : /// Passing in `null` will remove the existing value from the relationship. 44 4 : set value(E? newValue) { 45 4 : final isAddition = value == null && newValue != null; 46 4 : final isUpdate = value != null && newValue != null; 47 4 : final isRemoval = value != null && newValue == null; 48 : 49 : if (isRemoval || isUpdate) { 50 4 : super._remove(value!, notify: false); 51 : } 52 : if (isAddition || isUpdate) { 53 3 : super._add(newValue!, notify: false); 54 : } 55 : 56 : // handle events 57 : DataGraphEventType? eventType; 58 : if (isAddition) eventType = DataGraphEventType.addEdge; 59 : if (isUpdate) eventType = DataGraphEventType.updateEdge; 60 : if (isRemoval) eventType = DataGraphEventType.removeEdge; 61 : 62 : if (eventType != null) { 63 6 : _graph._notify( 64 12 : [_ownerKey!, if (newValue != null) newValue._key!], 65 3 : metadata: _name, 66 : type: eventType, 67 : ); 68 : } 69 12 : assert(_iterable.length <= 1); 70 : } 71 : 72 : /// Returns the [value]'s `key`. 73 30 : String? get key => super._keys.safeFirst; 74 : 75 : /// Returns the [value]'s `id`. 76 3 : Object? get id => super._ids.safeFirst; 77 : 78 : /// Returns a [StateNotifier] which emits the latest [value] of 79 : /// this [BelongsTo] relationship. 80 1 : @override 81 : DelayedStateNotifier<E?> watch() { 82 3 : return _relationshipEventNotifier.map((e) { 83 1 : return [DataGraphEventType.removeNode, DataGraphEventType.removeEdge] 84 2 : .contains(e.type) 85 : ? null 86 1 : : value; 87 : }); 88 : } 89 : 90 3 : @override 91 : String toString() { 92 6 : return 'BelongsTo<$E>(${super.toString()})'; 93 : } 94 : } 95 : 96 : extension DataModelRelationshipExtension<T extends DataModel<T>> 97 : on DataModel<T> { 98 : /// Converts a [DataModel<T>] into a [BelongsTo<T>]. 99 : /// 100 : /// Equivalent to using the constructor as `BelongsTo(model)`. 101 18 : BelongsTo<T> get asBelongsTo => BelongsTo<T>(this as T); 102 : }