feat: integrate editor record for snapshots

This commit is contained in:
DarkSky
2024-08-19 16:02:46 +08:00
parent f5f5b05a4c
commit 7901a55fd7
5 changed files with 38 additions and 19 deletions
@@ -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;
+4 -3
View File
@@ -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 {