Skip to content

Commit

Permalink
fix: cache peek should respect target method ttl
Browse files Browse the repository at this point in the history
  • Loading branch information
mateuszfilipek2000 committed Sep 27, 2024
1 parent 100bc08 commit e42efed
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 0 deletions.
8 changes: 8 additions & 0 deletions packages/cached/example/cached_example/bin/gen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,14 @@ abstract mixin class Gen implements _$Gen {
/// Method with this annotation will clear cached values for all methods.
@clearAllCached
void clearAllCache();

@Cached(ttl: 20)
Future<int?> cachedMethodWithTtl(int x) async {
return 3;
}

@CachePeek('cachedMethodWithTtl')
int? peekCachedMethodWithTtl(int x);
}

Future<bool> _shouldCache(Response response) async {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ Future<void> main(List<String> arguments) async {
// await gen.clearTodos();

await _fetchTodos(gen);

await gen.getTodosWithTtl();

final todosPeek = gen.peekMethodWithTtl();
final maybeFirst5Todos = todosPeek?.sublist(0, 5);
print('Peeked todos: $maybeFirst5Todos');

await Future<void>.delayed(const Duration(seconds: 6));

final todosPeekAfterTtl = gen.peekMethodWithTtl();
final maybeFirst5TodosAfterTtl = todosPeekAfterTtl?.sublist(0, 5);
print('Peeked todos after TTL: $maybeFirst5TodosAfterTtl');
}

Future<void> _fetchTodos(Gen gen) async {
Expand Down
15 changes: 15 additions & 0 deletions packages/cached/example/persistent_storage_example/bin/gen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ abstract mixin class Gen implements _$Gen {
return decodedBody.map<Todo>((e) => Todo.fromJson(e)).toList();
}

@PersistentCached(ttl: 5)
Future<List<Todo>> getTodosWithTtl() async {
final uri = Uri.parse(_url);
final response = await http.get(uri);
final decodedBody = jsonDecode(response.body);

return decodedBody.map<Todo>((e) => Todo.fromJson(e)).toList();
}

/// We will pass only a [directPersistentStorage]
/// here becouse you can not use any params combination
@DirectPersistentCached()
Expand All @@ -59,4 +68,10 @@ abstract mixin class Gen implements _$Gen {
Future<void> clearTodos() async {
print('Deleting todos from database...');
}

@CachePeek('getTodos')
List<Todo>? peekMethodWithoutTtl();

@CachePeek('getTodosWithTtl')
List<Todo>? peekMethodWithTtl();
}
15 changes: 15 additions & 0 deletions packages/cached/lib/src/models/cache_peek_method.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:analyzer/dart/constant/value.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:cached/src/config.dart';
import 'package:cached/src/models/cached_function_local_config.dart';
import 'package:cached/src/models/param.dart';
import 'package:cached_annotation/cached_annotation.dart';
import 'package:collection/collection.dart';
Expand All @@ -14,6 +15,7 @@ class CachePeekMethod {
required this.targetMethodName,
required this.returnType,
required this.params,
required this.targetHasTtl,
});

factory CachePeekMethod.fromElement(
Expand Down Expand Up @@ -110,18 +112,31 @@ class CachePeekMethod {
);
}

bool targetMethodHasTtl = false;

try {
final targetLocalConfig =
CachedFunctionLocalConfig.fromElement(targetMethod);
targetMethodHasTtl = targetLocalConfig.ttl != null;
} catch (e) {
print(e);
// ignore
}

return CachePeekMethod(
name: element.name,
returnType: peekCacheMethodTypeStr,
params: targetMethodParameters.map((p) => Param.fromElement(p, config)),
targetMethodName: methodName,
targetHasTtl: targetMethodHasTtl,
);
}

final String name;
final String targetMethodName;
final Iterable<Param> params;
final String returnType;
final bool targetHasTtl;

static DartObject? getAnnotation(MethodElement element) {
const methodAnnotationChecker = TypeChecker.fromRuntime(CachePeek);
Expand Down
16 changes: 16 additions & 0 deletions packages/cached/lib/src/templates/cache_peek_method_template.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,32 @@ class CachePeekMethodTemplate {
final String className;
final AllParamsTemplate paramsTemplate;

String get _ttlMapName => getTtlMapName(method.targetMethodName);

String generateMethod() {
final params = paramsTemplate.generateParams();
final paramKey = getParamKey(method.params);
final cacheMapName = getCacheMapName(method.targetMethodName);

final returnNullIfExpired = method.targetHasTtl
? '''
final now = DateTime.now();
final cachedTtl = $_ttlMapName[paramsKey];
final currentTtl = cachedTtl != null ? DateTime.parse(cachedTtl) : null;
if (currentTtl != null && currentTtl.isBefore(now)) {
return null;
}
'''
: '';

return '''
@override
${method.returnType}? ${method.name}($params) {
final paramsKey = "$paramKey";
$returnNullIfExpired
return $cacheMapName[paramsKey];
}
''';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,9 @@ class _StaticCache with StaticCache implements _$StaticCache {
_StaticCache();
static final _cachedMethodCached = <String, int?>{};
static final _cachedMethodWithTtlCached = <String, int?>{};
static final _cachedMethodWithTtlTtl = <String, String>{};
@override
Future<int?> cachedMethod(int x) async {
Expand All @@ -388,12 +391,61 @@ class _StaticCache with StaticCache implements _$StaticCache {
}
}
@override
Future<int?> cachedMethodWithTtl(int x) async {
final now = DateTime.now();
final cachedTtl = _cachedMethodWithTtlTtl["${x.hashCode}"];
final currentTtl = cachedTtl != null ? DateTime.parse(cachedTtl) : null;
if (currentTtl != null && currentTtl.isBefore(now)) {
_cachedMethodWithTtlTtl.remove("${x.hashCode}");
_cachedMethodWithTtlCached.remove("${x.hashCode}");
}
final cachedValue = _cachedMethodWithTtlCached["${x.hashCode}"];
if (cachedValue == null) {
final int? toReturn;
try {
final result = super.cachedMethodWithTtl(x);
toReturn = await result;
} catch (_) {
rethrow;
} finally {}
_cachedMethodWithTtlCached["${x.hashCode}"] = toReturn;
const duration = Duration(seconds: 20);
_cachedMethodWithTtlTtl["${x.hashCode}"] =
DateTime.now().add(duration).toIso8601String();
return toReturn;
} else {
return cachedValue;
}
}
@override
int? cachedPeek(int x) {
final paramsKey = "${x.hashCode}";
return _cachedMethodCached[paramsKey];
}
@override
int? cachedPeekWithTtl(int x) {
final paramsKey = "${x.hashCode}";
final now = DateTime.now();
final cachedTtl = _cachedMethodWithTtlTtl[paramsKey];
final currentTtl = cachedTtl != null ? DateTime.parse(cachedTtl) : null;
if (currentTtl != null && currentTtl.isBefore(now)) {
return null;
}
return _cachedMethodWithTtlCached[paramsKey];
}
}
''')
@WithCache(useStaticCache: true)
Expand All @@ -405,6 +457,14 @@ abstract class StaticCache {
return y;
}

@Cached(ttl: 20)
Future<int?> cachedMethodWithTtl(int x) {
return y;
}

@CachePeek("cachedMethod")
int? cachedPeek(int x);

@CachePeek("cachedMethodWithTtl")
int? cachedPeekWithTtl(int x);
}

0 comments on commit e42efed

Please sign in to comment.