Files
AFFiNE-Mirror/blocksuite/framework/store/src/test/test-doc.ts
Saul-Mirone 267bb3a975 refactor(editor): introduce store container to make implement doc easier (#12146)
<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Introduced a new store management system for handling document stores, improving efficiency and flexibility when working with document data.

- **Refactor**
  - Updated internal store handling to use a centralized store container, simplifying store retrieval and removal across various components.
  - Renamed and updated several store-related method signatures for consistency and clarity.
  - Replaced editor extension loading logic with a new local implementation for better modularity.

- **Chores**
  - Improved and streamlined the export of store-related modules for better maintainability.
  - Removed obsolete and redundant code related to previous store management approaches.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-05-07 06:08:43 +00:00

187 lines
3.5 KiB
TypeScript

import * as Y from 'yjs';
import type { YBlock } from '../model/block/types.js';
import {
type Doc,
type GetStoreOptions,
StoreContainer,
type Workspace,
} from '../model/index.js';
import type { AwarenessStore } from '../yjs/index.js';
import type { TestWorkspace } from './test-workspace.js';
type DocOptions = {
id: string;
collection: Workspace;
doc: Y.Doc;
awarenessStore: AwarenessStore;
};
export class TestDoc implements Doc {
private readonly _collection: Workspace;
private readonly _storeContainer: StoreContainer;
private readonly _initSubDoc = () => {
let subDoc = this.rootDoc.getMap('spaces').get(this.id);
if (!subDoc) {
subDoc = new Y.Doc({
guid: this.id,
});
this.rootDoc.getMap('spaces').set(this.id, subDoc);
this._loaded = true;
} else {
this._loaded = false;
this.rootDoc.on('subdocs', this._onSubdocEvent);
}
return subDoc;
};
private _loaded!: boolean;
private readonly _onSubdocEvent = ({
loaded,
}: {
loaded: Set<Y.Doc>;
}): void => {
const result = Array.from(loaded).find(
doc => doc.guid === this._ySpaceDoc.guid
);
if (!result) {
return;
}
this.rootDoc.off('subdocs', this._onSubdocEvent);
this._loaded = true;
};
/** Indicate whether the block tree is ready */
private _ready = false;
protected readonly _yBlocks: Y.Map<YBlock>;
/**
* @internal Used for convenient access to the underlying Yjs map,
* can be used interchangeably with ySpace
*/
protected readonly _ySpaceDoc: Y.Doc;
readonly awarenessStore: AwarenessStore;
readonly id: string;
readonly rootDoc: Y.Doc;
get blobSync() {
return this.workspace.blobSync;
}
get workspace() {
return this._collection;
}
get isEmpty() {
return this._yBlocks.size === 0;
}
get loaded() {
return this._loaded;
}
get meta() {
return this.workspace.meta.getDocMeta(this.id);
}
get ready() {
return this._ready;
}
get spaceDoc() {
return this._ySpaceDoc;
}
get yBlocks() {
return this._yBlocks;
}
constructor({ id, collection, doc, awarenessStore }: DocOptions) {
this.id = id;
this.rootDoc = doc;
this.awarenessStore = awarenessStore;
this._ySpaceDoc = this._initSubDoc() as Y.Doc;
this._yBlocks = this._ySpaceDoc.getMap('blocks');
this._collection = collection;
this._storeContainer = new StoreContainer(this);
}
clear() {
this._yBlocks.clear();
}
get removeStore() {
return this._storeContainer.removeStore;
}
private _destroy() {
this._ySpaceDoc.destroy();
this._loaded = false;
}
dispose() {
if (this.ready) {
this._yBlocks.clear();
}
}
getStore({
readonly,
query,
provider,
extensions,
id,
}: GetStoreOptions = {}) {
const storeExtensions = (
this.workspace as TestWorkspace
).storeExtensions.concat(extensions ?? []);
let storeId: string | undefined;
if (id) {
storeId = id;
} else if (readonly !== undefined || query) {
storeId = id;
} else {
storeId = this.spaceDoc.guid;
}
return this._storeContainer.getStore({
id: storeId,
readonly,
query,
provider,
extensions: storeExtensions,
});
}
load(initFn?: () => void): this {
if (this.ready) {
return this;
}
this._ySpaceDoc.load();
initFn?.();
this._ready = true;
return this;
}
remove() {
this._destroy();
this.rootDoc.getMap('spaces').delete(this.id);
}
}