From 9d57f4b751e1a4e5a7c3aabaea5a931b048d132b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoffer=20R=C3=B8dvik?= Date: Sat, 16 Aug 2025 14:40:37 +0200 Subject: [PATCH] feat: update pending logic --- src/databases/indexeddb/pending.ts | 57 +++++++++++++++++++----------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/src/databases/indexeddb/pending.ts b/src/databases/indexeddb/pending.ts index 25ec13b..c1c298f 100644 --- a/src/databases/indexeddb/pending.ts +++ b/src/databases/indexeddb/pending.ts @@ -2,15 +2,15 @@ import { Document } from "../../types.ts"; import { IndexedDbStorage } from "./storage.ts"; export class Pending { - readonly #upsert: any[] = []; - readonly #remove: string[] = []; - - readonly #chunkSize = 500; - - #saving: Promise | null = null; - #storage: IndexedDbStorage; + readonly #upsert = new Map(); + readonly #remove = new Set(); + + #chunkSize = 500; + #saveScheduled = false; + #saving: Promise | null = null; + constructor(storage: IndexedDbStorage) { this.#storage = storage; } @@ -20,33 +20,48 @@ export class Pending { } upsert(document: any): void { - this.#upsert.push(document); - this.save(); + this.#remove.delete(document.id); + this.#upsert.set(document.id, document); + this.#schedule(); } remove(id: any): void { - this.#remove.push(id); - this.save(); + this.#upsert.delete(id); + this.#remove.add(id); + this.#schedule(); + } + + #schedule() { + if (!this.#saveScheduled) { + this.#saveScheduled = true; + queueMicrotask(() => { + this.#saveScheduled = false; + void this.save(); + }); + } } async save() { - if (this.#saving) { - return; - } + if (this.#saving) return; this.#saving = (async () => { try { - while (this.#upsert.length > 0 || this.#remove.length > 0) { + while (this.#upsert.size > 0 || this.#remove.size > 0) { const tx = this.#storage.db.transaction(this.#storage.name, "readwrite", { durability: "relaxed" }); + const store = tx.store; - if (this.#remove.length > 0) { - const removals = this.#remove.splice(0, this.#chunkSize); - await Promise.all(removals.map((id) => tx.store.delete(id))); + // Process removals + if (this.#remove.size > 0) { + const removals = Array.from(this.#remove).slice(0, this.#chunkSize); + removals.forEach((id) => this.#remove.delete(id)); + await Promise.all(removals.map((id) => store.delete(id))); } - if (this.#upsert.length > 0) { - const upserts = this.#upsert.splice(0, this.#chunkSize); - await Promise.all(upserts.map((doc) => tx.store.put(doc))); + // Process upserts + if (this.#upsert.size > 0) { + const upserts = Array.from(this.#upsert.values()).slice(0, this.#chunkSize); + upserts.forEach((doc) => this.#upsert.delete(doc.id)); + await Promise.all(upserts.map((doc) => store.put(doc))); } await tx.done;