Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: cache peek should respect target method ttl #118

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
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);
}
Loading