Skip to content

Commit

Permalink
bug fix and isEmpty & isNotEmpty feature added
Browse files Browse the repository at this point in the history
  • Loading branch information
gokberkbar committed Aug 10, 2022
1 parent f5c740b commit 2ef2a16
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 19 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 1.1.0

- `isEmpty` & `isNotEmpty` features added.
- Some bug fixes.

---

## 1.0.0

- Initial version.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ $ flutter pub add memory_cache
This will add a line like this to your package's pubspec.yaml (and run an implicit `dart pub get` or `flutter pub get`):
```
dependencies:
memory_cache: ^1.0.0
memory_cache: ^1.1.0
```

## Usage
Expand Down
51 changes: 35 additions & 16 deletions lib/src/cache.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,21 @@ class MemoryCache {
/// internal cache
final Map<String, CacheItem> _cache = {};

/// Checks if cache is empty.
bool get isEmpty {
_cache.removeWhere((key, value) => _isExpired(value));
return _cache.isEmpty;
}

/// Checks if cache is not empty.
bool get isNotEmpty => !isEmpty;

/// If cache contains a value for the [key], returns the value.
/// If cache does not contains a value for the [key], returns null.
T? read<T>(String key) {
if (_cache.containsKey(key)) {
if (_expiryAwareContains(key)) {
final item = _cache[key]!;
if (item.expiry != null && item.expiry!.isBefore(DateTime.now())) {
delete(key);
return null;
} else {
return item.value;
}
return item.value;
}
return null;
}
Expand All @@ -32,23 +36,17 @@ class MemoryCache {
/// If cache does not contains a value for the [key], sets the [value] to the cache and returns true.
/// If cache contains a value for the [key], returns false.
bool createIfAbsent<T>(String key, T value, {Duration? expiry}) {
if (!_cache.containsKey(key)) {
if (!_expiryAwareContains(key)) {
create(key, value, expiry: expiry);
return true;
} else {
final item = _cache[key]!;
if (item.expiry != null && item.expiry!.isBefore(DateTime.now())) {
create(key, value, expiry: expiry);
return true;
}
}
return false;
}

/// If cache contains a value for the [key], updates the value on the cache and returns true.
/// If cache does not contains a value for the [key], returns false.
bool update<T>(String key, T value, {Duration? expiry}) {
if (_cache.containsKey(key)) {
if (_expiryAwareContains(key)) {
_cache[key] = _cache[key]!.copyWith(
value: value,
expiry: _setExpiry(expiry),
Expand All @@ -70,10 +68,31 @@ class MemoryCache {

/// Returns true if cached value exists.
bool contains(String key) {
return _cache.containsKey(key);
return _expiryAwareContains(key);
}

/// Adds [expiry] to DateTime.now() and returns it.
DateTime? _setExpiry(Duration? expiry) =>
expiry != null ? DateTime.now().add(expiry) : null;

/// Checks if [item] is expired.
bool _isExpired(CacheItem item) {
if (item.expiry != null && item.expiry!.isBefore(DateTime.now())) {
return true;
}
return false;
}

/// Returns true if cached value exists but not expired.
/// If cached value expired removes from cache.
bool _expiryAwareContains(String key) {
final item = _cache[key];
if (item == null) {
return false;
} else if (_isExpired(item)) {
delete(key);
return false;
}
return true;
}
}
5 changes: 3 additions & 2 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: memory_cache
description: Memory Cache is simple, fast and global in-memory cache.
version: 1.0.0
description: Memory Cache is simple, fast and global in-memory cache with CRUD features.
version: 1.1.0
repository: https://github.com/gokberkbar/memory_cache

environment:
Expand All @@ -9,3 +9,4 @@ environment:
dev_dependencies:
lints: ^2.0.0
test: ^1.16.0
analyzer: ^4.5.0
95 changes: 95 additions & 0 deletions test/memory_cache_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import 'package:memory_cache/memory_cache.dart';
import 'package:test/test.dart';

void main() {
group('CRUD Operations', () {
final key = 'key0';
final value = 'value0';

setUpAll(() {
MemoryCache.instance.invalidate();
MemoryCache.instance.create(key, value);
});

test('is item created', () {
expect(MemoryCache.instance.contains(key), true);
});

test('read item', () {
final cachedValue = MemoryCache.instance.read<String>(key);
expect(cachedValue, value);
});

test('create if item is absent', () {
final newValue = 'key1';
final newKey = 'value1';
final isCreated = MemoryCache.instance.createIfAbsent(key, newValue);
expect(isCreated, false);
final isNewValueCreated =
MemoryCache.instance.createIfAbsent(newKey, newValue);
expect(isNewValueCreated, true);
});

test('update item', () {
final newValue = 'updatedValue';
final isUpdated = MemoryCache.instance.update<String>(key, newValue);
expect(isUpdated, true);
final cachedValue = MemoryCache.instance.read<String>(key);
expect(cachedValue, newValue);
});

test('delete item', () {
MemoryCache.instance.delete(key);
expect(MemoryCache.instance.contains(key), false);
});

test('expire item', () async {
MemoryCache.instance
.create<String>(key, value, expiry: Duration(seconds: 1));
await Future.delayed(Duration(seconds: 2));
final isValueExist = MemoryCache.instance.contains(key);
expect(isValueExist, false);
});

test('createIfAbsent test on expired item', () async {
MemoryCache.instance
.create<String>(key, value, expiry: Duration(seconds: 1));
await Future.delayed(Duration(seconds: 2));
final isValueCreated =
MemoryCache.instance.createIfAbsent('newKey', 'newItem');
expect(isValueCreated, true);
});

test('re-create item with expiry', () async {
final newKey = 'newKey';
final item = 'item';
final newItem = 'newItem';

MemoryCache.instance
.create<String>(newKey, item, expiry: Duration(seconds: 1));
MemoryCache.instance
.create<String>(newKey, newItem, expiry: Duration(seconds: 5));
await Future.delayed(Duration(seconds: 2));
final value = MemoryCache.instance.read<String>(newKey);
expect(value, newItem);
});

test('update expired item', () async {
final newKey = 'newKey';
final item = 'item';
final newItem = 'newItem';

MemoryCache.instance
.create<String>(newKey, item, expiry: Duration(seconds: 1));
await Future.delayed(Duration(seconds: 2));
final isUpdated = MemoryCache.instance.update<String>(newKey, newItem);
expect(isUpdated, false);
});

test('check if cache is empty', () async {
MemoryCache.instance.invalidate();
final isEmpty = MemoryCache.instance.isEmpty;
expect(isEmpty, true);
});
});
}

0 comments on commit 2ef2a16

Please sign in to comment.