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

Generated by: LCOV version 1.15