LCOV - code coverage report
Current view: top level - repository - hive_local_adapter.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 53 69 76.8 %
Date: 2022-07-06 18:09:45 Functions: 0 0 -

          Line data    Source code
       1             : part of flutter_data;
       2             : 
       3             : /// Hive implementation of [LocalAdapter] and Hive's [TypeAdapter].
       4             : // ignore: must_be_immutable
       5             : abstract class HiveLocalAdapter<T extends DataModel<T>> extends LocalAdapter<T>
       6             :     with TypeAdapter<T> {
       7          11 :   HiveLocalAdapter(Reader read, {int? typeId})
       8             :       : _typeId = typeId,
       9          22 :         _hiveLocalStorage = read(hiveLocalStorageProvider),
      10          11 :         super(read);
      11             : 
      12             :   final int? _typeId;
      13             :   final HiveLocalStorage _hiveLocalStorage;
      14             : 
      15             :   final _hiveAdapterNs = '_adapter_hive';
      16          33 :   String get _hiveAdapterKey => 'key'.namespaceWith(_hiveAdapterNs);
      17             : 
      18          11 :   @protected
      19             :   @visibleForTesting
      20          33 :   Box<T>? get box => (_box?.isOpen ?? false) ? _box : null;
      21             :   Box<T>? _box;
      22             : 
      23             :   @override
      24          11 :   Future<HiveLocalAdapter<T>> initialize() async {
      25          11 :     if (isInitialized) return this;
      26          22 :     final hive = _hiveLocalStorage.hive;
      27             : 
      28          22 :     if (!hive.isBoxOpen(internalType)) {
      29          22 :       if (!hive.isAdapterRegistered(typeId)) {
      30           0 :         hive.registerAdapter(this);
      31             :       }
      32             :     }
      33             : 
      34             :     try {
      35          22 :       if (_hiveLocalStorage.clear) {
      36           0 :         await _hiveLocalStorage.deleteBox(internalType);
      37             :       }
      38          55 :       _box = await _hiveLocalStorage.openBox<T>(internalType);
      39             :     } catch (e, stackTrace) {
      40           0 :       print('[flutter_data] Box failed to open:\n$e\n$stackTrace');
      41             :     }
      42             : 
      43             :     return this;
      44             :   }
      45             : 
      46          11 :   @override
      47          11 :   bool get isInitialized => box != null;
      48             : 
      49          10 :   @override
      50             :   void dispose() {
      51          20 :     box?.close();
      52             :   }
      53             : 
      54             :   // protected API
      55             : 
      56           5 :   @override
      57             :   List<T>? findAll() {
      58           5 :     if (_isLocalStorageTouched) {
      59          15 :       return box?.values.toImmutableList();
      60             :     }
      61             :     return null;
      62             :   }
      63             : 
      64          11 :   @override
      65             :   T? findOne(String? key) {
      66             :     if (key == null) return null;
      67          22 :     return box?.get(key);
      68             :   }
      69             : 
      70             :   @override
      71          11 :   Future<T> save(String key, T model, {bool notify = true}) async {
      72          11 :     if (box == null) return model;
      73             : 
      74          11 :     _touchLocalStorage();
      75             : 
      76          22 :     final keyExisted = box!.containsKey(key);
      77          22 :     final save = box!.put(key, model);
      78             :     if (notify) {
      79          22 :       graph._notify(
      80          11 :         [key],
      81             :         type: keyExisted
      82             :             ? DataGraphEventType.updateNode
      83             :             : DataGraphEventType.addNode,
      84             :       );
      85             :     }
      86             : 
      87          11 :     await save;
      88             :     return model;
      89             :   }
      90             : 
      91             :   @override
      92           5 :   Future<void> delete(String key, {bool notify = true}) async {
      93           5 :     if (box == null) return;
      94          10 :     final delete = box!.delete(key); // delete in bg
      95             :     // id will become orphan & purged
      96          10 :     graph.removeKey(key);
      97           5 :     await delete;
      98             :   }
      99             : 
     100             :   @override
     101           2 :   Future<void> clear() async {
     102           6 :     await box?.clear();
     103             :   }
     104             : 
     105             :   // Touching local storage means the box has received data;
     106             :   // this is used to know whether `findAll` should return
     107             :   // null, or its models (possibly empty)
     108             : 
     109             :   // _boxMetadata: {
     110             :   //   '_boxMetadata:touched': ['_'],
     111             :   // }
     112             : 
     113           5 :   @override
     114             :   bool get _isLocalStorageTouched {
     115          10 :     return graph._hasEdge('_boxMetadata', metadata: '_boxMetadata:touched');
     116             :   }
     117             : 
     118          11 :   @override
     119             :   void _touchLocalStorage() {
     120          22 :     graph._addEdge('_boxMetadata', '_',
     121             :         metadata: '_boxMetadata:touched', addNode: true, notify: false);
     122             :   }
     123             : 
     124             :   // hive adapter
     125             : 
     126          11 :   @override
     127             :   int get typeId {
     128             :     late final int id;
     129             : 
     130             :     // if `typeId` was supplied, use it
     131          11 :     if (_typeId != null) {
     132          11 :       id = _typeId!;
     133             :     } else {
     134             :       // otherwise auto-calculate (and persist)
     135             : 
     136             :       // _adapter_hive:key: {
     137             :       //   '_adapter_hive:posts': ['_adapter_hive:1'],
     138             :       //   '_adapter_hive:comments': ['_adapter_hive:2'],
     139             :       //   '_adapter_hive:houses': ['_adapter_hive:3'],
     140             :       // }
     141             : 
     142             :       final typesNode =
     143          33 :           graph._getNode(_hiveAdapterKey, orAdd: true, notify: false)!;
     144             : 
     145          44 :       final edge = typesNode[internalType.namespaceWith(_hiveAdapterNs)];
     146             : 
     147           1 :       if (edge != null && edge.isNotEmpty) {
     148             :         // first is of format: _adapter_hive:1
     149           3 :         return int.parse(edge.first.denamespace());
     150             :       }
     151             : 
     152             :       // get namespaced indices
     153          11 :       id = typesNode.values
     154             :               // denamespace and parse single
     155          55 :               .map((e) => int.parse(e.first.denamespace()))
     156             :               // find max
     157          22 :               .fold(0, math.max) +
     158             :           1;
     159             :     }
     160             : 
     161          66 :     graph._addEdge(_hiveAdapterKey, id.toString().namespaceWith(_hiveAdapterNs),
     162          33 :         metadata: internalType.namespaceWith(_hiveAdapterNs), notify: false);
     163             : 
     164             :     return id;
     165             :   }
     166             : 
     167           0 :   @override
     168             :   T read(reader) {
     169             :     // read attributes (no relationships stored)
     170           0 :     final total = reader.readByte();
     171           0 :     final map = <String, dynamic>{
     172           0 :       for (var i = 0; i < total; i++) reader.read().toString(): reader.read(),
     173             :     };
     174             : 
     175           0 :     final model = deserialize(map);
     176             : 
     177             :     // Model initialization is necessary here as `DataModel`s
     178             :     // auto-initialization is not ready at this point
     179             :     // (reading adapters during FD initialization)
     180           0 :     initModel(model);
     181             : 
     182             :     return model;
     183             :   }
     184             : 
     185           0 :   @override
     186             :   void write(writer, T obj) {
     187           0 :     final map = serialize(obj, withRelationships: false);
     188             : 
     189           0 :     final keys = map.keys;
     190           0 :     writer.writeByte(keys.length);
     191           0 :     for (final k in keys) {
     192           0 :       writer.write(k);
     193           0 :       writer.write(map[k]);
     194             :     }
     195             :   }
     196             : }

Generated by: LCOV version 1.15