Line data Source code
1 : part of flutter_data; 2 : 3 : /// An adapter interface to access local storage. 4 : /// 5 : /// Identity in this layer is enforced by keys. 6 : /// 7 : /// See also: [HiveLocalAdapter] 8 : abstract class LocalAdapter<T extends DataModel<T>> with _Lifecycle { 9 11 : @protected 10 22 : LocalAdapter(Reader read) : graph = read(graphNotifierProvider); 11 : 12 : @protected 13 : final GraphNotifier graph; 14 : 15 : FutureOr<LocalAdapter<T>> initialize(); 16 : 17 22 : String get internalType => DataHelpers.getType<T>(); 18 : 19 : // protected API 20 : 21 : /// Returns all models of type [T] in local storage. 22 : List<T>? findAll(); 23 : 24 : /// Finds model of type [T] by [key] in local storage. 25 : T? findOne(String? key); 26 : 27 : /// Saves model of type [T] with [key] in local storage. 28 : /// 29 : /// By default notifies this modification to the associated [GraphNotifier]. 30 : @protected 31 : @visibleForTesting 32 : Future<T> save(String key, T model, {bool notify = true}); 33 : 34 : /// Deletes model of type [T] with [key] from local storage. 35 : /// 36 : /// By default notifies this modification to the associated [GraphNotifier]. 37 : @protected 38 : @visibleForTesting 39 : Future<void> delete(String key, {bool notify = true}); 40 : 41 : /// Deletes all models of type [T] in local storage. 42 : @protected 43 : @visibleForTesting 44 : Future<void> clear(); 45 : 46 : // model initialization 47 : 48 11 : @protected 49 : @nonVirtual 50 : T initModel(T model, {Function(T)? onModelInitialized}) { 51 11 : if (model._key == null) { 52 55 : model._key = graph.getKeyForId(internalType, model.id, 53 11 : keyIfAbsent: DataHelpers.generateKey<T>())!; 54 11 : _initializeRelationships(model); 55 11 : onModelInitialized?.call(model); 56 : } 57 : return model; 58 : } 59 : 60 11 : void _initializeRelationships(T model) { 61 22 : final metadatas = relationshipMetas.values; 62 22 : for (final metadata in metadatas) { 63 22 : final relationship = metadata.instance(model); 64 11 : relationship?.initialize( 65 : owner: model, 66 11 : name: metadata.name, 67 11 : inverseName: metadata.inverseName, 68 : ); 69 : } 70 : } 71 : 72 : // public abstract methods 73 : 74 : Map<String, dynamic> serialize(T model, {bool withRelationships = true}); 75 : 76 : T deserialize(Map<String, dynamic> map); 77 : 78 : Map<String, RelationshipMeta> get relationshipMetas; 79 : 80 : // helpers 81 : 82 8 : Map<String, dynamic> transformSerialize(Map<String, dynamic> map, 83 : {bool withRelationships = true}) { 84 24 : for (final e in relationshipMetas.entries) { 85 8 : final key = e.key; 86 : if (withRelationships) { 87 24 : final ignored = e.value.serialize == false; 88 1 : if (ignored) map.remove(key); 89 : 90 16 : if (map[key] is HasMany) { 91 24 : map[key] = (map[key] as HasMany).keys; 92 16 : } else if (map[key] is BelongsTo) { 93 24 : map[key] = map[key].key; 94 : } 95 : 96 16 : if (map[key] == null) map.remove(key); 97 : } else { 98 2 : map.remove(key); 99 : } 100 : } 101 : return map; 102 : } 103 : 104 8 : Map<String, dynamic> transformDeserialize(Map<String, dynamic> map) { 105 : // ensure value is dynamic (argument might come in as Map<String, String>) 106 8 : map = Map<String, dynamic>.from(map); 107 24 : for (final e in relationshipMetas.entries) { 108 8 : final key = e.key; 109 16 : final keyset = map[key] is Iterable 110 8 : ? {...(map[key] as Iterable)} 111 16 : : {if (map[key] != null) map[key].toString()}; 112 24 : final ignored = e.value.serialize == false; 113 16 : map[key] = { 114 8 : '_': (map.containsKey(key) && !ignored) ? keyset : null, 115 : }; 116 : } 117 : return map; 118 : } 119 : 120 : // private 121 : 122 : // ignore: unused_element 123 : bool get _isLocalStorageTouched; 124 : 125 : void _touchLocalStorage(); 126 : }