mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-14 00:26:51 +08:00
feat: integrate editor record for snapshots
This commit is contained in:
+2
-9
@@ -1,19 +1,12 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- Added the required column `created_by` to the `snapshot_histories` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `created_by` to the `updates` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "snapshot_histories" ADD COLUMN "created_by" VARCHAR NOT NULL;
|
||||
ALTER TABLE "snapshot_histories" ADD COLUMN "created_by" VARCHAR;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "snapshots" ADD COLUMN "created_by" VARCHAR,
|
||||
ADD COLUMN "updated_by" VARCHAR;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "updates" ADD COLUMN "created_by" VARCHAR NOT NULL;
|
||||
ALTER TABLE "updates" ADD COLUMN "created_by" VARCHAR NOT NULL DEFAULT 'system';
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "snapshots" ADD CONSTRAINT "snapshots_created_by_fkey" FOREIGN KEY ("created_by") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@@ -285,7 +285,8 @@ model Update {
|
||||
id String @map("guid") @db.VarChar
|
||||
blob Bytes @db.ByteA
|
||||
createdAt DateTime @map("created_at") @db.Timestamptz(3)
|
||||
createdBy String @map("created_by") @db.VarChar
|
||||
// TODO(@darkskygit): fullfill old update, remove default value in next release
|
||||
createdBy String @map("created_by") @db.VarChar @default("system")
|
||||
|
||||
// delete update if createor's account is deleted
|
||||
createdByUser User @relation(name: "createdUpdate", fields: [createdBy], references: [id], onDelete: Cascade)
|
||||
@@ -304,10 +305,10 @@ model SnapshotHistory {
|
||||
blob Bytes @db.ByteA
|
||||
state Bytes? @db.ByteA
|
||||
expiredAt DateTime @map("expired_at") @db.Timestamptz(3)
|
||||
createdBy String @map("created_by") @db.VarChar
|
||||
createdBy String? @map("created_by") @db.VarChar
|
||||
|
||||
// delete history if creator's account is deleted
|
||||
createdByUser User @relation(name: "createdHistory", fields: [createdBy], references: [id], onDelete: Cascade)
|
||||
createdByUser User? @relation(name: "createdHistory", fields: [createdBy], references: [id], onDelete: Cascade)
|
||||
|
||||
@@id([workspaceId, id, timestamp])
|
||||
@@map("snapshot_histories")
|
||||
|
||||
@@ -45,7 +45,12 @@ export class PgUserspaceDocStorageAdapter extends DocStorageAdapter {
|
||||
return this.getDocSnapshot(spaceId, docId);
|
||||
}
|
||||
|
||||
async pushDocUpdates(userId: string, docId: string, updates: Uint8Array[]) {
|
||||
async pushDocUpdates(
|
||||
editorId: string,
|
||||
userId: string,
|
||||
docId: string,
|
||||
updates: Uint8Array[]
|
||||
) {
|
||||
if (!updates.length) {
|
||||
return 0;
|
||||
}
|
||||
@@ -67,6 +72,7 @@ export class PgUserspaceDocStorageAdapter extends DocStorageAdapter {
|
||||
docId,
|
||||
bin,
|
||||
timestamp,
|
||||
editor: editorId,
|
||||
});
|
||||
|
||||
return timestamp;
|
||||
@@ -135,6 +141,7 @@ export class PgUserspaceDocStorageAdapter extends DocStorageAdapter {
|
||||
docId,
|
||||
bin: snapshot.blob,
|
||||
timestamp: snapshot.updatedAt.getTime(),
|
||||
editor: snapshot.userId,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -151,6 +158,7 @@ export class PgUserspaceDocStorageAdapter extends DocStorageAdapter {
|
||||
update: {
|
||||
blob: Buffer.from(snapshot.bin),
|
||||
updatedAt: new Date(snapshot.timestamp),
|
||||
updatedBy: snapshot.editor,
|
||||
},
|
||||
create: {
|
||||
userId: snapshot.spaceId,
|
||||
@@ -158,6 +166,8 @@ export class PgUserspaceDocStorageAdapter extends DocStorageAdapter {
|
||||
blob: Buffer.from(snapshot.bin),
|
||||
createdAt: new Date(snapshot.timestamp),
|
||||
updatedAt: new Date(snapshot.timestamp),
|
||||
createdBy: snapshot.editor,
|
||||
updatedBy: snapshot.editor,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ export class PgWorkspaceDocStorageAdapter extends DocStorageAdapter {
|
||||
}
|
||||
|
||||
async pushDocUpdates(
|
||||
editorId: string,
|
||||
workspaceId: string,
|
||||
docId: string,
|
||||
updates: Uint8Array[]
|
||||
@@ -82,6 +83,7 @@ export class PgWorkspaceDocStorageAdapter extends DocStorageAdapter {
|
||||
blob: Buffer.from(update),
|
||||
seq,
|
||||
createdAt: new Date(createdAt),
|
||||
createdBy: editorId,
|
||||
};
|
||||
}),
|
||||
});
|
||||
@@ -113,6 +115,7 @@ export class PgWorkspaceDocStorageAdapter extends DocStorageAdapter {
|
||||
return rows.map(row => ({
|
||||
bin: row.blob,
|
||||
timestamp: row.createdAt.getTime(),
|
||||
editor: row.createdBy,
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -253,10 +256,12 @@ export class PgWorkspaceDocStorageAdapter extends DocStorageAdapter {
|
||||
docId,
|
||||
bin: history.blob,
|
||||
timestamp,
|
||||
editor: history.createdBy || undefined,
|
||||
};
|
||||
}
|
||||
|
||||
override async rollbackDoc(
|
||||
editorId: string,
|
||||
spaceId: string,
|
||||
docId: string,
|
||||
timestamp: number
|
||||
@@ -274,7 +279,14 @@ export class PgWorkspaceDocStorageAdapter extends DocStorageAdapter {
|
||||
}
|
||||
|
||||
// force create a new history record after rollback
|
||||
await this.createDocHistory(fromSnapshot, true);
|
||||
await this.createDocHistory(
|
||||
{
|
||||
...fromSnapshot,
|
||||
// override the editor to the one who requested the rollback
|
||||
editor: editorId,
|
||||
},
|
||||
true
|
||||
);
|
||||
// WARN:
|
||||
// we should never do the snapshot updating in recovering,
|
||||
// which is not the solution in CRDT.
|
||||
@@ -331,6 +343,7 @@ export class PgWorkspaceDocStorageAdapter extends DocStorageAdapter {
|
||||
id: snapshot.docId,
|
||||
timestamp: new Date(snapshot.timestamp),
|
||||
blob: Buffer.from(snapshot.bin),
|
||||
createdBy: snapshot.editor,
|
||||
expiredAt: new Date(
|
||||
Date.now() + (await this.options.historyMaxAge(snapshot.spaceId))
|
||||
),
|
||||
@@ -374,6 +387,8 @@ export class PgWorkspaceDocStorageAdapter extends DocStorageAdapter {
|
||||
docId,
|
||||
bin: snapshot.blob,
|
||||
timestamp: snapshot.updatedAt.getTime(),
|
||||
// creator and editor may null if their account is deleted
|
||||
editor: snapshot.updatedBy || snapshot.createdBy || undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -396,10 +411,10 @@ export class PgWorkspaceDocStorageAdapter extends DocStorageAdapter {
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
try {
|
||||
const result: { updatedAt: Date }[] = await this.db.$queryRaw`
|
||||
INSERT INTO "snapshots" ("workspace_id", "guid", "blob", "created_at", "updated_at")
|
||||
VALUES (${spaceId}, ${docId}, ${bin}, DEFAULT, ${updatedAt})
|
||||
INSERT INTO "snapshots" ("workspace_id", "guid", "blob", "created_at", "updated_at", "created_by", "updated_by")
|
||||
VALUES (${spaceId}, ${docId}, ${bin}, DEFAULT, ${updatedAt}, ${snapshot.editor}, ${snapshot.editor})
|
||||
ON CONFLICT ("workspace_id", "guid")
|
||||
DO UPDATE SET "blob" = ${bin}, "updated_at" = ${updatedAt}
|
||||
DO UPDATE SET "blob" = ${bin}, "updated_at" = ${updatedAt}, "updated_by" = ${snapshot.editor}
|
||||
WHERE "snapshots"."workspace_id" = ${spaceId} AND "snapshots"."guid" = ${docId} AND "snapshots"."updated_at" <= ${updatedAt}
|
||||
RETURNING "snapshots"."workspace_id" as "workspaceId", "snapshots"."guid" as "id", "snapshots"."updated_at" as "updatedAt"
|
||||
`;
|
||||
|
||||
@@ -16,13 +16,13 @@ export interface DocRecord {
|
||||
docId: string;
|
||||
bin: Uint8Array;
|
||||
timestamp: number;
|
||||
editor: string;
|
||||
editor?: string;
|
||||
}
|
||||
|
||||
export interface DocUpdate {
|
||||
bin: Uint8Array;
|
||||
timestamp: number;
|
||||
editor: string;
|
||||
editor?: string;
|
||||
}
|
||||
|
||||
export interface HistoryFilter {
|
||||
|
||||
Reference in New Issue
Block a user