Closed matt-dalton closed 11 months ago
you have this option to configure the storage you prefer :) https://github.com/morrys/wora/blob/master/packages/cache-persist/src/CacheTypes.ts#L23
Once you have created the storage, can you share it here?
Ahh nice...looks super straightforward. We should be able to have a go at this shortly.
@matt-dalton how did it go? care to share the storage?
Good reminder! We eventually moved away from the idea of MMKV as a relay store because of the discussions in this thread. We ended up using react-native-quick-sqlite to store the data in a single table. The implementation here was a bit more complex, because we had to create a couple of layers to store/fetch data in the right format for the table. but it was something like:
// This can be passed into relay offline
export const sqlLiteStorage: ICacheStorage = {
multiRemove: (keys: string[]): Promise<void> => SQLiteAPI.deleteJSON(keys),
multiGet: (keys: string[]): Promise<string[][]> =>
SQLiteAPI.getJSON(keys).then((result) => {
return result || [[]]
}),
getAllKeys: (): Promise<string[]> => SQLiteAPI.getAllJSONKeys().then((result) => result || []),
multiSet: (items: KeyValuePair[]): Promise<void> => SQLiteAPI.setJSON(items),
setItem: (key: string, value: string): Promise<void> => SQLiteAPI.setJSON([key, value]),
removeItem: (key: string): Promise<void> => SQLiteAPI.deleteJSON(key),
getItem: (key: string): Promise<string> =>
SQLiteAPI.getJSON(key).then((result) => {
return result || ''
}),
}
Then here's an API layer. Note we only use quick SQLite for this specific use-case, so this is very much optimised for relay and hence not suitable for broader applications:
class SQLiteAPI {
private hasInitialized: boolean = false
async init(): Promise<void> {
// Seems to take about 200ms the first time this happens to create the DB
if (!this.hasInitialized) {
await SQLite.createTables()
this.hasInitialized = true
}
}
public async getJSON(keyOrKeys: string | string[]): Promise<string | string[][] | null> {
await this.init()
if (Array.isArray(keyOrKeys)) {
return SQLite.selectMultipleKeysFromJSON(keyOrKeys).then((result) => result || null)
}
return SQLite.selectKeyFromJSON(keyOrKeys).then((result) => (!!result ? result : null))
}
public async setJSON(keyValuePairOrArray: KeyValuePair | KeyValuePair[]): Promise<void> {
await this.init()
if (isKeyValuePairArray(keyValuePairOrArray)) {
return SQLite.upsertMultipleKeysFromJSON(keyValuePairOrArray)
}
const [key, value] = keyValuePairOrArray
return SQLite.upsertKeyFromJSON(key, value)
}
public async deleteJSON(keyOrKeys: string | string[]): Promise<void> {
await this.init()
if (Array.isArray(keyOrKeys)) {
return SQLite.deleteMultipleKeysFromJSON(keyOrKeys)
}
return SQLite.deleteKeyFromJSON(keyOrKeys)
}
public async getAllJSONKeys(): Promise<string[] | null> {
await this.init()
return SQLite.selectAllJSONKeys().then((result) => result || null)
}
}
Then you need to implement a controller/wrapper with functions that grab the JSON data (e.g. SQLite.selectAllJSONKeys()
).
We built all this fairly quickly so can almost certainly be improved.
If you do want to create an MMKV version, it's much easier. You can just mimic the first file above, and use it to call MMKV fairly directly, since the API is similar.
Have you considered creating an MMKV layer for React Native apps that we use for your libraries? Async storage works well, but it involves a lot of data going over the bridge (particularly with the volume of data Relay uses), so in theory MMKV should be much more performant.
I realise you'd probably need to customise this at the cache-persist layer. If this isn't on your roadmap, is there a guide for how we might switch out the storage layer? I've seen simple files like this, but not sure how we'd plug that in at the relay offline layer.