fix: only create version snapshot when content actually changes

Co-authored-by: fredicious <1580688+fredicious@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-03-11 21:02:00 +01:00
committed by Fred Cabassut
co-authored by fredicious
parent f7ede655e9
commit e777513a79
4 changed files with 13104 additions and 9 deletions
+13070
View File
File diff suppressed because it is too large Load Diff
+26 -1
View File
@@ -1,6 +1,6 @@
import { describe, it, expect, beforeEach } from 'vitest';
import { createTestDb } from './db/test-helpers.js';
import { notes, noteCollaborators, noteUserState, users } from './db/schema.js';
import { notes, noteCollaborators, noteUserState, noteVersions, users } from './db/schema.js';
import { eq, and } from 'drizzle-orm';
import type { Db } from './db/index.js';
import {
@@ -233,6 +233,31 @@ describe('updateNote', () => {
expect(updated!.version).toBe(2);
});
it('should create a snapshot when content changes', () => {
seedNote('n1', { title: 'Original', content: 'Hello', color: 'default', checklistMode: false });
updateNote(db, OWNER_ID, 'n1', { title: 'Changed' });
const snapshots = db.select().from(noteVersions).where(eq(noteVersions.noteId, 'n1')).all();
expect(snapshots).toHaveLength(1);
});
it('should not create a snapshot when no content field actually changed', () => {
seedNote('n1', { title: 'Same', content: 'Same', color: 'default', checklistMode: false });
// Send the same values — nothing actually changes
updateNote(db, OWNER_ID, 'n1', { title: 'Same', content: 'Same' });
const snapshots = db.select().from(noteVersions).where(eq(noteVersions.noteId, 'n1')).all();
expect(snapshots).toHaveLength(0);
});
it('should not create a snapshot when only non-content fields change (pinned, archived)', () => {
seedNote('n1', { title: 'Note', pinned: false });
updateNote(db, OWNER_ID, 'n1', { pinned: true });
const snapshots = db.select().from(noteVersions).where(eq(noteVersions.noteId, 'n1')).all();
expect(snapshots).toHaveLength(0);
});
it('should extract and sync tags on title/content change', () => {
seedNote('n1', { title: 'Original' });
const updated = updateNote(db, OWNER_ID, 'n1', { title: 'Now with #newtag' });
+7 -7
View File
@@ -294,14 +294,14 @@ export function updateNote(db: Db, userId: number, id: string, input: UpdateNote
}
}
// Create a version snapshot whenever content-related fields are saved
const hasContentUpdate =
input.title !== undefined ||
input.content !== undefined ||
input.color !== undefined ||
input.checklistMode !== undefined;
// Create a version snapshot only when at least one content field actually changed
const hasActualContentChange =
(input.title !== undefined && input.title !== existing.title) ||
(input.content !== undefined && input.content !== existing.content) ||
(input.color !== undefined && input.color !== existing.color) ||
(input.checklistMode !== undefined && input.checklistMode !== existing.checklistMode);
if (hasContentUpdate) {
if (hasActualContentChange) {
const saved = db.select().from(notes).where(eq(notes.id, id)).get();
if (saved) {
createSnapshot(db, id, {
+1 -1
View File
@@ -9,7 +9,7 @@ const CONTENT_PREVIEW_LENGTH = 80;
/**
* Create a snapshot of a note's current state.
* Called on every save. Prunes snapshots beyond MAX_VERSIONS_PER_NOTE.
* Only called when content actually changed. Prunes snapshots beyond MAX_VERSIONS_PER_NOTE.
*/
export function createSnapshot(
db: Db,