LCOV - code coverage report
Current view: top level - model - data_model.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 54 56 96.4 %
Date: 2022-05-06 22:54:19 Functions: 0 0 -

          Line data    Source code
       1             : part of flutter_data;
       2             : 
       3             : /// A mixin to "tag" and ensure the implementation of an [id] getter
       4             : /// in data classes managed through Flutter Data.
       5             : ///
       6             : /// It contains private state and methods to track the model's identity.
       7             : abstract class DataModel<T extends DataModel<T>> {
       8             :   Object? get id;
       9             : 
      10           1 :   DataModel() {
      11           3 :     final _isRepoInitialized = internalRepositories.containsKey(_internalType);
      12           3 :     if (_isRepoInitialized && remoteAdapter.autoInitializeModels) init();
      13             :   }
      14             : 
      15             :   late String _key;
      16           2 :   String get _internalType => DataHelpers.getType<T>();
      17             :   DataStateNotifier<T?>? _notifier;
      18           1 :   T get _this => this as T;
      19             : 
      20             :   /// Exposes this type's [RemoteAdapter]
      21           1 :   RemoteAdapter<T> get remoteAdapter =>
      22           4 :       internalRepositories[_internalType]!.remoteAdapter as RemoteAdapter<T>;
      23             : 
      24             :   /// Exposes the [DataStateNotifier] that fetched this model;
      25             :   /// typically used to access `notifier.reload()`.
      26             :   /// ONLY available if loaded via [Repository.watchOneNotifier].
      27           2 :   DataStateNotifier<T?>? get notifier => _notifier;
      28             : 
      29             :   // methods
      30             : 
      31           1 :   T saveLocal() {
      32           5 :     remoteAdapter.localAdapter.save(_key, _this);
      33           1 :     return _this;
      34             :   }
      35             : 
      36             :   // privately set the notifier
      37           1 :   void _updateNotifier(DataStateNotifier<T?>? value) {
      38           1 :     _notifier = value;
      39             :   }
      40             : }
      41             : 
      42             : /// Extension that adds syntax-sugar to data classes,
      43             : /// linking them to common [Repository] methods such as
      44             : /// [save] and [delete].
      45             : extension DataModelExtension<T extends DataModel<T>> on DataModel<T> {
      46             :   /// Copy identity (internal key) from an old model to a new one
      47             :   /// to signal they are the same.
      48           1 :   T was(T model) {
      49           3 :     if (model._key != _key) {
      50             :       T _old;
      51             :       T _new;
      52             : 
      53             :       // if the passed-in model has no ID
      54             :       // then treat the original as prevalent
      55           2 :       if (model.id == null && id != null) {
      56             :         _old = model;
      57           1 :         _new = _this;
      58             :       } else {
      59             :         // in all other cases, treat the passed-in
      60             :         // model as prevalent
      61           1 :         _old = _this;
      62             :         _new = model;
      63             :       }
      64             : 
      65           1 :       final _oldKey = _old._key;
      66           3 :       if (_key != _new._key) {
      67           2 :         _key = _new._key;
      68             :       }
      69           3 :       if (_key != _old._key) {
      70           2 :         _old._key = _key;
      71           3 :         remoteAdapter.graph.removeKey(_oldKey);
      72             :       }
      73             : 
      74           1 :       if (_old.id != null) {
      75           5 :         remoteAdapter.graph.removeId(_internalType, _old.id!);
      76           2 :         remoteAdapter.graph
      77           4 :             .getKeyForId(_internalType, _old.id, keyIfAbsent: _key);
      78             :       }
      79             :     }
      80           1 :     return _this;
      81             :   }
      82             : 
      83             :   /// Saves this model through a call equivalent to [Repository.save].
      84             :   ///
      85             :   /// Usage: `await post.save()`, `author.save(remote: false, params: {'a': 'x'})`.
      86           1 :   Future<T> save({
      87             :     bool? remote,
      88             :     Map<String, dynamic>? params,
      89             :     Map<String, String>? headers,
      90             :     OnSuccessOne<T>? onSuccess,
      91             :     OnErrorOne<T>? onError,
      92             :   }) async {
      93           3 :     return await remoteAdapter.save(
      94           1 :       _this,
      95             :       remote: remote,
      96             :       params: params,
      97             :       headers: headers,
      98             :       onSuccess: onSuccess,
      99             :       onError: onError,
     100             :     );
     101             :   }
     102             : 
     103             :   /// Deletes this model through a call equivalent to [Repository.delete].
     104             :   ///
     105             :   /// Usage: `await post.delete()`
     106           1 :   Future<T?> delete({
     107             :     bool? remote,
     108             :     Map<String, dynamic>? params,
     109             :     Map<String, String>? headers,
     110             :     OnSuccessOne<T>? onSuccess,
     111             :     OnErrorOne<T>? onError,
     112             :   }) async {
     113           3 :     return await remoteAdapter.delete(
     114             :       this,
     115             :       remote: remote,
     116             :       params: params,
     117             :       headers: headers,
     118             :       onSuccess: onSuccess,
     119             :       onError: onError,
     120             :     );
     121             :   }
     122             : 
     123             :   /// Get the refreshed version from local storage.
     124           0 :   T? refresh() {
     125           0 :     return remoteAdapter.localAdapter.findOne(_key);
     126             :   }
     127             : 
     128             :   /// Re-fetch this model through a call equivalent to [Repository.findOne].
     129             :   /// with the current object/[id]
     130           1 :   Future<T?> reload({
     131             :     Map<String, dynamic>? params,
     132             :     Map<String, String>? headers,
     133             :     bool? background,
     134             :     DataRequestLabel? label,
     135             :   }) async {
     136           3 :     return await remoteAdapter.findOne(
     137             :       this,
     138             :       remote: true,
     139             :       params: params,
     140             :       headers: headers,
     141             :       background: background,
     142             :       label: label,
     143             :     );
     144             :   }
     145             : 
     146             :   /// Get all non-null [Relationship]s for this model.
     147           1 :   Iterable<Relationship> getRelationships() {
     148           5 :     final metadatas = remoteAdapter.localAdapter.relationshipsFor(_this).values;
     149             : 
     150             :     return metadatas
     151           2 :         .map((metadata) {
     152           1 :           final relationship = metadata['instance'] as Relationship?;
     153           1 :           return relationship?.initialize(
     154             :             owner: this,
     155           1 :             name: metadata['name'] as String,
     156           1 :             inverseName: metadata['inverse'] as String?,
     157             :           );
     158             :         })
     159           1 :         .toList()
     160           1 :         .filterNulls;
     161             :   }
     162             : 
     163           1 :   T init({bool save = true}) {
     164           6 :     _key = remoteAdapter.graph.getKeyForId(_internalType, id,
     165           1 :         keyIfAbsent: DataHelpers.generateKey<T>())!;
     166             :     if (save) {
     167           5 :       remoteAdapter.localAdapter.save(_key, _this, notify: false);
     168             :     }
     169           1 :     getRelationships();
     170           1 :     return _this;
     171             :   }
     172             : }
     173             : 
     174             : /// Returns a model's `_key` private attribute.
     175             : ///
     176             : /// Useful for testing, debugging or usage in [RemoteAdapter] subclasses.
     177           2 : String? keyFor<T extends DataModel<T>>(T model) => model._key;
     178             : 
     179           1 : @visibleForTesting
     180             : @protected
     181             : RemoteAdapter? adapterFor<T extends DataModel<T>>(T model) =>
     182           1 :     model.remoteAdapter;

Generated by: LCOV version 1.15