all repos — snow-editor @ main

small and cozy markdown, and orgmode editor

backend/src/versionUtils.js (view raw)

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
import { MAX_VERSIONS_PER_DOCUMENT } from './messages.js';
import { newId } from './utils.js';

// Autosave fires every second while typing; without coalescing the version
// history fills up with near-identical snapshots within minutes.
export const VERSION_COALESCE_MS = 5 * 60 * 1000;

export function saveDocumentVersion(db, doc, createdAt) {
  const versionId = newId();
  db.prepare(
    `INSERT INTO document_versions (id, document_id, title, mode, content, created_at)
     VALUES (?, ?, ?, ?, ?, ?)`,
  ).run(versionId, doc.id, doc.title, doc.mode, doc.content, createdAt);

  const excess = db
    .prepare(
      `SELECT id FROM document_versions
       WHERE document_id = ?
       ORDER BY created_at DESC
       LIMIT -1 OFFSET ?`,
    )
    .all(doc.id, MAX_VERSIONS_PER_DOCUMENT);

  if (excess.length > 0) {
    const placeholders = excess.map(() => '?').join(',');
    db.prepare(`DELETE FROM document_versions WHERE id IN (${placeholders})`).run(
      ...excess.map((row) => row.id),
    );
  }
}

// Snapshot only when the latest version is older than the coalescing window
// (or when there is no version yet). Returns true when a snapshot was taken.
export function maybeSaveDocumentVersion(db, doc, createdAt) {
  const latest = db
    .prepare(
      `SELECT created_at FROM document_versions
       WHERE document_id = ?
       ORDER BY created_at DESC
       LIMIT 1`,
    )
    .get(doc.id);

  if (latest) {
    const age = Date.parse(createdAt) - Date.parse(latest.created_at);
    if (age < VERSION_COALESCE_MS) {
      return false;
    }
  }

  saveDocumentVersion(db, doc, createdAt);
  return true;
}