CacheService example
This commit is contained in:
parent
65d914f5aa
commit
7f1fe992cf
4 changed files with 127 additions and 2 deletions
7
.idea/runConfigurations/cache_service_dart.xml
Normal file
7
.idea/runConfigurations/cache_service_dart.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="cache_service.dart" type="DartCommandLineRunConfigurationType" factoryName="Dart Command Line Application" singleton="true" nameIsGenerated="true">
|
||||
<option name="filePath" value="$PROJECT_DIR$/example/cache_service.dart" />
|
||||
<option name="workingDirectory" value="$PROJECT_DIR$" />
|
||||
<method />
|
||||
</configuration>
|
||||
</component>
|
|
@ -1 +1,3 @@
|
|||
language: dart
|
||||
language: dart
|
||||
dart:
|
||||
- dev
|
25
example/cache_service.dart
Normal file
25
example/cache_service.dart
Normal file
|
@ -0,0 +1,25 @@
|
|||
import 'package:angel_cache/angel_cache.dart';
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
|
||||
main() async {
|
||||
var app = new Angel()..lazyParseBodies = true;
|
||||
|
||||
app.use(
|
||||
'/api/todos',
|
||||
new CacheService(
|
||||
database: new AnonymousService(
|
||||
index: ([params]) {
|
||||
print('Fetched directly from the underlying service at ${new DateTime.now()}!');
|
||||
return ['foo', 'bar', 'baz'];
|
||||
},
|
||||
read: (id, [params]) {
|
||||
return {id: '$id at ${new DateTime.now()}'};
|
||||
}
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
var http = new AngelHttp(app);
|
||||
var server = await http.startServer('127.0.0.1', 3000);
|
||||
print('Listening at http://${server.address.address}:${server.port}');
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import 'dart:async';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
|
@ -15,28 +16,118 @@ class CacheService extends Service {
|
|||
/// If not provided, this defaults to a [MapService].
|
||||
final Service cache;
|
||||
|
||||
CacheService({@required this.database, Service cache})
|
||||
final bool ignoreQuery;
|
||||
|
||||
final Duration timeout;
|
||||
|
||||
final Map<dynamic, _CachedItem> _cache = {};
|
||||
_CachedItem _indexed;
|
||||
|
||||
CacheService(
|
||||
{@required this.database,
|
||||
Service cache,
|
||||
this.ignoreQuery: false,
|
||||
this.timeout})
|
||||
: this.cache = cache ?? new MapService() {
|
||||
assert(database != null);
|
||||
}
|
||||
|
||||
Future _getCached(Map params, _CachedItem get(), Future getFresh(),
|
||||
Future getCached(), Future save(data, DateTime now)) async {
|
||||
var cached = get();
|
||||
//print('$params => $cached');
|
||||
var now = new DateTime.now().toUtc();
|
||||
|
||||
if (cached != null) {
|
||||
// If the entry has expired, don't send from the cache
|
||||
var expired =
|
||||
timeout != null && now.difference(cached.timestamp) >= timeout;
|
||||
|
||||
if (timeout == null || !expired) {
|
||||
// Read from the cache if necessary
|
||||
var queryEqual = ignoreQuery == true ||
|
||||
(params != null &&
|
||||
cached.params != null &&
|
||||
const MapEquality()
|
||||
.equals(params['query'], cached.params['query']));
|
||||
if (queryEqual) {
|
||||
return await getCached();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we haven't fetched from the cache by this point,
|
||||
// let's fetch from the database.
|
||||
var data = await getFresh();
|
||||
await save(data, now);
|
||||
return data;
|
||||
}
|
||||
|
||||
@override
|
||||
Future index([Map params]) {
|
||||
return _getCached(
|
||||
params,
|
||||
() => _indexed,
|
||||
() => database.index(params),
|
||||
() => _indexed.data,
|
||||
(data, now) async {
|
||||
_indexed = new _CachedItem(params, now, data);
|
||||
return data;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future read(id, [Map params]) async {
|
||||
return _getCached(
|
||||
params,
|
||||
() => _cache[id],
|
||||
() => database.read(id, params),
|
||||
() => cache.read(id),
|
||||
(data, now) async {
|
||||
_cache[id] = new _CachedItem(params, now);
|
||||
return await cache.modify(id, data);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future create(data, [Map params]) {
|
||||
_indexed = null;
|
||||
return database.create(data, params);
|
||||
}
|
||||
|
||||
@override
|
||||
Future modify(id, data, [Map params]) {
|
||||
_indexed = null;
|
||||
_cache.remove(id);
|
||||
return database.modify(id, data, params);
|
||||
}
|
||||
|
||||
@override
|
||||
Future update(id, data, [Map params]) {
|
||||
_indexed = null;
|
||||
_cache.remove(id);
|
||||
return database.modify(id, data, params);
|
||||
}
|
||||
|
||||
@override
|
||||
Future remove(id, [Map params]) {
|
||||
_indexed = null;
|
||||
_cache.remove(id);
|
||||
return database.remove(id, params);
|
||||
}
|
||||
}
|
||||
|
||||
class _CachedItem {
|
||||
final params;
|
||||
final DateTime timestamp;
|
||||
final data;
|
||||
|
||||
_CachedItem(this.params, this.timestamp, [this.data]);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '$timestamp:$params:$data';
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue