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 2 : HiveLocalAdapter(this._hiveLocalStorage, GraphNotifier graph) : super(graph); 8 : 9 : final HiveLocalStorage _hiveLocalStorage; 10 : final _type = DataHelpers.getType<T>(); 11 : 12 : // once late final field, remove ignore on class 13 : @protected 14 : @visibleForTesting 15 : Box<T> box; 16 : 17 : @override 18 1 : Future<HiveLocalAdapter<T>> initialize() async { 19 1 : if (isInitialized) return this; 20 : // IMPORTANT: initialize graph before registering 21 2 : await super.initialize(); 22 : 23 4 : if (!_hiveLocalStorage.hive.isBoxOpen(_type)) { 24 0 : _hiveLocalStorage.hive.registerAdapter(this); 25 : } 26 : 27 6 : box = await _hiveLocalStorage.hive.openBox<T>(_type, 28 2 : encryptionCipher: _hiveLocalStorage.encryptionCipher); 29 : 30 2 : if (_hiveLocalStorage.clear ?? false) { 31 0 : await box.clear(); 32 : } 33 : 34 : return this; 35 : } 36 : 37 : @override 38 1 : Future<void> dispose() async { 39 2 : await super.dispose(); 40 3 : await box?.close(); 41 : } 42 : 43 : // protected API 44 : 45 1 : @override 46 : List<T> findAll() { 47 3 : return box.values.toImmutableList(); 48 : } 49 : 50 1 : @override 51 2 : T findOne(String key) => key != null ? box.get(key) : null; 52 : 53 : @override 54 1 : Future<void> save(String key, T model, {bool notify = true}) async { 55 0 : assert(key != null); 56 2 : final keyExisted = box.containsKey(key); 57 2 : final save = box.put(key, model); 58 : if (notify) { 59 2 : graph._notify( 60 1 : [key], 61 : keyExisted ? DataGraphEventType.updateNode : DataGraphEventType.addNode, 62 : ); 63 : } 64 1 : await save; 65 : } 66 : 67 : @override 68 1 : Future<void> delete(String key) async { 69 : if (key != null) { 70 2 : final delete = box.delete(key); // delete in bg 71 : // id will become orphan & purged 72 2 : graph.removeKey(key); 73 1 : await delete; 74 : } 75 : } 76 : 77 : @override 78 1 : Future<void> clear() async { 79 3 : await box.clear(); 80 : } 81 : 82 : // hive adapter 83 : 84 1 : @override 85 : int get typeId { 86 : // _types: { 87 : // 'posts': {'1'}, 88 : // 'comments': {'2'}, 89 : // 'houses': {'3'}, 90 : // } 91 : 92 2 : if (!graph.hasNode('hive:adapter')) { 93 2 : graph.addNode('hive:adapter'); 94 : } 95 : 96 2 : final _typesNode = graph.getNode('hive:adapter'); 97 : 98 5 : if (_typesNode[_type] != null && _typesNode[_type].isNotEmpty) { 99 4 : return int.parse(_typesNode[_type].first); 100 : } 101 : 102 2 : final index = _typesNode.length + 1; 103 : // insert at last position of _typesNode map 104 4 : _typesNode[_type] = [index.toString()]; 105 : return index; 106 : } 107 : 108 0 : @override 109 : T read(reader) { 110 : // read key first 111 0 : final key = reader.read().toString(); 112 : 113 : // read attributes (no relationships stored) 114 0 : final total = reader.readByte(); 115 0 : final map = <String, dynamic>{ 116 0 : for (var i = 0; i < total; i++) reader.read().toString(): reader.read(), 117 : }; 118 : 119 : // reconstruct relationship information from graph 120 0 : for (final entry in relationshipsFor().entries) { 121 : // entry keys are the name of relationships => metadata 122 0 : final name = entry.key; 123 0 : final relKeys = graph._getEdge(key, metadata: name); 124 0 : map[name] = 125 0 : entry.value['kind'] == 'BelongsTo' ? relKeys.safeFirst : relKeys; 126 : } 127 : 128 0 : return deserialize(map); 129 : } 130 : 131 0 : @override 132 : void write(writer, T obj) { 133 0 : final _map = serialize(obj); 134 : // write key first 135 0 : writer.write(obj._key); 136 : 137 : // exclude relationships 138 0 : final keys = _map.keys.where((k) => !relationshipsFor().containsKey(k)); 139 0 : writer.writeByte(keys.length); 140 0 : for (final k in keys) { 141 0 : writer.write(k); 142 0 : writer.write(_map[k]); 143 : } 144 : } 145 : }