LCOV - code coverage report
Current view: top level - src/model/relationship - relationship.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 82 86 95.3 %
Date: 2020-07-30 22:52:57 Functions: 0 0 -

          Line data    Source code
       1             : part of flutter_data;
       2             : 
       3             : /// A `Set` that models a relationship between one or more [DataModel] objects
       4             : /// and their a [DataModel] owner. Backed by a [GraphNotifier].
       5             : abstract class Relationship<E extends DataModel<E>, N>
       6             :     with SetMixin<E>, _Lifecycle<Relationship<E, N>> {
       7           1 :   @protected
       8             :   Relationship([Set<E> models])
       9             :       : _uninitializedKeys = {},
      10             :         _uninitializedModels = models ?? {},
      11             :         _wasOmitted = models == null;
      12             : 
      13           1 :   Relationship._(Iterable<String> keys, this._wasOmitted)
      14           1 :       : _uninitializedKeys = keys.toSet(),
      15             :         _uninitializedModels = {};
      16             : 
      17             :   String _ownerKey;
      18             :   String _name;
      19             :   String _inverseName;
      20             :   Map<String, RemoteAdapter> _adapters;
      21             :   RemoteAdapter<E> _adapter;
      22           4 :   GraphNotifier get _graph => _adapter?.localAdapter?.graph;
      23             : 
      24             :   final Set<String> _uninitializedKeys;
      25             :   final Set<E> _uninitializedModels;
      26             :   final bool _wasOmitted;
      27             : 
      28           1 :   @protected
      29           1 :   String get type => DataHelpers.getType<E>();
      30             : 
      31             :   /// Initializes this relationship (typically when initializing the owner
      32             :   /// in [DataModel]) by supplying the owner, and related [adapters] and metadata.
      33             :   @override
      34             :   @mustCallSuper
      35           1 :   Future<Relationship<E, N>> initialize(
      36             :       {@required final Map<String, RemoteAdapter> adapters,
      37             :       @required final DataModel owner,
      38             :       @required final String name,
      39             :       @required final String inverseName}) async {
      40           1 :     if (isInitialized) return this;
      41             : 
      42           1 :     _adapters = adapters;
      43           3 :     _adapter = adapters[type] as RemoteAdapter<E>;
      44             : 
      45           1 :     assert(owner != null && _adapter != null);
      46           2 :     _ownerKey = owner._key;
      47           1 :     _name = name;
      48           1 :     _inverseName = inverseName;
      49             : 
      50             :     // initialize uninitialized models and get keys
      51           3 :     final newKeys = _uninitializedModels.map((model) {
      52           3 :       return model._initialize(_adapters, save: true)._key;
      53             :     });
      54           2 :     _uninitializedKeys..addAll(newKeys);
      55           2 :     _uninitializedModels.clear();
      56             : 
      57             :     // initialize keys
      58           1 :     if (!_wasOmitted) {
      59             :       // if it wasn't omitted, we overwrite
      60           3 :       _graph._removeEdges(_ownerKey,
      61           2 :           metadata: _name, inverseMetadata: _inverseName);
      62           2 :       _graph._addEdges(
      63           1 :         _ownerKey,
      64           1 :         tos: _uninitializedKeys,
      65           1 :         metadata: _name,
      66           1 :         inverseMetadata: _inverseName,
      67             :       );
      68           2 :       _uninitializedKeys.clear();
      69             :     }
      70             : 
      71           1 :     super.initialize();
      72             :     return this;
      73             :   }
      74             : 
      75           1 :   @override
      76           2 :   bool get isInitialized => _ownerKey != null && _adapters != null;
      77             : 
      78             :   // implement the `Set`
      79             : 
      80             :   /// Add a [value] to this [Relationship]
      81             :   ///
      82             :   /// Attempting to add an existing [value] has no effect as this is a [Set]
      83           1 :   @override
      84             :   bool add(E value, {bool notify = true}) {
      85             :     if (value == null) {
      86             :       return false;
      87             :     }
      88           1 :     if (contains(value)) {
      89             :       return false;
      90             :     }
      91             : 
      92             :     // try to ensure value is initialized
      93           1 :     _ensureModelIsInitialized(value);
      94             : 
      95           2 :     if (value._isInitialized && isInitialized) {
      96           4 :       _graph._addEdge(_ownerKey, value._key,
      97           2 :           metadata: _name, inverseMetadata: _inverseName);
      98             :     } else {
      99             :       // if it can't be initialized, add to the models queue
     100           2 :       _uninitializedModels.add(value);
     101             :     }
     102             :     return true;
     103             :   }
     104             : 
     105           1 :   @override
     106             :   bool contains(Object element) {
     107           2 :     return _iterable.contains(element);
     108             :   }
     109             : 
     110           1 :   @override
     111           2 :   Iterator<E> get iterator => _iterable.iterator;
     112             : 
     113           1 :   @override
     114             :   E lookup(Object element) {
     115           2 :     return toSet().lookup(element);
     116             :   }
     117             : 
     118             :   /// Removes a [value] from this [Relationship]
     119           1 :   @override
     120             :   bool remove(Object value, {bool notify = true}) {
     121           1 :     assert(value is E);
     122             :     final model = value as E;
     123           1 :     if (isInitialized) {
     124           1 :       _ensureModelIsInitialized(model);
     125           2 :       _graph._removeEdge(
     126           1 :         _ownerKey,
     127           1 :         model._key,
     128           1 :         metadata: _name,
     129           1 :         inverseMetadata: _inverseName,
     130             :         notify: notify,
     131             :       );
     132             :       return true;
     133             :     }
     134           2 :     return _uninitializedModels.remove(model);
     135             :   }
     136             : 
     137           1 :   @override
     138           2 :   int get length => _iterable.length;
     139             : 
     140           1 :   @override
     141             :   Set<E> toSet() {
     142           2 :     return _iterable.toSet();
     143             :   }
     144             : 
     145             :   // support methods
     146             : 
     147           1 :   Iterable<E> get _iterable {
     148           1 :     if (isInitialized) {
     149           1 :       return keys
     150           4 :           .map((key) => _adapter.localAdapter
     151           1 :               .findOne(key)
     152           2 :               ?._initialize(_adapters, key: key))
     153           1 :           .filterNulls;
     154             :     }
     155           1 :     return _uninitializedModels;
     156             :   }
     157             : 
     158             :   /// Returns keys as [Set] in relationship if initialized, otherwise an empty set
     159           1 :   @protected
     160             :   @visibleForTesting
     161             :   Set<String> get keys {
     162           1 :     if (isInitialized) {
     163           5 :       return _graph?._getEdge(_ownerKey, metadata: _name)?.toSet() ?? {};
     164             :     }
     165           1 :     return _uninitializedKeys;
     166             :   }
     167             : 
     168           1 :   E _ensureModelIsInitialized(E model) {
     169           2 :     if (!model._isInitialized && isInitialized) {
     170           2 :       model._initialize(_adapters, save: true);
     171             :     }
     172             :     return model;
     173             :   }
     174             : 
     175           1 :   StateNotifier<List<DataGraphEvent>> get _graphEvents {
     176           1 :     assert(_adapter != null);
     177           4 :     return _adapter.throttledGraph.map((events) {
     178           1 :       final appliesToRelationship = (DataGraphEvent event) {
     179           2 :         return event.type.isEdge &&
     180           3 :             event.metadata == _name &&
     181           3 :             event.keys.containsFirst(_ownerKey);
     182             :       };
     183           2 :       return events.where(appliesToRelationship).toImmutableList();
     184             :     });
     185             :   }
     186             : 
     187             :   StateNotifier<N> watch();
     188             : 
     189             :   /// This is used to make `json_serializable`'s `explicitToJson` transparent.
     190             :   ///
     191             :   /// For internal use. Does not return valid JSON.
     192           1 :   dynamic toJson() => this;
     193             : 
     194             :   @override
     195             :   String toString();
     196             : 
     197             :   // equality
     198             : 
     199           1 :   @override
     200             :   bool operator ==(dynamic other) =>
     201             :       identical(this, other) ||
     202           0 :       other is Relationship && toSet() == other.toSet();
     203             : 
     204           0 :   @override
     205           0 :   int get hashCode => runtimeType.hashCode ^ toSet().hashCode;
     206             : }
     207             : 
     208             : // annotation
     209             : 
     210             : class DataRelationship {
     211             :   final String inverse;
     212           0 :   const DataRelationship({@required this.inverse});
     213             : }

Generated by: LCOV version 1.14