diff --git a/src/common/api/worker/rest/DefaultEntityRestCache.ts b/src/common/api/worker/rest/DefaultEntityRestCache.ts index 820f0037d7c5..d129fb9d3475 100644 --- a/src/common/api/worker/rest/DefaultEntityRestCache.ts +++ b/src/common/api/worker/rest/DefaultEntityRestCache.ts @@ -747,7 +747,7 @@ export class DefaultEntityRestCache implements EntityRestCache { try { // loadMultiple is only called to cache the elements and check which ones return errors - const returnedInstances = await this._loadMultiple(typeRef, instanceListId, idsInCacheRange, undefined, { cacheMode: CacheMode.Bypass }) + const returnedInstances = await this._loadMultiple(typeRef, instanceListId, idsInCacheRange, undefined, { cacheMode: CacheMode.WriteOnly }) //We do not want to pass updates that caused an error if (returnedInstances.length !== idsInCacheRange.length) { const returnedIds = returnedInstances.map((instance) => getElementId(instance)) diff --git a/src/common/api/worker/rest/EntityRestClient.ts b/src/common/api/worker/rest/EntityRestClient.ts index 839cb32abb43..2974e8d8a1c9 100644 --- a/src/common/api/worker/rest/EntityRestClient.ts +++ b/src/common/api/worker/rest/EntityRestClient.ts @@ -54,27 +54,29 @@ export interface EntityRestClientUpdateOptions { * Use {@link getCacheModeBehavior} to programmatically check the behavior of the cache mode. */ export const enum CacheMode { - /** Prefer cached value if it's there or fall back to network. */ - Cache, + /** Prefer cached value if it's there, or fall back to network and write it to cache. */ + ReadAndWrite, + /** - * Prefer the value from network, do not fetch from cache. The entity will still be cached upon loading. + * Always retrieve from the network, but still save to cache. * - * NOTE: This cannot be used for ranged requests. + * NOTE: This cannot be used with ranged requests. */ - Bypass, - /** Prefer cached value, but in case of a cache miss, retrieve the value from network but don't write it to cache. */ + WriteOnly, + + /** Prefer cached value, but in case of a cache miss, retrieve the value from network without writing it to cache. */ ReadOnly, } /** * Get the behavior of the cache mode for the options - * @param cacheMode cache mode to check, or if `undefined`, check the default cache mode ({@link CacheMode.Cache}) + * @param cacheMode cache mode to check, or if `undefined`, check the default cache mode ({@link CacheMode.ReadAndWrite}) */ export function getCacheModeBehavior(cacheMode: CacheMode | undefined): { readsFromCache: boolean; writesToCache: boolean } { - switch (cacheMode ?? CacheMode.Cache) { - case CacheMode.Cache: + switch (cacheMode ?? CacheMode.ReadAndWrite) { + case CacheMode.ReadAndWrite: return { readsFromCache: true, writesToCache: true } - case CacheMode.Bypass: + case CacheMode.WriteOnly: return { readsFromCache: false, writesToCache: true } case CacheMode.ReadOnly: return { readsFromCache: true, writesToCache: false } @@ -86,7 +88,7 @@ export interface EntityRestClientLoadOptions { extraHeaders?: Dict /** Use the key provided by this to decrypt the existing ownerEncSessionKey instead of trying to resolve the owner key based on the ownerGroup. */ ownerKeyProvider?: OwnerKeyProvider - /** Defaults to {@link CacheMode.Cache }*/ + /** Defaults to {@link CacheMode.ReadAndWrite }*/ cacheMode?: CacheMode } diff --git a/src/mail-app/mail/view/MailViewModel.ts b/src/mail-app/mail/view/MailViewModel.ts index b65515295997..da75ced42369 100644 --- a/src/mail-app/mail/view/MailViewModel.ts +++ b/src/mail-app/mail/view/MailViewModel.ts @@ -266,7 +266,7 @@ export class MailViewModel { let mail: Mail | null try { - mail = await this.entityClient.load(MailTypeRef, [listId, mailId], { cacheMode: CacheMode.Bypass }) + mail = await this.entityClient.load(MailTypeRef, [listId, mailId], { cacheMode: CacheMode.WriteOnly }) } catch (e) { if (isOfflineError(e)) { return diff --git a/test/tests/api/worker/rest/EntityRestCacheTest.ts b/test/tests/api/worker/rest/EntityRestCacheTest.ts index 1976a844b5c0..543d79dd4be7 100644 --- a/test/tests/api/worker/rest/EntityRestCacheTest.ts +++ b/test/tests/api/worker/rest/EntityRestCacheTest.ts @@ -1729,22 +1729,22 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr when(client.load(ContactTypeRef, contactId, anything())).thenResolve(contactOnTheServer) const cache = new DefaultEntityRestCache(client, storage) - const cacheBypassed1 = await cache.load(ContactTypeRef, contactId, { cacheMode: CacheMode.Bypass }) + const cacheBypassed1 = await cache.load(ContactTypeRef, contactId, { cacheMode: CacheMode.WriteOnly }) o(cacheBypassed1).deepEquals(contactOnTheServer) // Fresh cache; should be loaded remotely and cached verify(client.load(ContactTypeRef, contactId, anything()), { times: 1 }) - const cacheBypassed2 = await cache.load(ContactTypeRef, contactId, { cacheMode: CacheMode.Bypass }) + const cacheBypassed2 = await cache.load(ContactTypeRef, contactId, { cacheMode: CacheMode.WriteOnly }) o(cacheBypassed2).deepEquals(contactOnTheServer) // Since we're bypassing it, it should still be loaded remotely (but still cached) verify(client.load(ContactTypeRef, contactId, anything()), { times: 2 }) - const cached = await cache.load(ContactTypeRef, contactId, { cacheMode: CacheMode.Cache }) + const cached = await cache.load(ContactTypeRef, contactId, { cacheMode: CacheMode.ReadAndWrite }) o(cached).deepEquals(contactOnTheServer) // We aren't bypassing it with Cache, so it should just use the cache verify(client.load(ContactTypeRef, contactId, anything()), { times: 2 }) - const cacheBypassed3 = await cache.load(ContactTypeRef, contactId, { cacheMode: CacheMode.Bypass }) + const cacheBypassed3 = await cache.load(ContactTypeRef, contactId, { cacheMode: CacheMode.WriteOnly }) o(cacheBypassed3).deepEquals(contactOnTheServer) // Bypassing again; should be loaded remotely verify(client.load(ContactTypeRef, contactId, anything()), { times: 3 }) @@ -1773,18 +1773,22 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr const cache = new DefaultEntityRestCache(client, storage) - const cacheBypassed1 = await cache.loadMultiple(ContactTypeRef, listId, [elementIdPart(contactAId)], undefined, { cacheMode: CacheMode.Bypass }) + const cacheBypassed1 = await cache.loadMultiple(ContactTypeRef, listId, [elementIdPart(contactAId)], undefined, { + cacheMode: CacheMode.WriteOnly, + }) o(cacheBypassed1).deepEquals([contactAOnTheServer]) // Fresh cache; should be loaded remotely and cached verify(client.loadMultiple(ContactTypeRef, listId, [elementIdPart(contactAId)], undefined, anything()), { times: 1 }) - const cacheBypassed2 = await cache.loadMultiple(ContactTypeRef, listId, [elementIdPart(contactAId)], undefined, { cacheMode: CacheMode.Bypass }) + const cacheBypassed2 = await cache.loadMultiple(ContactTypeRef, listId, [elementIdPart(contactAId)], undefined, { + cacheMode: CacheMode.WriteOnly, + }) o(cacheBypassed2).deepEquals([contactAOnTheServer]) // Still bypassing verify(client.loadMultiple(ContactTypeRef, listId, [elementIdPart(contactAId)], undefined, anything()), { times: 2 }) const cached = await cache.loadMultiple(ContactTypeRef, listId, [elementIdPart(contactAId), elementIdPart(contactBId)], undefined, { - cacheMode: CacheMode.Cache, + cacheMode: CacheMode.ReadAndWrite, }) o(true).equals(cached.some((a) => deepEqual(a, contactAOnTheServer))) o(true).equals(cached.some((b) => deepEqual(b, contactBOnTheServer))) @@ -1793,7 +1797,7 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr verify(client.loadMultiple(ContactTypeRef, listId, [elementIdPart(contactBId)], undefined, anything()), { times: 1 }) const cacheBypassed3 = await cache.loadMultiple(ContactTypeRef, listId, [elementIdPart(contactAId), elementIdPart(contactBId)], undefined, { - cacheMode: CacheMode.Bypass, + cacheMode: CacheMode.WriteOnly, }) o(cacheBypassed3).deepEquals([contactAOnTheServer, contactBOnTheServer]) // Bypassed again @@ -1825,7 +1829,7 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr // It wasn't cached before, so it should be loaded remotely again verify(client.load(ContactTypeRef, contactId, anything()), { times: 2 }) - const cached = await cache.load(ContactTypeRef, contactId, { cacheMode: CacheMode.Cache }) + const cached = await cache.load(ContactTypeRef, contactId, { cacheMode: CacheMode.ReadAndWrite }) o(cached).deepEquals(contactOnTheServer) // Again, it wasn't cached before, so it should be loaded remotely again verify(client.load(ContactTypeRef, contactId, anything()), { times: 3 }) @@ -1862,7 +1866,7 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr // Fresh cache; should be loaded remotely and cached verify(client.loadMultiple(ContactTypeRef, listId, [elementIdPart(contactAId)], undefined, anything()), { times: 1 }) - const cached = await cache.loadMultiple(ContactTypeRef, listId, [elementIdPart(contactAId)], undefined, { cacheMode: CacheMode.Cache }) + const cached = await cache.loadMultiple(ContactTypeRef, listId, [elementIdPart(contactAId)], undefined, { cacheMode: CacheMode.ReadAndWrite }) o(cached).deepEquals([contactAOnTheServer]) // Wasn't written earlier; should be written now verify(client.loadMultiple(ContactTypeRef, listId, [elementIdPart(contactAId)], undefined, anything()), { times: 2 }) @@ -1899,7 +1903,7 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr // Fresh cache; should be loaded remotely and cached verify(client.loadRange(ContactTypeRef, listId, createId("0"), 2, false, anything()), { times: 1 }) - const cached = await cache.loadRange(ContactTypeRef, listId, createId("0"), 2, false, { cacheMode: CacheMode.Cache }) + const cached = await cache.loadRange(ContactTypeRef, listId, createId("0"), 2, false, { cacheMode: CacheMode.ReadAndWrite }) o(cached).deepEquals([contactAOnTheServer, contactBOnTheServer]) // Wasn't saved before verify(client.loadRange(ContactTypeRef, listId, createId("0"), 2, false, anything()), { times: 2 }) @@ -1936,7 +1940,7 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr // Fresh cache verify(client.loadRange(ContactTypeRef, listId, createId("1"), 2, false, anything()), { times: 1 }) - const cached = await cache.loadRange(ContactTypeRef, listId, createId("1"), 2, false, { cacheMode: CacheMode.Cache }) + const cached = await cache.loadRange(ContactTypeRef, listId, createId("1"), 2, false, { cacheMode: CacheMode.ReadAndWrite }) o(cached).deepEquals([contactBOnTheServer]) // Was saved before now verify(client.loadRange(ContactTypeRef, listId, createId("1"), 2, false, anything()), { times: 2 })