Skip to content

Commit

Permalink
feat(ferr_cache): add evict operation
Browse files Browse the repository at this point in the history
  • Loading branch information
knaeckeKami committed Jan 6, 2025
1 parent f74599b commit bef3417
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 21 deletions.
69 changes: 49 additions & 20 deletions packages/ferry_cache/lib/src/cache.dart
Original file line number Diff line number Diff line change
Expand Up @@ -310,12 +310,9 @@ class Cache {
}
}

void _evictField(
String entityId,
String fieldName,
Map<String, dynamic> args,
OperationRequest? optimisticRequest,
) {
void _evictField(String entityId, String fieldName, Map<String, dynamic> args,
OperationRequest? optimisticRequest,
[bool eraseCompletely = false]) {
if (optimisticRequest != null) {
/// Set field to `null` in optimistic patch
optimisticPatchesStream.add({
Expand Down Expand Up @@ -349,25 +346,57 @@ class Cache {

final entity = store.get(entityId);
if (entity != null) {
store.put(
entityId,
entity.map(
// NOTE: we need to set to null rather than removing altogether
// to ensure that denormalize doesn't throw a [PartialDataException]
(key, value) => _fieldMatch(
key,
fieldName,
args,
)
? MapEntry(key, null)
: MapEntry(key, value),
),
);
if (eraseCompletely) {
store.put(
entityId,
{
for (final key in entity.keys)
if (!_fieldMatch(key, fieldName, args)) key: entity[key],
},
);
} else {
store.put(
entityId,
entity.map(
// NOTE: we need to set to null rather than removing altogether
// to ensure that denormalize doesn't throw a [PartialDataException]
(key, value) => _fieldMatch(
key,
fieldName,
args,
)
? MapEntry(key, null)
: MapEntry(key, value),
),
);
}
}
_eventStream.add(null);
}
}

/// Evicts all top-level fields from that operation from the cache.
/// Consider calling after this gc() to completely remove orphaned entities.
void evictOperation<TData, TVars>(OperationRequest<TData, TVars> request) {
final operationDefinition = utils.getOperationDefinition(
request.operation.document, request.operation.operationName);
final rootTypeName =
utils.resolveRootTypename(operationDefinition, typePolicies);

final fields = utils.operationFieldNames(
request.operation.document,
request.operation.operationName,
request.varsToJson(),
typePolicies,
possibleTypes,
);

for (final field in fields) {
final fieldKey = utils.FieldKey.parse(field);
_evictField(rootTypeName, fieldKey.fieldName, fieldKey.args, null, true);
}
}

bool _fieldMatch(
String keyString,
String fieldName,
Expand Down
2 changes: 1 addition & 1 deletion packages/ferry_cache/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ dependencies:
pedantic: ^1.11.0
dev_dependencies:
test: ^1.16.8
ferry_test_graphql2: ^0.4.0
ferry_test_graphql2:
gql_exec: ^1.0.0
gql: ^1.0.0
gql_tristate_value: ^1.0.0
47 changes: 47 additions & 0 deletions packages/ferry_cache/test/eviction_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ void main() {
hanReq.rebuild((b) => b..vars.friendsAfter = 'chewie'),
hanData,
);

final entityId = cache.identify(hanData.human)!;
final keyLuke =
FieldKey.from('friendsConnection', {'first': 10, 'after': 'luke'});
Expand Down Expand Up @@ -170,4 +171,50 @@ void main() {
expect(cache.store.get('Human:chewie'), isNull);
});
});

group('evictOperation', () {
test('can evict Operation', () {
final cache = Cache();
addTearDown(() {
cache.dispose();
});
cache.writeQuery(
hanReq,
hanData,
);

cache.evictOperation(hanReq);

expect(cache.readQuery(hanReq), equals(null));

final gcResult = cache.gc();

expect(gcResult, equals({'Human:luke', 'Human:chewie', 'Human:han'}));

expect(cache.store.get('Query'), equals({'__typename': 'Query'}));

expect(cache.store.keys, equals({'Query'}));
});

test('only evicts given operation', () {
final cache = Cache();
addTearDown(() {
cache.dispose();
});
cache.writeQuery(
hanReq,
hanData,
);

cache.writeQuery(
chewieReq,
chewieData,
);

cache.evictOperation(hanReq);

expect(cache.readQuery(hanReq), equals(null));
expect(cache.readQuery(chewieReq), equals(chewieData));
});
});
}

0 comments on commit bef3417

Please sign in to comment.