Skip to content

Commit 8bbf7ff

Browse files
authored
feat: JsonCachePrefs class
Closes #17
1 parent cf97778 commit 8bbf7ff

13 files changed

+373
-109
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- JsonCachePrefs, a implementation on top of the shared_preferences package —
13+
[26](https://github.com/dartoos-dev/json_cache/issues/26).
14+
15+
### Changed
16+
17+
- renaming JsonCache methods: erase to remove; recovery to value. **BREAKING
18+
CHANGES**.
19+
1020
## [0.1.0] - 2021-08-22
1121

1222
### Added

README.md

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
# json_cache
22

3-
<center>
4-
<img width="406" hight="192" alt="json cache logo" src="https://user-images.githubusercontent.com/24878574/119276278-56ef4a80-bbf0-11eb-8701-53a94f24f75b.png" align="middle">
5-
</center>
3+
<img width="406" hight="192" alt="json cache logo" src="https://user-images.githubusercontent.com/24878574/119276278-56ef4a80-bbf0-11eb-8701-53a94f24f75b.png" align="middle">
64

75
[![EO principles respected
86
here](https://www.elegantobjects.org/badge.svg)](https://www.elegantobjects.org)
@@ -28,6 +26,15 @@ Rultor.com](https://www.rultor.com/b/dartoos-dev/json_cache)](https://www.rultor
2826

2927
## Overview
3028

29+
30+
> Cache is a hardware or software component that stores data so that future
31+
> requests for that data can be served faster; the data stored in a cache might
32+
> be the result of an earlier computation or a copy of data stored elsewhere.
33+
>
34+
> [Cache_(computing) (2021, August 22). In Wikipedia, The Free Encyclopedia.
35+
> Retrieved 09:55, August 22,
36+
> 2021](https://en.wikipedia.org/wiki/Cache_(computing))
37+
3138
**Json Cache** is an object-oriented package to cache user data locally in json.
3239
It can also be thought of as a layer on top of Flutter's local storage packages
3340
like [sharable_preferences](https://pub.dev/packages/shared_preferences) and
@@ -57,16 +64,17 @@ abstract class JsonCache {
5764
/// Frees up storage space.
5865
Future<void> clear();
5966
60-
/// Updates data at [key] or creates a new cache line at [key] if there is no
61-
/// previous data there.
62-
Future<void> refresh(String key, Map<String, dynamic> data);
67+
/// It either updates the data found at [key] with [value] or, if there is no
68+
/// previous data at [key], creates a new cache row at [key] with [value].
69+
///
70+
/// **Note**: [value] must be json encodable.
71+
Future<void> refresh(String key, Map<String, dynamic> value);
6372
64-
/// Removes data from cache at [key] and returns it or returns null if there
65-
/// is no data at [key].
66-
Future<Map<String, dynamic>?> erase(String key);
73+
/// Removes data from cache at [key].
74+
Future<void> remove(String key);
6775
68-
/// Retrieves either the data at [key] or null if a cache miss occurs.
69-
Future<Map<String, dynamic>?> recover(String key);
76+
/// Retrieves the data value at [key] or null if a cache miss occurs.
77+
Future<Map<String, dynamic>?> value(String key);
7078
}
7179
```
7280

@@ -82,7 +90,24 @@ represents the name of a single data group. For example:
8290
Above, the _profile_ key is associated with the profile-related data group,
8391
while the _preferences_ key is associated with the preferences-related data.
8492

85-
<!-- @todo #10 Some implementation is needed to add more examples -->
93+
### JsonCacheMem
94+
95+
It is a thread-safe, in-memory implementation of the `JsonCache` interface.
96+
Moreover, it encapsulates a secondary cache or "slower level2 cache". Typically,
97+
the secondary cache instance is responsible for the local cache; that is, it is
98+
the cache instance that persists data on the user's device.
99+
100+
#### JsonCacheMem Usage
101+
102+
Due to the fact that `JsonCacheMem` is a decorator, you should always pass
103+
another `JsonCache` instance when you instantiates it. For example:
104+
105+
```dart
106+
107+
final prefs = await SharedPreferences.getInstance();
108+
final JsonCacheMem jsonCache = JsonCacheMem(JsonCachePrefs(prefs));
109+
110+
```
86111

87112
## Demo application
88113

lib/json_cache.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ library json_cache;
44
export 'src/json_cache.dart';
55
export 'src/json_cache_fake.dart';
66
export 'src/json_cache_mem.dart';
7+
export 'src/json_cache_prefs.dart';
78
export 'src/json_cache_wrap.dart';

lib/src/json_cache.dart

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
/// Represents data cached in json.
2+
///
3+
///> Cache is a hardware or software component that stores data so that future
4+
///> requests for that data can be served faster; the data stored in a cache
5+
///> might be the result of an earlier computation or a copy of data stored
6+
///> elsewhere.
7+
///> — [cache Wikipedia](https://en.wikipedia.org/wiki/Cache_(computing))
28
abstract class JsonCache {
39
/// Frees up storage space.
410
Future<void> clear();
511

6-
/// Updates data at [key] or creates a new cache line at [key] if there is no
7-
/// previous data there.
8-
Future<void> refresh(String key, Map<String, dynamic> data);
12+
/// It either updates the data found at [key] with [value] or, if there is no
13+
/// previous data at [key], creates a new cache row at [key] with [value].
14+
///
15+
/// **Note**: [value] must be json encodable.
16+
Future<void> refresh(String key, Map<String, dynamic> value);
917

10-
/// Removes data from cache at [key]. It returns the removed data or null if
11-
/// no removal was performed — there was no data at [key].
12-
Future<Map<String, dynamic>?> erase(String key);
18+
/// Removes data from cache at [key].
19+
Future<void> remove(String key);
1320

14-
/// Retrieves either the data at [key] or null if a cache miss occurs.
15-
Future<Map<String, dynamic>?> recover(String key);
21+
/// Retrieves the data value at [key] or null if a cache miss occurs.
22+
Future<Map<String, dynamic>?> value(String key);
1623
}

lib/src/json_cache_fake.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import 'package:json_cache/json_cache.dart';
44
///
55
/// **Warning**: do not use it in production code. It is not thread safe.
66
class JsonCacheFake implements JsonCache {
7-
/// Default ctor. Shares a static memory with other instances.
7+
/// It will share a static memory with other instances.
88
JsonCacheFake() : this.mem(_shrMem);
99

1010
/// Cache with custom memory.
@@ -26,12 +26,12 @@ class JsonCacheFake implements JsonCache {
2626

2727
/// Removes data located at [key].
2828
@override
29-
Future<Map<String, dynamic>?> erase(String key) async => _memory.remove(key);
29+
Future<void> remove(String key) async => _memory.remove(key);
3030

31-
/// Retrieves the data at [key] or null if there is no data.
31+
/// Retrieves a copy of the data at [key] or null if there is no data.
3232
@override
33-
Future<Map<String, dynamic>?> recover(String key) async {
33+
Future<Map<String, dynamic>?> value(String key) async {
3434
final cached = _memory[key];
35-
return cached == null ? cached : Map<String, dynamic>.of(cached);
35+
return cached == null ? null : Map<String, dynamic>.of(cached);
3636
}
3737
}

lib/src/json_cache_mem.dart

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,17 @@ import 'json_cache.dart';
1111
///
1212
/// It encapsulates a slower chache but keeps its own data in-memory.
1313
class JsonCacheMem implements JsonCache {
14-
/// Default ctor. [level2] the slower level 2 cache.
15-
JsonCacheMem(JsonCache level2) : this.main(level2, _shrMem, _shrMutex);
14+
/// Encapsulates a slower [level2] cache and utilizes a static memory that
15+
/// will be shared (without race conditions) among all [JsonCacheMem] objects
16+
/// that have been instantiated with this constructor.
17+
JsonCacheMem(JsonCache level2) : this.mem(level2, _shrMem, _shrMutex);
1618

17-
/// Cache with custom memory.
18-
JsonCacheMem.mem(JsonCache level2, Map<String, Map<String, dynamic>?> mem)
19-
: this.main(level2, mem, ReadWriteMutex());
20-
21-
/// Main ctor.
22-
JsonCacheMem.main(
23-
JsonCache level2,
24-
Map<String, Map<String, dynamic>?> mem,
25-
ReadWriteMutex mutex,
26-
) : _level2 = level2,
19+
/// Cache with custom memory and an optional custom mutex.
20+
JsonCacheMem.mem(JsonCache level2, Map<String, Map<String, dynamic>?> mem,
21+
[ReadWriteMutex? mutex])
22+
: _level2 = level2,
2723
_memory = mem,
28-
_mutex = mutex;
24+
_mutex = mutex ?? ReadWriteMutex();
2925

3026
/// Slower cache level.
3127
final JsonCache _level2;
@@ -70,22 +66,22 @@ class JsonCacheMem implements JsonCache {
7066
});
7167
}
7268

73-
/// Removes data located at [key] from both the level2 cache and in-memory
74-
/// cache.
69+
/// Removes the value located at [key] from both the level2 cache and
70+
/// in-memory cache.
7571
@override
76-
Future<Map<String, dynamic>?> erase(String key) async {
77-
return _mutex.protectWrite(() async {
78-
await _level2.erase(key);
79-
return _memory.remove(key);
72+
Future<void> remove(String key) async {
73+
await _mutex.protectWrite(() async {
74+
await _level2.remove(key);
75+
_memory.remove(key);
8076
});
8177
}
8278

83-
/// Retrieves the data at [key] or null if there is no data.
79+
/// Retrieves the value at [key] or null if there is no data.
8480
@override
85-
Future<Map<String, dynamic>?> recover(String key) async {
81+
Future<Map<String, dynamic>?> value(String key) async {
8682
return _mutex.protectRead(() async {
8783
if (!_memory.containsKey(key)) {
88-
_memory[key] = await _level2.recover(key);
84+
_memory[key] = await _level2.value(key);
8985
}
9086
final cached = _memory[key];
9187
return cached == null ? cached : Map<String, dynamic>.of(cached);

lib/src/json_cache_prefs.dart

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import 'dart:convert';
2+
3+
import 'package:shared_preferences/shared_preferences.dart';
4+
5+
import 'json_cache.dart';
6+
7+
/// Persistent preferences file cache.
8+
class JsonCachePrefs implements JsonCache {
9+
/// [_prefs] a [SharedPreferences] instance.
10+
const JsonCachePrefs(this._prefs);
11+
12+
// The preferences file object.
13+
final SharedPreferences _prefs;
14+
15+
/// Frees up the preferences file space.
16+
@override
17+
Future<void> clear() async {
18+
await _prefs.clear();
19+
}
20+
21+
/// Removes an entry from the preferences file storage at [key].
22+
@override
23+
Future<void> remove(String key) async {
24+
await _prefs.remove(key);
25+
}
26+
27+
/// Writes [value] to the preferences file.
28+
///
29+
/// **Note**: [value] must be json encodable — `json.encode()` is called under
30+
/// the hood.
31+
@override
32+
Future<void> refresh(String key, Map<String, dynamic> value) async {
33+
await _prefs.setString(key, json.encode(value));
34+
}
35+
36+
/// The value at [key] from the preferences file; it returns null if a cache
37+
/// miss occurs.
38+
@override
39+
Future<Map<String, dynamic>?> value(String key) async {
40+
final strJson = _prefs.getString(key);
41+
return strJson == null
42+
? null
43+
: json.decode(strJson) as Map<String, dynamic>;
44+
}
45+
}

lib/src/json_cache_wrap.dart

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,25 @@ import 'json_cache.dart';
44
///
55
/// It just forwards method calls to its encapsulated [JsonCache] instance.
66
abstract class JsonCacheWrap implements JsonCache {
7-
/// Ctor.
7+
/// Encapsulates a [JsonCache] instance.
88
const JsonCacheWrap(this._wrapped);
99

1010
// wrapped instance.
1111
final JsonCache _wrapped;
1212

13-
/// Forwards to its encapsulated [JsonCache] instance.
13+
/// Forwards to the [JsonCache.clear] of its wrapped instance.
1414
@override
1515
Future<void> clear() => _wrapped.clear();
1616

17-
/// Forwards to its encapsulated [JsonCache] instance.
17+
/// Forwards to the [JsonCache.remove] of its wrapped instance.
1818
@override
19-
Future<Map<String, dynamic>?> erase(String key) => _wrapped.erase(key);
19+
Future<void> remove(String key) => _wrapped.remove(key);
2020

21-
/// Forwards to its encapsulated [JsonCache] instance.
21+
/// Forwards to the [JsonCache.value] of its wrapped instance.
2222
@override
23-
Future<Map<String, dynamic>?> recover(String key) => _wrapped.recover(key);
23+
Future<Map<String, dynamic>?> value(String key) => _wrapped.value(key);
2424

25-
/// Forwards to its encapsulated [JsonCache] instance.
25+
/// Forwards to the [JsonCache.refresh] of its wrapped instance.
2626
@override
2727
Future<void> refresh(String key, Map<String, dynamic> data) =>
2828
_wrapped.refresh(key, data);

0 commit comments

Comments
 (0)