Refinement

This commit is contained in:
Eric Bailey
2023-11-06 13:31:03 -06:00
parent ff946c59ec
commit bdb9082e7e
3 changed files with 33 additions and 88 deletions
+8 -8
View File
@@ -14,26 +14,26 @@ afterEach(() => {
})
test(`gets and sets data synchronously`, async () => {
storage.set('shell.colorMode', 'light')
storage.set('shell', {colorMode: 'light'})
expect(AsyncStorage.setItem).toHaveBeenCalledWith(
storage.STORAGE_ROOT_KEY,
JSON.stringify({shell: {colorMode: 'light'}}),
)
expect(storage.get('shell.colorMode')).toBe('light')
storage.set('shell', {colorMode: 'light'})
expect(AsyncStorage.getItem).not.toHaveBeenCalled()
storage.set('shell.colorMode', 'dark')
expect(storage.get('shell.colorMode')).toBe('dark')
storage.set('shell', {colorMode: 'dark'})
expect(storage.get('shell').colorMode).toBe('dark')
})
test(`set rolls back on error`, async () => {
storage.set('shell.colorMode', 'light')
test(`set ignores error and continues in memory`, async () => {
storage.set('shell', {colorMode: 'light'})
jest
.mocked(AsyncStorage.setItem)
.mockImplementationOnce(() => Promise.reject(new Error('test error')))
await storage.set('shell.colorMode', 'system')
await storage.set('shell', {colorMode: 'system'})
expect(storage.get('shell.colorMode')).toBe('light')
expect(storage.get('shell').colorMode).toBe('system')
})
+21 -20
View File
@@ -1,45 +1,46 @@
import AsyncStorage from '@react-native-async-storage/async-storage'
import {logger} from '#/logger'
import {Schema, PropertyMap} from '#/storage/schema'
import {Schema, defaultData} from '#/storage/schema'
export const STORAGE_ROOT_KEY = 'root'
/**
* In memory cache of local storage data. Never export or reference this
* directly.
*
* We set it to a default value so that if AsyncStorage entirely fails, the app
* will continue to function entirely in memory.
*/
let data: Schema | undefined
let data: Schema = defaultData
export async function init() {
const raw = await AsyncStorage.getItem(STORAGE_ROOT_KEY)
logger.debug(`storage initialized`)
// TODO: Add try catch here etc, same in lib/storage.ts
data = (raw ? JSON.parse(raw) : {}) as Schema
logger.debug(`storage initializing`)
try {
const raw = await AsyncStorage.getItem(STORAGE_ROOT_KEY)
data = (raw ? JSON.parse(raw) : {}) as Schema
} catch (e) {
logger.error(`storage init() failed`)
}
}
export function get<T extends keyof PropertyMap>(key: T): PropertyMap[T] {
export function get<T extends keyof Schema>(key: T): Schema[T] {
logger.debug(`storage get(${key})`)
if (!data) {
throw new Error(`Data is not initialized. Did you forget to call init()`)
}
return data[key]
}
export async function set<T extends keyof PropertyMap>(
key: T,
value: PropertyMap[T],
) {
export async function set<T extends keyof Schema>(key: T, value: Schema[T]) {
logger.debug(`storage set(${key}, value)`)
if (!data) {
throw new Error(`Data is not initialized. Did you forget to call init()`)
}
data[ley] = value
// TODO: actual writing should probably be debounced
data[key] = value
try {
// TODO maybe debounce this in the future
await AsyncStorage.setItem(STORAGE_ROOT_KEY, JSON.stringify(data))
return true
} catch (err) {
logger.error(`storage set(${keypath}, value) failed`)
logger.error(`storage set(${key}, value) failed`)
return false
}
}
+4 -60
View File
@@ -1,5 +1,3 @@
// import {LabelPreference} from '@atproto/api'
/**
* The shape of the object we store in local storage
*/
@@ -7,64 +5,10 @@ export type Schema = {
shell: {
colorMode: 'system' | 'light' | 'dark'
}
// session: {
// data: {
// service: string
// did: `did:plc:${string}`
// }
// accounts: {
// service: string
// did: `did:plc:${string}`
// refreshJwt: string
// accessJwt: string
// handle: string
// email: string
// displayName: string
// aviUrl: string
// emailConfirmed: boolean
// }[]
// }
// me: {
// did: `did:plc:${string}`
// handle: string
// displayName: string
// description: string
// avatar: string
// }
// onboarding: {
// step: string
// }
// preferences: {
// primaryLanguage: string
// contentLanguages: string[]
// postLanguage: string
// postLanguageHistory: string[]
// contentLabels: {
// nsfw: LabelPreference
// nudity: LabelPreference
// suggestive: LabelPreference
// gore: LabelPreference
// hate: LabelPreference
// spam: LabelPreference
// impersonation: LabelPreference
// }
// savedFeeds: string[]
// pinnedFeeds: string[]
// requireAltTextEnabled: boolean
// }
// invitedUsers: {
// seenDids: string[]
// copiedInvites: string[]
// }
// mutedThreads: {uris: string[]}
// reminders: {lastEmailConfirm: string}
}
/**
* A map of all the properties that can be stored in the storage, and their
* values. This mapping must be updated in order to get/set values by their
* keypaths.
*/
export type PropertyMap = {
'shell.colorMode': Schema['shell']['colorMode']
export const defaultData: Schema = {
shell: {
colorMode: 'system',
},
}