LCOV - code coverage report
Current view: top level - model/relationship - relationship.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 81 82 98.8 %
Date: 2021-06-18 12:41:16 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 _Lifecycle, EquatableMixin {
       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             :   late final String _ownerKey;
      18             :   late final String _name;
      19             :   late final String? _inverseName;
      20             :   late final Map<String, RemoteAdapter> _adapters;
      21             :   late final 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           2 :   String get _internalType => DataHelpers.getType<E>();
      29             : 
      30             :   /// Initializes this relationship (typically when initializing the owner
      31             :   /// in [DataModel]) by supplying the owner, and related [adapters] and metadata.
      32           1 :   Future<Relationship<E, N>> initialize(
      33             :       {required final Map<String, RemoteAdapter> adapters,
      34             :       required final DataModel owner,
      35             :       required final String name,
      36             :       final String? inverseName}) async {
      37           1 :     if (isInitialized) return this;
      38             : 
      39           1 :     _adapters = adapters;
      40           3 :     _adapter = adapters[_internalType] as RemoteAdapter<E>;
      41             : 
      42           2 :     _ownerKey = owner._key!;
      43           1 :     _name = name;
      44           1 :     _inverseName = inverseName;
      45             : 
      46             :     // initialize uninitialized models and get keys
      47           3 :     final newKeys = _uninitializedModels.map((model) {
      48           3 :       return model._initialize(_adapters, save: true)._key!;
      49             :     });
      50           2 :     _uninitializedKeys.addAll(newKeys);
      51           2 :     _uninitializedModels.clear();
      52             : 
      53             :     // initialize keys
      54           1 :     if (!_wasOmitted) {
      55             :       // if it wasn't omitted, we overwrite
      56           3 :       _graph._removeEdges(_ownerKey,
      57           2 :           metadata: _name, inverseMetadata: _inverseName);
      58           2 :       _graph._addEdges(
      59           1 :         _ownerKey,
      60           1 :         tos: _uninitializedKeys,
      61           1 :         metadata: _name,
      62           1 :         inverseMetadata: _inverseName,
      63             :       );
      64           2 :       _uninitializedKeys.clear();
      65             :     }
      66             : 
      67           1 :     isInitialized = true;
      68             :     return this;
      69             :   }
      70             : 
      71             :   @override
      72             :   bool isInitialized = false;
      73             : 
      74             :   // implement collection-like methods
      75             : 
      76             :   /// Add a [value] to this [Relationship]
      77             :   ///
      78             :   /// Attempting to add an existing [value] has no effect as this is a [Set]
      79           1 :   bool add(E value, {bool notify = true}) {
      80           1 :     if (contains(value)) {
      81             :       return false;
      82             :     }
      83             : 
      84             :     // try to ensure value is initialized
      85           1 :     _ensureModelIsInitialized(value);
      86             : 
      87           2 :     if (value.isInitialized && isInitialized) {
      88           4 :       _graph._addEdge(_ownerKey, value._key!,
      89           2 :           metadata: _name, inverseMetadata: _inverseName);
      90             :     } else {
      91             :       // if it can't be initialized, add to the models queue
      92           2 :       _uninitializedModels.add(value);
      93             :     }
      94             :     return true;
      95             :   }
      96             : 
      97           1 :   bool contains(Object element) {
      98           2 :     return _iterable.contains(element);
      99             :   }
     100             : 
     101             :   /// Removes a [value] from this [Relationship]
     102           1 :   bool remove(Object value, {bool notify = true}) {
     103             :     assert(value is E);
     104             :     final model = value as E;
     105           1 :     if (isInitialized) {
     106           1 :       _ensureModelIsInitialized(model);
     107           2 :       _graph._removeEdge(
     108           1 :         _ownerKey,
     109           1 :         model._key!,
     110           1 :         metadata: _name,
     111           1 :         inverseMetadata: _inverseName,
     112             :         notify: notify,
     113             :       );
     114             :       return true;
     115             :     }
     116           2 :     return _uninitializedModels.remove(model);
     117             :   }
     118             : 
     119           3 :   E? get first => _iterable.safeFirst;
     120             : 
     121           3 :   int get length => _iterable.length;
     122             : 
     123           3 :   bool get isEmpty => _iterable.isEmpty;
     124             : 
     125           3 :   bool get isNotEmpty => _iterable.isNotEmpty;
     126             : 
     127           3 :   Iterable<E> where(bool Function(E) test) => _iterable.where(test);
     128             : 
     129           3 :   Iterable<T> map<T>(T Function(E) f) => _iterable.map(f);
     130             : 
     131           3 :   Set<E> toSet() => _iterable.toSet();
     132             : 
     133           3 :   List<E> toList() => _iterable.toList();
     134             : 
     135             :   // support methods
     136             : 
     137           1 :   Iterable<E> get _iterable {
     138           1 :     if (isInitialized) {
     139           1 :       return keys
     140           4 :           .map((key) => _adapter.localAdapter
     141           1 :               .findOne(key)
     142           2 :               ?._initialize(_adapters, key: key))
     143           1 :           .filterNulls;
     144             :     }
     145           1 :     return _uninitializedModels;
     146             :   }
     147             : 
     148             :   /// Returns keys as [Set] in relationship if initialized, otherwise an empty set
     149           1 :   @protected
     150             :   @visibleForTesting
     151             :   Set<String> get keys {
     152           1 :     if (isInitialized) {
     153           5 :       return _graph._getEdge(_ownerKey, metadata: _name).toSet();
     154             :     }
     155           1 :     return _uninitializedKeys;
     156             :   }
     157             : 
     158           1 :   Set<String> get ids {
     159           6 :     return keys.map(_graph.getIdForKey).filterNulls.toSet();
     160             :   }
     161             : 
     162           1 :   E _ensureModelIsInitialized(E model) {
     163           2 :     if (!model.isInitialized && isInitialized) {
     164           2 :       model._initialize(_adapters, save: true);
     165             :     }
     166             :     return model;
     167             :   }
     168             : 
     169           1 :   DelayedStateNotifier<List<DataGraphEvent>> get _graphEvents {
     170           4 :     return _adapter.throttledGraph.map((events) {
     171           3 :       return events.where(_appliesToRelationship).toImmutableList();
     172             :     });
     173             :   }
     174             : 
     175             :   DelayedStateNotifier<N> watch();
     176             : 
     177             :   /// This is used to make `json_serializable`'s `explicitToJson` transparent.
     178             :   ///
     179             :   /// For internal use. Does not return valid JSON.
     180           1 :   dynamic toJson() => this;
     181             : 
     182             :   @override
     183             :   String toString();
     184             : 
     185           1 :   @override
     186           2 :   List<Object> get props => [_prop];
     187             : 
     188           0 :   @override
     189             :   void dispose() {
     190             :     // relationships are not disposed
     191             :   }
     192             : 
     193             :   // utils
     194             : 
     195           6 :   String get _prop => _iterable.map((e) => e.id).join(', ');
     196             : 
     197           1 :   bool _appliesToRelationship(DataGraphEvent event) {
     198           2 :     return event.type.isEdge &&
     199           3 :         event.metadata == _name &&
     200           3 :         event.keys.containsFirst(_ownerKey);
     201             :   }
     202             : }
     203             : 
     204             : // annotation
     205             : 
     206             : class DataRelationship {
     207             :   final String inverse;
     208           3 :   const DataRelationship({required this.inverse});
     209             : }

Generated by: LCOV version 1.15