Skip to content

Commit

Permalink
feat(infra): standard storage service
Browse files Browse the repository at this point in the history
  • Loading branch information
EYHN committed Jan 17, 2024
1 parent 928bff0 commit ad28c4b
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/common/infra/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"./app-config-storage": "./src/app-config-storage.ts",
"./di": "./src/di/index.ts",
"./livedata": "./src/livedata/index.ts",
"./storage": "./src/storage/index.ts",
".": "./src/index.ts"
},
"dependencies": {
Expand Down
3 changes: 3 additions & 0 deletions packages/common/infra/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@ export * from './app-config-storage';
export * from './atom';
export * from './blocksuite';
export * from './command';
export * from './di';
export * from './livedata';
export * from './storage';
44 changes: 44 additions & 0 deletions packages/common/infra/src/storage/__tests__/memento.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { describe, expect, test } from 'vitest';

import { ServiceCollection } from '../../di';
import {
GlobalCache,
GlobalState,
MemoryGlobalCache,
MemoryGlobalState,
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.add(MemoryGlobalCache, MemoryGlobalState);

const provider = services.provider();
const cache = provider.resolve(GlobalCache);
expect(cache).toBeInstanceOf(MemoryGlobalCache);
const state = provider.resolve(GlobalState);
expect(state).toBeInstanceOf(MemoryGlobalState);
});
});
1 change: 1 addition & 0 deletions packages/common/infra/src/storage/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './memento';
71 changes: 71 additions & 0 deletions packages/common/infra/src/storage/memento.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import type { Observable } from 'rxjs';

import { createIdentifier, Service } 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);
}
}

/**
* A simple implementation of GlobalState. Used for testing.
*/
@Service()
@GlobalState()
export class MemoryGlobalState extends MemoryMemento implements GlobalState {}

/**
* A simple implementation of GlobalCache. Used for testing.
*/
@Service()
@GlobalCache()
export class MemoryGlobalCache extends MemoryMemento implements GlobalCache {}

0 comments on commit ad28c4b

Please sign in to comment.