avenger
avenger copied to clipboard
Plugin architecture for cache?
I'd like to propose a slightly modified architecture of avenger that allows for greater flexibility in the choice of cache source. In this issue I'll provide some detailed thoughts and the motivation for doing so. Given that I think the change is fairly significant and I'm new to avenger, before attempting a PR I'd like feedback on if you think is feasible and desirable. My proposal is also non-breaking (I think), so there may be a way to progressively merge this in. I'll start with an example of how I think the resulting API will look (though less verbose) before I dive into a bunch of words explaining it:
// An additional argument is provided to specify the cache source
const user = queryStrict((id: string) => API.fetchUser(id), available, cache: {source: 'localStorage', lookup: 'localStorage'});
Basic Idea
The basic idea is to allow the cache to be a source other than just what's locally in memory. Here the cache could be a persistent source, but it is a "cache" in the eyes of the user because it is significantly faster than its corresponding fetch. For example, the cache could be LocalStorage in the browser or the FileSystem on React Native. Resultantly, the architecture would probably need to be modified slightly such that the cache lookup table is now separate from the cache source itself. Additionally, this cache lookup table source could itself be configurable, such as using a persistent source like LocalStorage or
Motivation
Making the cache configurable to something other than in memory
has two advantages
- Avenger can now handle large objects that don't fit well in memory
- You can achieve some persistence between sessions for a user
As a motivating example, on React native I often download images via a fetch and store them on the FileSystem. I then create a lookup table using React Natives version of local storage (AsyncStorage
). The cache is invalidated for the image using a UUID, but I will create a separate issue for that. The point is, often these images are too big to keep in memory AND i can create better UX for a person returning to the app in that they might not need to redownload the images each time
API
I think that there could be some helper functions for reducing boilerplate, but in general the API of e.g. queryStrict
would add an additional parameter to specify the CacheRetrieval
. This parameter would be optional an default to the existing in memory approach so that this change would be non breaking
type CacheSource = 'memory' | 'localStorage' | 'reactNativeFS'
type CacheLookup = 'memory' | 'localStorage' | 'reactNativeAsyncStorage'
interface CacheRetrieval {
source: CacheSource,
lookup: CacheLookup
}
queryStrict<A = void, L = unknown, P = unknown>(
fetch: Fetch<A, L, P>,
makeStrategy: StrategyBuilder<A, L, P>,
cacheRetrieval?: CacheRetrieval // New parameter to specify cache source and lookup table
): CachedQuery<A, L, P>
Plugin
Here I think some kind of plugin archiecture is needed so that you could specify how exactly localStorage
or reactNativeFS
works.For example, reactNativeFS
would use react-native-fs to store files to the filesystem. I think this plugin architecture would be the most complex part
Anyway, curious thoughts on this?