mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-18 23:07:02 +08:00
fix(server): check state changes before saving history record (#5038)
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
import { isDeepStrictEqual } from 'node:util';
|
||||||
|
|
||||||
import { Injectable, Logger } from '@nestjs/common';
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
import { OnEvent } from '@nestjs/event-emitter';
|
import { OnEvent } from '@nestjs/event-emitter';
|
||||||
import { Cron, CronExpression } from '@nestjs/schedule';
|
import { Cron, CronExpression } from '@nestjs/schedule';
|
||||||
@@ -41,6 +43,14 @@ export class DocHistoryManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (shouldCreateHistory) {
|
if (shouldCreateHistory) {
|
||||||
|
// skip the history recording when no actual update on snapshot happended
|
||||||
|
if (last && isDeepStrictEqual(last.state, snapshot.state)) {
|
||||||
|
this.logger.debug(
|
||||||
|
`State matches, skip creating history record for ${snapshot.id} in workspace ${snapshot.workspaceId}`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await this.db.snapshotHistory
|
await this.db.snapshotHistory
|
||||||
.create({
|
.create({
|
||||||
select: {
|
select: {
|
||||||
@@ -129,6 +139,7 @@ export class DocHistoryManager {
|
|||||||
},
|
},
|
||||||
select: {
|
select: {
|
||||||
timestamp: true,
|
timestamp: true,
|
||||||
|
state: true,
|
||||||
},
|
},
|
||||||
orderBy: {
|
orderBy: {
|
||||||
timestamp: 'desc',
|
timestamp: 'desc',
|
||||||
|
|||||||
@@ -74,9 +74,9 @@ test('should create doc history if never created before', async t => {
|
|||||||
t.is(history?.timestamp.getTime(), timestamp.getTime());
|
t.is(history?.timestamp.getTime(), timestamp.getTime());
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should not create history is timestamp equals to last record', async t => {
|
test('should not create history if timestamp equals to last record', async t => {
|
||||||
const timestamp = new Date();
|
const timestamp = new Date();
|
||||||
Sinon.stub(manager, 'last').resolves({ timestamp });
|
Sinon.stub(manager, 'last').resolves({ timestamp, state: null });
|
||||||
|
|
||||||
await manager.onDocUpdated({
|
await manager.onDocUpdated({
|
||||||
...snapshot,
|
...snapshot,
|
||||||
@@ -93,10 +93,55 @@ test('should not create history is timestamp equals to last record', async t =>
|
|||||||
t.falsy(history);
|
t.falsy(history);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should create history if time diff is larger than interval config', async t => {
|
test('should not create history if state equals to last record', async t => {
|
||||||
|
const timestamp = new Date();
|
||||||
|
Sinon.stub(manager, 'last').resolves({
|
||||||
|
timestamp: new Date(timestamp.getTime() - 1),
|
||||||
|
state: snapshot.state,
|
||||||
|
});
|
||||||
|
|
||||||
|
await manager.onDocUpdated({
|
||||||
|
...snapshot,
|
||||||
|
updatedAt: timestamp,
|
||||||
|
});
|
||||||
|
|
||||||
|
const history = await db.snapshotHistory.findFirst({
|
||||||
|
where: {
|
||||||
|
workspaceId: '1',
|
||||||
|
id: 'doc1',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
t.falsy(history);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not create history if time diff is less than interval config', async t => {
|
||||||
|
const timestamp = new Date();
|
||||||
|
Sinon.stub(manager, 'last').resolves({
|
||||||
|
timestamp: new Date(timestamp.getTime() - 1000),
|
||||||
|
state: Buffer.from([0, 1]),
|
||||||
|
});
|
||||||
|
|
||||||
|
await manager.onDocUpdated({
|
||||||
|
...snapshot,
|
||||||
|
updatedAt: timestamp,
|
||||||
|
});
|
||||||
|
|
||||||
|
const history = await db.snapshotHistory.findFirst({
|
||||||
|
where: {
|
||||||
|
workspaceId: '1',
|
||||||
|
id: 'doc1',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
t.falsy(history);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should create history if time diff is larger than interval config and state diff', async t => {
|
||||||
const timestamp = new Date();
|
const timestamp = new Date();
|
||||||
Sinon.stub(manager, 'last').resolves({
|
Sinon.stub(manager, 'last').resolves({
|
||||||
timestamp: new Date(timestamp.getTime() - 1000 * 60 * 20),
|
timestamp: new Date(timestamp.getTime() - 1000 * 60 * 20),
|
||||||
|
state: Buffer.from([0, 1]),
|
||||||
});
|
});
|
||||||
|
|
||||||
await manager.onDocUpdated({
|
await manager.onDocUpdated({
|
||||||
@@ -114,31 +159,11 @@ test('should create history if time diff is larger than interval config', async
|
|||||||
t.truthy(history);
|
t.truthy(history);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should not create history if time diff is less than interval config', async t => {
|
|
||||||
const timestamp = new Date();
|
|
||||||
Sinon.stub(manager, 'last').resolves({
|
|
||||||
timestamp: new Date(timestamp.getTime() - 1000),
|
|
||||||
});
|
|
||||||
|
|
||||||
await manager.onDocUpdated({
|
|
||||||
...snapshot,
|
|
||||||
updatedAt: timestamp,
|
|
||||||
});
|
|
||||||
|
|
||||||
const history = await db.snapshotHistory.findFirst({
|
|
||||||
where: {
|
|
||||||
workspaceId: '1',
|
|
||||||
id: 'doc1',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
t.falsy(history);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should create history with force flag even if time diff in small', async t => {
|
test('should create history with force flag even if time diff in small', async t => {
|
||||||
const timestamp = new Date();
|
const timestamp = new Date();
|
||||||
Sinon.stub(manager, 'last').resolves({
|
Sinon.stub(manager, 'last').resolves({
|
||||||
timestamp: new Date(timestamp.getTime() - 1),
|
timestamp: new Date(timestamp.getTime() - 1),
|
||||||
|
state: Buffer.from([0, 1]),
|
||||||
});
|
});
|
||||||
|
|
||||||
await manager.onDocUpdated(
|
await manager.onDocUpdated(
|
||||||
@@ -309,4 +334,8 @@ test('should be able to cleanup expired history', async t => {
|
|||||||
|
|
||||||
count = await db.snapshotHistory.count();
|
count = await db.snapshotHistory.count();
|
||||||
t.is(count, 10);
|
t.is(count, 10);
|
||||||
|
|
||||||
|
const example = await db.snapshotHistory.findFirst();
|
||||||
|
t.truthy(example);
|
||||||
|
t.true(example!.expiredAt > new Date());
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user