mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-30 00:29:46 +08:00
chore: prohibit using mergeUpdates (#3701)
This commit is contained in:
+12
-11
@@ -2,7 +2,8 @@ import { readFileSync } from 'fs';
|
||||
import { dirname, resolve } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { describe, expect, test } from 'vitest';
|
||||
import * as Y from 'yjs';
|
||||
import type { Array as YArray, Map as YMap } from 'yjs';
|
||||
import { applyUpdate, Doc } from 'yjs';
|
||||
|
||||
import { migrateToSubdoc } from '../blocksuite/index.js';
|
||||
|
||||
@@ -11,8 +12,8 @@ const fixturePath = resolve(
|
||||
'workspace.ydoc'
|
||||
);
|
||||
const yDocBuffer = readFileSync(fixturePath);
|
||||
const doc = new Y.Doc();
|
||||
Y.applyUpdate(doc, new Uint8Array(yDocBuffer));
|
||||
const doc = new Doc();
|
||||
applyUpdate(doc, new Uint8Array(yDocBuffer));
|
||||
const migratedDoc = migrateToSubdoc(doc);
|
||||
|
||||
describe('subdoc', () => {
|
||||
@@ -23,8 +24,8 @@ describe('subdoc', () => {
|
||||
for (let i = 0; i < length; i++) {
|
||||
binary[i] = (json as any)[i];
|
||||
}
|
||||
const doc = new Y.Doc();
|
||||
Y.applyUpdate(doc, binary);
|
||||
const doc = new Doc();
|
||||
applyUpdate(doc, binary);
|
||||
{
|
||||
// invoke data
|
||||
doc.getMap('space:hello-world');
|
||||
@@ -32,7 +33,7 @@ describe('subdoc', () => {
|
||||
}
|
||||
const blocks = doc.getMap('space:hello-world').toJSON();
|
||||
const newDoc = migrateToSubdoc(doc);
|
||||
const subDoc = newDoc.getMap('spaces').get('space:hello-world') as Y.Doc;
|
||||
const subDoc = newDoc.getMap('spaces').get('space:hello-world') as Doc;
|
||||
const data = (subDoc.toJSON() as any).blocks;
|
||||
Object.keys(data).forEach(id => {
|
||||
if (id === 'xyWNqindHH') {
|
||||
@@ -50,23 +51,23 @@ describe('subdoc', () => {
|
||||
|
||||
test('Test fixture should be set correctly', () => {
|
||||
const meta = doc.getMap('space:meta');
|
||||
const versions = meta.get('versions') as Y.Map<unknown>;
|
||||
const versions = meta.get('versions') as YMap<unknown>;
|
||||
expect(versions.get('affine:code')).toBeTypeOf('number');
|
||||
});
|
||||
|
||||
test('Meta data should be migrated correctly', () => {
|
||||
const originalMeta = doc.getMap('space:meta');
|
||||
const originalVersions = originalMeta.get('versions') as Y.Map<unknown>;
|
||||
const originalVersions = originalMeta.get('versions') as YMap<unknown>;
|
||||
|
||||
const meta = migratedDoc.getMap('meta');
|
||||
const blockVersions = meta.get('blockVersions') as Y.Map<unknown>;
|
||||
const blockVersions = meta.get('blockVersions') as YMap<unknown>;
|
||||
|
||||
expect(meta.get('workspaceVersion')).toBe(1);
|
||||
expect(blockVersions.get('affine:code')).toBe(
|
||||
originalVersions.get('affine:code')
|
||||
);
|
||||
expect((meta.get('pages') as Y.Array<unknown>).length).toBe(
|
||||
(originalMeta.get('pages') as Y.Array<unknown>).length
|
||||
expect((meta.get('pages') as YArray<unknown>).length).toBe(
|
||||
(originalMeta.get('pages') as YArray<unknown>).length
|
||||
);
|
||||
|
||||
expect(blockVersions.get('affine:embed')).toBeUndefined();
|
||||
|
||||
+28
-28
@@ -1,5 +1,5 @@
|
||||
import type { Schema } from '@blocksuite/store';
|
||||
import * as Y from 'yjs';
|
||||
import { Array as YArray, Doc as YDoc, Map as YMap } from 'yjs';
|
||||
|
||||
type XYWH = [number, number, number, number];
|
||||
|
||||
@@ -7,10 +7,10 @@ function deserializeXYWH(xywh: string): XYWH {
|
||||
return JSON.parse(xywh) as XYWH;
|
||||
}
|
||||
|
||||
function migrateDatabase(data: Y.Map<unknown>) {
|
||||
function migrateDatabase(data: YMap<unknown>) {
|
||||
data.delete('prop:mode');
|
||||
data.set('prop:views', new Y.Array());
|
||||
const columns = (data.get('prop:columns') as Y.Array<unknown>).toJSON() as {
|
||||
data.set('prop:views', new YArray());
|
||||
const columns = (data.get('prop:columns') as YArray<unknown>).toJSON() as {
|
||||
id: string;
|
||||
name: string;
|
||||
hide: boolean;
|
||||
@@ -31,7 +31,7 @@ function migrateDatabase(data: Y.Map<unknown>) {
|
||||
mode: 'table',
|
||||
},
|
||||
];
|
||||
const cells = (data.get('prop:cells') as Y.Map<unknown>).toJSON() as Record<
|
||||
const cells = (data.get('prop:cells') as YMap<unknown>).toJSON() as Record<
|
||||
string,
|
||||
Record<
|
||||
string,
|
||||
@@ -90,7 +90,7 @@ function migrateDatabase(data: Y.Map<unknown>) {
|
||||
|
||||
function runBlockMigration(
|
||||
flavour: string,
|
||||
data: Y.Map<unknown>,
|
||||
data: YMap<unknown>,
|
||||
version: number
|
||||
) {
|
||||
if (flavour === 'affine:frame') {
|
||||
@@ -99,12 +99,12 @@ function runBlockMigration(
|
||||
}
|
||||
if (flavour === 'affine:surface' && version <= 3) {
|
||||
if (data.has('elements')) {
|
||||
const elements = data.get('elements') as Y.Map<unknown>;
|
||||
const elements = data.get('elements') as YMap<unknown>;
|
||||
migrateSurface(elements);
|
||||
data.set('prop:elements', elements.clone());
|
||||
data.delete('elements');
|
||||
} else {
|
||||
data.set('prop:elements', new Y.Map());
|
||||
data.set('prop:elements', new YMap());
|
||||
}
|
||||
}
|
||||
if (flavour === 'affine:embed') {
|
||||
@@ -116,8 +116,8 @@ function runBlockMigration(
|
||||
}
|
||||
}
|
||||
|
||||
function migrateSurface(data: Y.Map<unknown>) {
|
||||
for (const [, value] of <IterableIterator<[string, Y.Map<unknown>]>>(
|
||||
function migrateSurface(data: YMap<unknown>) {
|
||||
for (const [, value] of <IterableIterator<[string, YMap<unknown>]>>(
|
||||
data.entries()
|
||||
)) {
|
||||
if (value.get('type') === 'connector') {
|
||||
@@ -126,7 +126,7 @@ function migrateSurface(data: Y.Map<unknown>) {
|
||||
}
|
||||
}
|
||||
|
||||
function migrateSurfaceConnector(data: Y.Map<any>) {
|
||||
function migrateSurfaceConnector(data: YMap<any>) {
|
||||
let id = data.get('startElement')?.id;
|
||||
const controllers = data.get('controllers');
|
||||
const length = controllers.length;
|
||||
@@ -164,7 +164,7 @@ function migrateSurfaceConnector(data: Y.Map<any>) {
|
||||
data.delete('xywh');
|
||||
}
|
||||
|
||||
function updateBlockVersions(versions: Y.Map<number>) {
|
||||
function updateBlockVersions(versions: YMap<number>) {
|
||||
const frameVersion = versions.get('affine:frame');
|
||||
if (frameVersion !== undefined) {
|
||||
versions.set('affine:note', frameVersion);
|
||||
@@ -181,12 +181,12 @@ function updateBlockVersions(versions: Y.Map<number>) {
|
||||
}
|
||||
}
|
||||
|
||||
function migrateMeta(oldDoc: Y.Doc, newDoc: Y.Doc) {
|
||||
function migrateMeta(oldDoc: YDoc, newDoc: YDoc) {
|
||||
const originalMeta = oldDoc.getMap('space:meta');
|
||||
const originalVersions = originalMeta.get('versions') as Y.Map<number>;
|
||||
const originalPages = originalMeta.get('pages') as Y.Array<Y.Map<unknown>>;
|
||||
const originalVersions = originalMeta.get('versions') as YMap<number>;
|
||||
const originalPages = originalMeta.get('pages') as YArray<YMap<unknown>>;
|
||||
const meta = newDoc.getMap('meta');
|
||||
const pages = new Y.Array();
|
||||
const pages = new YArray();
|
||||
const blockVersions = originalVersions.clone();
|
||||
|
||||
meta.set('workspaceVersion', 1);
|
||||
@@ -196,7 +196,7 @@ function migrateMeta(oldDoc: Y.Doc, newDoc: Y.Doc) {
|
||||
|
||||
updateBlockVersions(blockVersions);
|
||||
const mapList = originalPages.map(page => {
|
||||
const map = new Y.Map();
|
||||
const map = new YMap();
|
||||
Array.from(page.entries())
|
||||
.filter(([key]) => key !== 'subpageIds')
|
||||
.forEach(([key, value]) => {
|
||||
@@ -207,16 +207,16 @@ function migrateMeta(oldDoc: Y.Doc, newDoc: Y.Doc) {
|
||||
pages.push(mapList);
|
||||
}
|
||||
|
||||
function migrateBlocks(oldDoc: Y.Doc, newDoc: Y.Doc) {
|
||||
function migrateBlocks(oldDoc: YDoc, newDoc: YDoc) {
|
||||
const spaces = newDoc.getMap('spaces');
|
||||
const originalMeta = oldDoc.getMap('space:meta');
|
||||
const originalVersions = originalMeta.get('versions') as Y.Map<number>;
|
||||
const originalPages = originalMeta.get('pages') as Y.Array<Y.Map<unknown>>;
|
||||
const originalVersions = originalMeta.get('versions') as YMap<number>;
|
||||
const originalPages = originalMeta.get('pages') as YArray<YMap<unknown>>;
|
||||
originalPages.forEach(page => {
|
||||
const id = page.get('id') as string;
|
||||
const spaceId = id.startsWith('space:') ? id : `space:${id}`;
|
||||
const originalBlocks = oldDoc.getMap(spaceId) as Y.Map<unknown>;
|
||||
const subdoc = new Y.Doc();
|
||||
const originalBlocks = oldDoc.getMap(spaceId) as YMap<unknown>;
|
||||
const subdoc = new YDoc();
|
||||
spaces.set(spaceId, subdoc);
|
||||
const blocks = subdoc.getMap('blocks');
|
||||
Array.from(originalBlocks.entries()).forEach(([key, value]) => {
|
||||
@@ -231,19 +231,19 @@ function migrateBlocks(oldDoc: Y.Doc, newDoc: Y.Doc) {
|
||||
});
|
||||
}
|
||||
|
||||
export function migrateToSubdoc(doc: Y.Doc): Y.Doc {
|
||||
export function migrateToSubdoc(doc: YDoc): YDoc {
|
||||
const needMigration = Array.from(doc.getMap('space:meta').keys()).length > 0;
|
||||
if (!needMigration) {
|
||||
return doc;
|
||||
}
|
||||
const output = new Y.Doc();
|
||||
const output = new YDoc();
|
||||
migrateMeta(doc, output);
|
||||
migrateBlocks(doc, output);
|
||||
return output;
|
||||
}
|
||||
|
||||
export async function migrateDatabaseBlockTo3(rootDoc: Y.Doc, schema: Schema) {
|
||||
const spaces = rootDoc.getMap('spaces') as Y.Map<any>;
|
||||
export async function migrateDatabaseBlockTo3(rootDoc: YDoc, schema: Schema) {
|
||||
const spaces = rootDoc.getMap('spaces') as YMap<any>;
|
||||
spaces.forEach(space => {
|
||||
schema.upgradePage(
|
||||
{
|
||||
@@ -261,7 +261,7 @@ export async function migrateDatabaseBlockTo3(rootDoc: Y.Doc, schema: Schema) {
|
||||
space
|
||||
);
|
||||
});
|
||||
const meta = rootDoc.getMap('meta') as Y.Map<unknown>;
|
||||
const versions = meta.get('blockVersions') as Y.Map<number>;
|
||||
const meta = rootDoc.getMap('meta') as YMap<unknown>;
|
||||
const versions = meta.get('blockVersions') as YMap<number>;
|
||||
versions.set('affine:database', 3);
|
||||
}
|
||||
|
||||
@@ -2,13 +2,44 @@ import assert from 'node:assert';
|
||||
import { beforeEach, describe, test } from 'node:test';
|
||||
|
||||
import { encoding } from 'lib0';
|
||||
import * as Y from 'yjs';
|
||||
import { applyUpdate, Doc } from 'yjs';
|
||||
|
||||
import { Storage } from '../index.js';
|
||||
|
||||
// update binary by y.doc.text('content').insert('hello world')
|
||||
// prettier-ignore
|
||||
let init = Buffer.from([1,1,160,238,169,240,10,0,4,1,7,99,111,110,116,101,110,116,11,104,101,108,108,111,32,119,111,114,108,100,0])
|
||||
let init = Buffer.from([
|
||||
1,
|
||||
1,
|
||||
160,
|
||||
238,
|
||||
169,
|
||||
240,
|
||||
10,
|
||||
0,
|
||||
4,
|
||||
1,
|
||||
7,
|
||||
99,
|
||||
111,
|
||||
110,
|
||||
116,
|
||||
101,
|
||||
110,
|
||||
116,
|
||||
11,
|
||||
104,
|
||||
101,
|
||||
108,
|
||||
108,
|
||||
111,
|
||||
32,
|
||||
119,
|
||||
111,
|
||||
114,
|
||||
108,
|
||||
100,
|
||||
0])
|
||||
describe('Test jwst storage binding', () => {
|
||||
/** @type { Storage } */
|
||||
let storage;
|
||||
@@ -48,8 +79,8 @@ describe('Test jwst storage binding', () => {
|
||||
const update = await storage.load(workspace.doc.guid);
|
||||
assert(update !== null);
|
||||
|
||||
const doc = new Y.Doc();
|
||||
Y.applyUpdate(doc, update);
|
||||
const doc = new Doc();
|
||||
applyUpdate(doc, update);
|
||||
|
||||
let text = doc.getText('content');
|
||||
assert.equal(text.toJSON(), 'hello world');
|
||||
@@ -67,8 +98,8 @@ describe('Test jwst storage binding', () => {
|
||||
}
|
||||
|
||||
const update2 = await storage.load(workspace.doc.guid);
|
||||
const doc2 = new Y.Doc();
|
||||
Y.applyUpdate(doc2, update2);
|
||||
const doc2 = new Doc();
|
||||
applyUpdate(doc2, update2);
|
||||
|
||||
text = doc2.getText('content');
|
||||
assert.equal(text.toJSON(), 'hello my world!');
|
||||
@@ -80,8 +111,8 @@ describe('Test jwst storage binding', () => {
|
||||
const update = await storage.load(workspace.doc.guid);
|
||||
assert(update !== null);
|
||||
|
||||
const doc = new Y.Doc();
|
||||
Y.applyUpdate(doc, update);
|
||||
const doc = new Doc();
|
||||
applyUpdate(doc, update);
|
||||
|
||||
let text = doc.getText('content');
|
||||
assert.equal(text.toJSON(), 'hello world');
|
||||
@@ -103,8 +134,8 @@ describe('Test jwst storage binding', () => {
|
||||
}
|
||||
|
||||
const update2 = await storage.load(workspace.doc.guid);
|
||||
const doc2 = new Y.Doc();
|
||||
Y.applyUpdate(doc2, update2);
|
||||
const doc2 = new Doc();
|
||||
applyUpdate(doc2, update2);
|
||||
|
||||
text = doc2.getText('content');
|
||||
assert.equal(text.toJSON(), 'hello my world!');
|
||||
|
||||
@@ -435,15 +435,13 @@ describe('utils', () => {
|
||||
});
|
||||
|
||||
test('overwrite binary', async () => {
|
||||
await overwriteBinary('test', new Uint8Array([1, 2, 3]));
|
||||
const doc = new Doc();
|
||||
const map = doc.getMap();
|
||||
map.set('1', 1);
|
||||
await overwriteBinary('test', new Uint8Array(encodeStateAsUpdate(doc)));
|
||||
{
|
||||
const binary = await downloadBinary('test');
|
||||
expect(binary).toEqual(new Uint8Array([1, 2, 3]));
|
||||
}
|
||||
await overwriteBinary('test', new Uint8Array([0, 0]));
|
||||
{
|
||||
const binary = await downloadBinary('test');
|
||||
expect(binary).toEqual(new Uint8Array([0, 0]));
|
||||
expect(binary).toEqual(new Uint8Array(encodeStateAsUpdate(doc)));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import { openDB } from 'idb';
|
||||
import type { Doc } from 'yjs';
|
||||
import { diffUpdate, mergeUpdates } from 'yjs';
|
||||
import { diffUpdate } from 'yjs';
|
||||
|
||||
import {
|
||||
type BlockSuiteBinaryDB,
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
type UpdateMessage,
|
||||
upgradeDB,
|
||||
} from './shared';
|
||||
import { mergeUpdates } from './utils';
|
||||
|
||||
let mergeCount = 500;
|
||||
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
import type { IDBPDatabase } from 'idb';
|
||||
import { openDB } from 'idb';
|
||||
import { mergeUpdates } from 'yjs';
|
||||
import { applyUpdate, Doc, encodeStateAsUpdate } from 'yjs';
|
||||
|
||||
import type { BlockSuiteBinaryDB, OldYjsDB, UpdateMessage } from './shared';
|
||||
import { dbVersion, DEFAULT_DB_NAME, upgradeDB } from './shared';
|
||||
|
||||
let allDb: IDBDatabaseInfo[];
|
||||
|
||||
export function mergeUpdates(updates: Uint8Array[]) {
|
||||
const doc = new Doc();
|
||||
updates.forEach(update => {
|
||||
applyUpdate(doc, update);
|
||||
});
|
||||
return encodeStateAsUpdate(doc);
|
||||
}
|
||||
|
||||
async function databaseExists(name: string): Promise<boolean> {
|
||||
return new Promise(resolve => {
|
||||
const req = indexedDB.open(name);
|
||||
|
||||
Reference in New Issue
Block a user