feat(infra): standard storage service (#5563)
This commit is contained in:
@@ -9,6 +9,7 @@
|
|||||||
"./app-config-storage": "./src/app-config-storage.ts",
|
"./app-config-storage": "./src/app-config-storage.ts",
|
||||||
"./di": "./src/di/index.ts",
|
"./di": "./src/di/index.ts",
|
||||||
"./livedata": "./src/livedata/index.ts",
|
"./livedata": "./src/livedata/index.ts",
|
||||||
|
"./storage": "./src/storage/index.ts",
|
||||||
".": "./src/index.ts"
|
".": "./src/index.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -2,3 +2,6 @@ export * from './app-config-storage';
|
|||||||
export * from './atom';
|
export * from './atom';
|
||||||
export * from './blocksuite';
|
export * from './blocksuite';
|
||||||
export * from './command';
|
export * from './command';
|
||||||
|
export * from './di';
|
||||||
|
export * from './livedata';
|
||||||
|
export * from './storage';
|
||||||
|
|||||||
40
packages/common/infra/src/storage/__tests__/memento.spec.ts
Normal file
40
packages/common/infra/src/storage/__tests__/memento.spec.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { describe, expect, test } from 'vitest';
|
||||||
|
|
||||||
|
import { ServiceCollection } from '../../di';
|
||||||
|
import { GlobalCache, GlobalState, MemoryMemento } from '..';
|
||||||
|
|
||||||
|
describe('memento', () => {
|
||||||
|
test('memory', () => {
|
||||||
|
const memento = new MemoryMemento();
|
||||||
|
|
||||||
|
expect(memento.get('foo')).toBeNull();
|
||||||
|
memento.set('foo', 'bar');
|
||||||
|
expect(memento.get('foo')).toEqual('bar');
|
||||||
|
|
||||||
|
let subscribed = null;
|
||||||
|
const subscription = memento.watch('foo').subscribe(v => {
|
||||||
|
subscribed = v;
|
||||||
|
});
|
||||||
|
expect(subscribed).toEqual('bar');
|
||||||
|
memento.set('foo', 'baz');
|
||||||
|
expect(subscribed).toEqual('baz');
|
||||||
|
|
||||||
|
subscription.unsubscribe();
|
||||||
|
memento.set('foo', 'hello');
|
||||||
|
expect(subscribed).toEqual('baz');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('service', () => {
|
||||||
|
const services = new ServiceCollection();
|
||||||
|
|
||||||
|
services
|
||||||
|
.addImpl(GlobalCache, MemoryMemento)
|
||||||
|
.addImpl(GlobalState, MemoryMemento);
|
||||||
|
|
||||||
|
const provider = services.provider();
|
||||||
|
const cache = provider.get(GlobalCache);
|
||||||
|
expect(cache).toBeInstanceOf(MemoryMemento);
|
||||||
|
const state = provider.get(GlobalState);
|
||||||
|
expect(state).toBeInstanceOf(MemoryMemento);
|
||||||
|
});
|
||||||
|
});
|
||||||
1
packages/common/infra/src/storage/index.ts
Normal file
1
packages/common/infra/src/storage/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './memento';
|
||||||
57
packages/common/infra/src/storage/memento.ts
Normal file
57
packages/common/infra/src/storage/memento.ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import type { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
import { createIdentifier } from '../di';
|
||||||
|
import { LiveData } from '../livedata';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A memento represents a storage utility. It can store and retrieve values, and observe changes.
|
||||||
|
*/
|
||||||
|
export interface Memento {
|
||||||
|
get<T>(key: string): T | null;
|
||||||
|
watch<T>(key: string): Observable<T | null>;
|
||||||
|
set<T>(key: string, value: T | null): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A memento object that stores the entire application state.
|
||||||
|
*
|
||||||
|
* State is persisted, even the application is closed.
|
||||||
|
*/
|
||||||
|
export interface GlobalState extends Memento {}
|
||||||
|
|
||||||
|
export const GlobalState = createIdentifier<GlobalState>('GlobalState');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A memento object that stores the entire application cache.
|
||||||
|
*
|
||||||
|
* Cache may be deleted from time to time, business logic should not rely on cache.
|
||||||
|
*/
|
||||||
|
export interface GlobalCache extends Memento {}
|
||||||
|
|
||||||
|
export const GlobalCache = createIdentifier<GlobalCache>('GlobalCache');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple implementation of Memento. Used for testing.
|
||||||
|
*/
|
||||||
|
export class MemoryMemento implements Memento {
|
||||||
|
private readonly data = new Map<string, LiveData<any>>();
|
||||||
|
|
||||||
|
private getLiveData(key: string): LiveData<any> {
|
||||||
|
let data = this.data.get(key);
|
||||||
|
if (!data) {
|
||||||
|
data = new LiveData<any>(null);
|
||||||
|
this.data.set(key, data);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
get<T>(key: string): T | null {
|
||||||
|
return this.getLiveData(key).value;
|
||||||
|
}
|
||||||
|
watch<T>(key: string): Observable<T | null> {
|
||||||
|
return this.getLiveData(key).asObservable();
|
||||||
|
}
|
||||||
|
set<T>(key: string, value: T | null): void {
|
||||||
|
this.getLiveData(key).next(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user