-
-
Notifications
You must be signed in to change notification settings - Fork 101
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
aa39728
commit 8e5155a
Showing
2 changed files
with
34 additions
and
91 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,118 +1,67 @@ | ||
import type { Change } from '@legendapp/state'; | ||
import { applyChanges, internal, isArray } from '@legendapp/state'; | ||
import type { | ||
ObservablePersistPlugin, | ||
ObservablePersistPluginOptions, | ||
ObservablePersistSQLiteStoragePluginOptions, | ||
PersistMetadata, | ||
} from '@legendapp/state/sync'; | ||
import type { SQLiteStorage as SQLiteStorageStatic } from 'expo-sqlite/kv-store'; | ||
|
||
const MetadataSuffix = '__m'; | ||
|
||
let SQLiteStorage: SQLiteStorageStatic; | ||
import { applyChanges, internal } from '@legendapp/state'; | ||
import type { ObservablePersistPlugin, PersistMetadata } from '@legendapp/state/sync'; | ||
import { SQLiteStorage, Storage } from 'expo-sqlite/kv-store'; | ||
|
||
const { safeParse, safeStringify } = internal; | ||
|
||
export class ObservablePersistSQLiteStorage implements ObservablePersistPlugin { | ||
private data: Record<string, any> = {}; | ||
private configuration: ObservablePersistSQLiteStoragePluginOptions; | ||
const MetadataSuffix = '__m'; | ||
|
||
constructor(configuration: ObservablePersistSQLiteStoragePluginOptions) { | ||
this.configuration = configuration; | ||
export class ObservablePersistSqlite implements ObservablePersistPlugin { | ||
private data: Record<string, any> = {}; | ||
private storage: SQLiteStorage | undefined; | ||
constructor(storage: SQLiteStorage | undefined) { | ||
this.storage = storage || Storage; | ||
} | ||
public async initialize(configOptions: ObservablePersistPluginOptions) { | ||
const storageConfig = this.configuration || configOptions.sqliteStorage; | ||
|
||
let tables: readonly string[] = []; | ||
if (storageConfig) { | ||
SQLiteStorage = storageConfig.SQLiteStorage; | ||
const { preload } = storageConfig; | ||
public getTable(table: string, init: any) { | ||
if (!this.storage) return undefined; | ||
if (this.data[table] === undefined) { | ||
try { | ||
if (preload === true) { | ||
// If preloadAllKeys, load all keys and preload tables on startup | ||
tables = await SQLiteStorage.getAllKeys(); | ||
} else if (isArray(preload)) { | ||
// If preloadKeys, preload load the tables on startup | ||
const metadataTables = preload.map((table) => | ||
table.endsWith(MetadataSuffix) ? undefined : table + MetadataSuffix, | ||
); | ||
tables = [...preload, ...(metadataTables.filter(Boolean) as string[])]; | ||
} | ||
if (tables) { | ||
const values = await SQLiteStorage.multiGet(tables as string[]); | ||
|
||
values.forEach(([table, value]) => { | ||
this.data[table] = value ? safeParse(value) : undefined; | ||
}); | ||
} | ||
} catch (e) { | ||
console.error('[legend-state] ObservablePersistSQLiteStorage failed to initialize', e); | ||
const value = this.storage.getItemSync(table); | ||
this.data[table] = value ? safeParse(value) : init; | ||
} catch { | ||
console.error('[legend-state] ObservablePersistSqlite failed to parse', table); | ||
} | ||
} else { | ||
console.error('[legend-state] Missing sQLiteStorage configuration'); | ||
} | ||
} | ||
public loadTable(table: string): void | Promise<void> { | ||
if (this.data[table] === undefined) { | ||
return SQLiteStorage.multiGet([table, table + MetadataSuffix]) | ||
.then((values) => { | ||
try { | ||
values.forEach(([table, value]) => { | ||
this.data[table] = value ? safeParse(value) : undefined; | ||
}); | ||
} catch (err) { | ||
console.error('[legend-state] ObservablePersistLocalSQLiteStorage failed to parse', table, err); | ||
} | ||
}) | ||
.catch((err: Error) => { | ||
if (err?.message !== 'window is not defined') { | ||
console.error('[legend-state] SQLiteStorage.multiGet failed', table, err); | ||
} | ||
}); | ||
} | ||
} | ||
// Gets | ||
public getTable(table: string, init: object) { | ||
return this.data[table] ?? init ?? {}; | ||
return this.data[table]; | ||
} | ||
public getMetadata(table: string): PersistMetadata { | ||
return this.getTable(table + MetadataSuffix, {}); | ||
} | ||
// Sets | ||
public set(table: string, changes: Change[]): Promise<void> { | ||
public set(table: string, changes: Change[]): void { | ||
if (!this.data[table]) { | ||
this.data[table] = {}; | ||
} | ||
|
||
this.data[table] = applyChanges(this.data[table], changes); | ||
return this.save(table); | ||
this.save(table); | ||
} | ||
public setMetadata(table: string, metadata: PersistMetadata) { | ||
return this.setValue(table + MetadataSuffix, metadata); | ||
table = table + MetadataSuffix; | ||
this.data[table] = metadata; | ||
this.save(table); | ||
} | ||
public async deleteTable(table: string) { | ||
return SQLiteStorage.removeItem(table); | ||
public deleteTable(table: string) { | ||
if (!this.storage) return undefined; | ||
delete this.data[table]; | ||
this.storage.removeItemSync(table); | ||
} | ||
public deleteMetadata(table: string) { | ||
return this.deleteTable(table + MetadataSuffix); | ||
this.deleteTable(table + MetadataSuffix); | ||
} | ||
// Private | ||
private async setValue(table: string, value: any) { | ||
this.data[table] = value; | ||
await this.save(table); | ||
} | ||
private async save(table: string) { | ||
private save(table: string) { | ||
if (!this.storage) return undefined; | ||
|
||
const v = this.data[table]; | ||
|
||
if (v !== undefined && v !== null) { | ||
return SQLiteStorage.setItem(table, safeStringify(v)); | ||
this.storage.setItemSync(table, safeStringify(v)); | ||
} else { | ||
return SQLiteStorage.removeItem(table); | ||
this.storage.removeItemSync(table); | ||
} | ||
} | ||
} | ||
|
||
export function observablePersistSQLiteStorage(configuration: ObservablePersistSQLiteStoragePluginOptions) { | ||
return new ObservablePersistSQLiteStorage(configuration); | ||
export function observablePersistSqlite(storage?: SQLiteStorage) { | ||
return new ObservablePersistSqlite(storage); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters