diff --git a/CHANGELOG.md b/CHANGELOG.md index 272adee..9462cf2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] - +## [0.1.0] + +### Added + +- JsonCache interface and the JsonFake, JsonWrap, and JsonMem implementations. ## [0.0.1] + +- structural organization: + - linter setup + - CI/CD pipelines + - dependencies + - README file + - CHANGELOG file diff --git a/README.md b/README.md index a83f5eb..dd98d50 100644 --- a/README.md +++ b/README.md @@ -28,9 +28,12 @@ Rultor.com](https://www.rultor.com/b/dartoos-dev/json_cache)](https://www.rultor ## Overview -**Json Cache** is an object-oriented layer on top of local storage packages that +**Json Cache** is an object-oriented package to cache user data locally in json. +It can also be thought of as a layer on top of Flutter's local storage packages +like [sharable_preferences](https://pub.dev/packages/shared_preferences)that unifies them as an elegant caching API. + In addition, this package gives developers great flexibility by providing a set of classes that can be selected and grouped in various combinations to meet specific cache requirements. diff --git a/analysis_options.yaml b/analysis_options.yaml index 36c6284..511bc97 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -13,6 +13,8 @@ linter: sort_constructors_first: true # Good packages document everything public_member_api_docs: true + # Always await. + unawaited_futures: true always_declare_return_types: true cancel_subscriptions: true close_sinks: true diff --git a/lib/src/json_cache.dart b/lib/src/json_cache.dart index edc9134..d10fefc 100644 --- a/lib/src/json_cache.dart +++ b/lib/src/json_cache.dart @@ -7,8 +7,8 @@ abstract class JsonCache { /// previous data there. Future refresh(String key, Map data); - /// Removes data from cache at [key] and returns it or returns null if there - /// is no data at [key]. + /// Removes data from cache at [key]. It returns the removed data or null if + /// no removal was performed — there was no data at [key]. Future?> erase(String key); /// Retrieves either the data at [key] or null if a cache miss occurs. diff --git a/lib/src/json_cache_fake.dart b/lib/src/json_cache_fake.dart index bd10285..1457c76 100644 --- a/lib/src/json_cache_fake.dart +++ b/lib/src/json_cache_fake.dart @@ -13,7 +13,7 @@ class JsonCacheFake implements JsonCache { /// in-memory storage. final Map?> _memory; - static final Map> _shrMem = {}; + static late final Map?> _shrMem = {}; /// Clears the internal map. @override diff --git a/lib/src/json_cache_mem.dart b/lib/src/json_cache_mem.dart index 34b422e..f0a409a 100644 --- a/lib/src/json_cache_mem.dart +++ b/lib/src/json_cache_mem.dart @@ -37,10 +37,10 @@ class JsonCacheMem implements JsonCache { final ReadWriteMutex _mutex; /// in-memory shared storage. - static final Map> _shrMem = {}; + static late final Map?> _shrMem = {}; /// shared mutex. - static final _shrMutex = ReadWriteMutex(); + static late final _shrMutex = ReadWriteMutex(); /// Frees up storage space in both the level2 cache and in-memory cache. @override diff --git a/test/json_cache_mem_test.dart b/test/json_cache_mem_test.dart index 6b8863c..bdb1aae 100644 --- a/test/json_cache_mem_test.dart +++ b/test/json_cache_mem_test.dart @@ -3,12 +3,54 @@ import 'package:json_cache/json_cache.dart'; void main() { group('JsonCacheMem', () { - test('clear', () async { + const profKey = 'profile'; + const Map profData = { + 'id': 1, + 'name': 'John Due' + }; + group('clear, recover and refresh', () { + test('default ctor', () async { + final JsonCacheMem inMemCache = JsonCacheMem(JsonCacheFake()); + await inMemCache.refresh(profKey, profData); + final result = await inMemCache.recover(profKey); + expect(profData, result); + await inMemCache.clear(); + final mustBeNull = await inMemCache.recover(profKey); + expect(mustBeNull, isNull); + }); + test('mem ctor', () async { + final Map?> copy = { + profKey: Map.of(profData) + }; + final inMemCache = JsonCacheMem.mem(JsonCacheFake.mem(copy), copy); + final result = await inMemCache.recover(profKey); + expect(result, profData); + await inMemCache.clear(); + expect(copy.isEmpty, true); + final mustBeNull = await inMemCache.recover(profKey); + expect(mustBeNull, isNull); + }); + }); + + test('erase', () async { + const profKey = 'profile'; + const prefsKey = 'preferences'; + final prof = {'id': 1, 'name': 'John Due'}; + final prefs = { + 'preferences': { + 'theme': 'dark', + 'notifications': {'enabled': true} + } + }; final Map> data = { - 'profile': {'id': 1, 'name': 'John Due'} + profKey: prof, + prefsKey: prefs }; - await JsonCacheMem.mem(JsonCacheFake.mem(data), data).clear(); - expect(data.isEmpty, true); + expect(data.containsKey(profKey), true); + expect(data.containsKey(prefsKey), true); + await JsonCacheMem.mem(JsonCacheFake.mem(data), data).erase(prefsKey); + expect(data.containsKey(prefsKey), false); + expect(data.containsKey(profKey), true); }); }); } diff --git a/test/json_cache_wrap_test.dart b/test/json_cache_wrap_test.dart index 8a438f3..7f6af15 100644 --- a/test/json_cache_wrap_test.dart +++ b/test/json_cache_wrap_test.dart @@ -1,5 +1,51 @@ import 'package:flutter_test/flutter_test.dart'; +import 'package:json_cache/json_cache.dart'; + +class JsonCacheFakeWrap extends JsonCacheWrap { + JsonCacheFakeWrap() : super(JsonCacheFake()); +} void main() { - group('JsonCacheWrap', () {}); + group('JsonCacheWrap', () { + const profKey = 'profile'; + const Map profData = { + 'id': 1, + 'name': 'John Due' + }; + group('clear, recover and refresh', () { + test('default ctor', () async { + final JsonCache wrap = JsonCacheFakeWrap(); + await wrap.refresh(profKey, profData); + final result = await wrap.recover(profKey); + expect(profData, result); + await wrap.clear(); + final mustBeNull = await wrap.recover(profKey); + expect(mustBeNull, isNull); + }); + }); + + test('erase', () async { + const profKey = 'profile'; + const prefsKey = 'preferences'; + final prof = {'id': 1, 'name': 'John Due'}; + final prefs = { + 'preferences': { + 'theme': 'dark', + 'notifications': {'enabled': true} + } + }; + final Map> data = { + profKey: prof, + prefsKey: prefs + }; + expect(data.containsKey(profKey), true); + expect(data.containsKey(prefsKey), true); + final wrap = JsonCacheFakeWrap(); + await wrap.refresh(prefsKey, prefs); + final erasedPrefs = await wrap.erase(prefsKey); + expect(erasedPrefs, prefs); + final mustBeNull = await wrap.recover(prefsKey); + expect(mustBeNull, isNull); + }); + }); }