Skip to content

Commit a91a59d

Browse files
author
Kinpert
committed
feat: JsonCacheSafeLocalStorage class
1 parent b0882fe commit a91a59d

File tree

5 files changed

+167
-1
lines changed

5 files changed

+167
-1
lines changed

CHANGELOG.md

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

88
## [Unreleased]
99

10+
### Added
11+
12+
- JsonCacheSafeLocalStorage: an implementation on top of the safe_local_storage package - [124](https://github.com/dartoos-dev/json_cache/issues/124).
13+
1014
## [2.0.0] - 2023-03-22
1115

1216
### Changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// ignore_for_file: avoid_dynamic_calls
2+
3+
import 'package:json_cache/json_cache.dart';
4+
import 'package:safe_local_storage/safe_local_storage.dart';
5+
6+
/// Implementation on top of the SafeLocalStorage package.
7+
///
8+
/// See: [Safe local storage](https://pub.dev/packages/safe_local_storage)
9+
class JsonCacheSafeLocalStorage implements JsonCache {
10+
/// Encapsulates a [SafeLocalStorage] instance.
11+
const JsonCacheSafeLocalStorage(this._localStorage);
12+
13+
final SafeLocalStorage _localStorage;
14+
15+
@override
16+
Future<void> clear() async {
17+
await _localStorage.delete();
18+
}
19+
20+
@override
21+
Future<bool> contains(String key) async {
22+
final item = await _localStorage.read();
23+
return item[key] != null;
24+
}
25+
26+
@override
27+
Future<void> refresh(String key, Map<String, dynamic> value) async {
28+
final data = {key: value};
29+
await _localStorage.write(data);
30+
}
31+
32+
@override
33+
Future<void> remove(String key) async {
34+
final data = await _localStorage.read() as Map<String, dynamic>;
35+
data.removeWhere((keyMap, valueMap) => keyMap == key);
36+
await _localStorage.write(data);
37+
}
38+
39+
@override
40+
Future<Map<String, dynamic>?> value(String key) async {
41+
final data = await _localStorage.read();
42+
return data[key] == null ? null : data[key] as Map<String, dynamic>;
43+
}
44+
}

pubspec.lock

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,14 @@ packages:
432432
url: "https://pub.dev"
433433
source: hosted
434434
version: "2.1.3"
435+
safe_local_storage:
436+
dependency: "direct main"
437+
description:
438+
name: safe_local_storage
439+
sha256: "7ca14be87040e6badfcdb9c71e963846c4e7d827dbc9f62cab7496497352f8d8"
440+
url: "https://pub.dev"
441+
source: hosted
442+
version: "1.0.0"
435443
shared_preferences:
436444
dependency: "direct main"
437445
description:
@@ -581,6 +589,14 @@ packages:
581589
url: "https://pub.dev"
582590
source: hosted
583591
version: "1.2.0"
592+
synchronized:
593+
dependency: transitive
594+
description:
595+
name: synchronized
596+
sha256: "33b31b6beb98100bf9add464a36a8dd03eb10c7a8cf15aeec535e9b054aaf04b"
597+
url: "https://pub.dev"
598+
source: hosted
599+
version: "3.0.1"
584600
term_glyph:
585601
dependency: transitive
586602
description:
@@ -686,5 +702,5 @@ packages:
686702
source: hosted
687703
version: "3.1.1"
688704
sdks:
689-
dart: ">=2.18.0 <3.0.0"
705+
dart: ">=2.18.0 <4.0.0"
690706
flutter: ">=3.0.0"

pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ dependencies:
1616
hive: ^2.2.3
1717
localstorage: ^4.0.1+2
1818
mutex: ^3.0.1
19+
safe_local_storage: ^1.0.0
1920
shared_preferences: ^2.0.18
2021

2122
dev_dependencies:
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import 'dart:io';
2+
import 'package:flutter_test/flutter_test.dart';
3+
import 'package:json_cache/src/json_cache_safe_local_storage.dart';
4+
import 'package:safe_local_storage/safe_local_storage.dart';
5+
6+
void main() {
7+
// Group of elements to 'mock' the temporary directory and file.
8+
late Directory tempDir;
9+
late File tempFile;
10+
11+
late SafeLocalStorage storage;
12+
13+
late JsonCacheSafeLocalStorage jsonCacheSafeLocalStorage;
14+
15+
// Profile data
16+
const profKey = 'profile';
17+
const profData = {
18+
'name': 'John Doe',
19+
'age': 23,
20+
'email': 'johndoe@example.com',
21+
};
22+
23+
// App preferences data
24+
const prefKey = 'preferences';
25+
const prefData = {
26+
'theme': 'light',
27+
'notifications': {'enabled': true}
28+
};
29+
30+
setUp(
31+
() async {
32+
tempDir = Directory.systemTemp;
33+
tempFile = File('${tempDir.path}/temp_file.json');
34+
storage = SafeLocalStorage(tempFile.path);
35+
jsonCacheSafeLocalStorage = JsonCacheSafeLocalStorage(storage);
36+
},
37+
);
38+
39+
group(
40+
'JsonCacheSafeLocalStorage',
41+
() {
42+
test(
43+
'refresh, value, clear, refresh',
44+
() async {
45+
await jsonCacheSafeLocalStorage.refresh(profKey, profData);
46+
47+
final data = await jsonCacheSafeLocalStorage.value(profKey);
48+
expect(data, profData);
49+
await jsonCacheSafeLocalStorage.clear();
50+
51+
final cleanCache = await jsonCacheSafeLocalStorage.value(profKey);
52+
expect(cleanCache, isNull);
53+
},
54+
);
55+
56+
test(
57+
'contains',
58+
() async {
59+
// Adding content on cache. Each 'refresh' method overrides the last one.
60+
await jsonCacheSafeLocalStorage.refresh(profKey, profData);
61+
await jsonCacheSafeLocalStorage.refresh(prefKey, prefData);
62+
63+
// Returning true if the last content exists on cache based on 'prefKey'.
64+
expect(await jsonCacheSafeLocalStorage.contains(prefKey), true);
65+
expect(await jsonCacheSafeLocalStorage.contains(profKey), false);
66+
67+
await jsonCacheSafeLocalStorage.refresh(profKey, profData);
68+
// Returning true if the last content exists on cache based on 'profKey'.
69+
expect(await jsonCacheSafeLocalStorage.contains(profKey), true);
70+
expect(await jsonCacheSafeLocalStorage.contains(prefKey), false);
71+
72+
// Test for keys that doesn't exist
73+
expect(await jsonCacheSafeLocalStorage.contains('generickey'), false);
74+
expect(await jsonCacheSafeLocalStorage.contains('PROFKEY'), false);
75+
expect(await jsonCacheSafeLocalStorage.contains('PREFKEY'), false);
76+
},
77+
);
78+
79+
test(
80+
'remove',
81+
() async {
82+
await jsonCacheSafeLocalStorage.refresh(profKey, profData);
83+
84+
final recoveredData = await jsonCacheSafeLocalStorage.value(profKey);
85+
expect(recoveredData, profData);
86+
87+
await jsonCacheSafeLocalStorage.remove(profKey);
88+
final cleanCache = await jsonCacheSafeLocalStorage.value(profKey);
89+
expect(cleanCache, isNull);
90+
},
91+
);
92+
},
93+
);
94+
95+
tearDown(
96+
() async {
97+
await storage.delete();
98+
await tempDir.delete_();
99+
},
100+
);
101+
}

0 commit comments

Comments
 (0)