UNPKG

delta-sync

Version:

A lightweight framework for bi-directional database synchronization with automatic version tracking and conflict resolution.

118 lines (117 loc) 3.81 kB
// core/types.ts // Synchronization status enumeration export var SyncStatus; (function (SyncStatus) { SyncStatus[SyncStatus["ERROR"] = -2] = "ERROR"; SyncStatus[SyncStatus["OFFLINE"] = -1] = "OFFLINE"; SyncStatus[SyncStatus["IDLE"] = 0] = "IDLE"; SyncStatus[SyncStatus["UPLOADING"] = 1] = "UPLOADING"; SyncStatus[SyncStatus["DOWNLOADING"] = 2] = "DOWNLOADING"; SyncStatus[SyncStatus["OPERATING"] = 3] = "OPERATING"; })(SyncStatus || (SyncStatus = {})); export class SyncView { constructor() { this.items = new Map(); this.storeIndex = new Map(); } // Add or update record upsert(item) { const key = this.getKey(item.store, item.id); this.items.set(key, item); if (!this.storeIndex.has(item.store)) { this.storeIndex.set(item.store, new Set()); } this.storeIndex.get(item.store).add(item.id); } // Batch update records upsertBatch(items) { for (const item of items) { this.upsert(item); } } // Get specific record get(store, id) { return this.items.get(this.getKey(store, id)); } // Get paginated records for specified store getByStore(store, offset = 0, limit = 100) { const storeItems = this.storeIndex.get(store); if (!storeItems) return []; return Array.from(storeItems) .slice(offset, offset + limit) .map(id => this.items.get(this.getKey(store, id))) .filter(item => item !== undefined); } // Get all store names getStores() { return Array.from(this.storeIndex.keys()); } // Compare differences between two views static diffViews(local, remote) { const toDownload = []; const toUpload = []; const localKeys = new Set(local.items.keys()); const remoteKeys = new Set(remote.items.keys()); // Keys only in local (need to upload) for (const key of localKeys) { if (!remoteKeys.has(key)) { toUpload.push(local.items.get(key)); } } // Keys only in remote (need to download) for (const key of remoteKeys) { if (!localKeys.has(key)) { toDownload.push(remote.items.get(key)); } } // Keys in both (need version comparison) for (const key of localKeys) { if (remoteKeys.has(key)) { const localItem = local.items.get(key); const remoteItem = remote.items.get(key); if (localItem._ver > remoteItem._ver) { toUpload.push(localItem); } else if (localItem._ver < remoteItem._ver) { toDownload.push(remoteItem); } } } return { toDownload, toUpload }; } // Generate composite key getKey(store, id) { return `${store}:${id}`; } // Delete record delete(store, id) { const key = this.getKey(store, id); this.items.delete(key); this.storeIndex.get(store)?.delete(id); } // Get total storage size size() { return this.items.size; } // Get record count for specific store storeSize(store) { return this.storeIndex.get(store)?.size || 0; } // Clear all data clear() { this.items.clear(); this.storeIndex.clear(); } // Serialize view data (for persistence) serialize() { return JSON.stringify(Array.from(this.items.values())); } // Deserialize from data (for persistence) static deserialize(data) { const view = new SyncView(); const items = JSON.parse(data); view.upsertBatch(items); return view; } }