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

Generated by: LCOV version 1.15