delta-sync
Version:
A lightweight framework for bi-directional database synchronization with automatic version tracking and conflict resolution.
103 lines (102 loc) • 3.46 kB
JavaScript
export class MemoryAdapter {
constructor() {
this.stores = new Map();
this.fileStore = new Map();
}
async isAvailable() {
return true;
}
async readByVersion(storeName, options = {}) {
const store = this.stores.get(storeName) || new Map();
let items = Array.from(store.values());
if (options.since !== undefined) {
items = items.filter(item => options.order === 'desc'
? (item._version || 0) < options.since
: (item._version || 0) > options.since);
}
items.sort((a, b) => options.order === 'desc'
? (b._version || 0) - (a._version || 0)
: (a._version || 0) - (b._version || 0));
const offset = options.offset || 0;
const limit = options.limit || items.length;
const paginatedItems = items.slice(offset, offset + limit);
return {
items: paginatedItems,
hasMore: offset + limit < items.length
};
}
async readAll(storeName) {
const store = this.stores.get(storeName) || new Map();
return Array.from(store.values());
}
async readBulk(storeName, ids) {
const store = this.stores.get(storeName) || new Map();
return ids
.map(id => store.get(id))
.filter(item => item !== undefined);
}
async putBulk(storeName, items) {
if (!items.length)
return [];
const store = this.stores.get(storeName) || new Map();
this.stores.set(storeName, store);
items.forEach(item => {
store.set(item.id, { ...item });
});
return [...items];
}
async deleteBulk(storeName, ids) {
const store = this.stores.get(storeName);
if (store) {
ids.forEach(id => store.delete(id));
}
}
async readFiles(fileIds) {
return new Map(fileIds.map(id => [
id,
this.fileStore.get(id)?.content || null
]));
}
async saveFiles(files) {
if (!files.length)
return [];
const now = Date.now();
return files.map(({ content, fileId }) => {
const fileContent = typeof content === 'string'
? new Blob([content], { type: 'text/plain' })
: content;
const attachment = {
id: fileId,
filename: fileId,
mimeType: fileContent instanceof Blob ? fileContent.type : 'application/octet-stream',
size: fileContent instanceof Blob ? fileContent.size : fileContent.byteLength,
createdAt: now,
updatedAt: now,
metadata: {}
};
this.fileStore.set(fileId, {
id: fileId,
content: fileContent,
metadata: attachment,
_created_at: now,
_updated_at: now
});
return attachment;
});
}
async deleteFiles(fileIds) {
return fileIds.reduce((result, fileId) => {
if (this.fileStore.delete(fileId)) {
result.deleted.push(fileId);
}
else {
result.failed.push(fileId);
}
return result;
}, { deleted: [], failed: [] });
}
async clearStore(storeName) {
this.stores.delete(storeName);
return true;
}
}