Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

<!-- @todo #1 Describe initial release. -->
## [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
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions lib/src/json_cache.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ abstract class JsonCache {
/// previous data there.
Future<void> refresh(String key, Map<String, dynamic> 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<Map<String, dynamic>?> erase(String key);

/// Retrieves either the data at [key] or null if a cache miss occurs.
Expand Down
2 changes: 1 addition & 1 deletion lib/src/json_cache_fake.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class JsonCacheFake implements JsonCache {
/// in-memory storage.
final Map<String, Map<String, dynamic>?> _memory;

static final Map<String, Map<String, dynamic>> _shrMem = {};
static late final Map<String, Map<String, dynamic>?> _shrMem = {};

/// Clears the internal map.
@override
Expand Down
4 changes: 2 additions & 2 deletions lib/src/json_cache_mem.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ class JsonCacheMem implements JsonCache {
final ReadWriteMutex _mutex;

/// in-memory shared storage.
static final Map<String, Map<String, dynamic>> _shrMem = {};
static late final Map<String, Map<String, dynamic>?> _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
Expand Down
50 changes: 46 additions & 4 deletions test/json_cache_mem_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,54 @@ import 'package:json_cache/json_cache.dart';

void main() {
group('JsonCacheMem', () {
test('clear', () async {
const profKey = 'profile';
const Map<String, dynamic> profData = <String, dynamic>{
'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<String, Map<String, dynamic>?> copy = {
profKey: Map<String, dynamic>.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 = <String, dynamic>{'id': 1, 'name': 'John Due'};
final prefs = <String, dynamic>{
'preferences': <String, dynamic>{
'theme': 'dark',
'notifications': {'enabled': true}
}
};
final Map<String, Map<String, dynamic>> data = {
'profile': <String, dynamic>{'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);
});
});
}
48 changes: 47 additions & 1 deletion test/json_cache_wrap_test.dart
Original file line number Diff line number Diff line change
@@ -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<String, dynamic> profData = <String, dynamic>{
'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 = <String, dynamic>{'id': 1, 'name': 'John Due'};
final prefs = <String, dynamic>{
'preferences': <String, dynamic>{
'theme': 'dark',
'notifications': {'enabled': true}
}
};
final Map<String, Map<String, dynamic>> 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);
});
});
}