@worldbrain/storex-sync
Version:
Offline-first syncing between multiple databases using Storex
145 lines • 9.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var storex_1 = require("@worldbrain/storex");
var expect = require("expect");
var default_1 = require("./default");
function test(_a) {
var logEntries = _a.logEntries, expectedOperations = _a.expectedOperations;
var storageRegistry = new storex_1.StorageRegistry();
storageRegistry.registerCollections({
list: {
version: new Date('2019-02-02'),
fields: {
title: { type: 'string' },
}
},
listEntry: {
version: new Date('2019-02-02'),
fields: {
title: { type: 'string' },
url: { type: 'string' },
}
}
});
var reconciled = default_1.reconcileSyncLog(logEntries, { storageRegistry: storageRegistry });
if (expectedOperations) {
expect(reconciled).toEqual(expectedOperations);
}
}
describe('Reconciliation', function () {
it('should choose the newest write when finding two entries for the same object field', function () {
var logEntries = [
{ operation: 'modify', createdOn: 2, sharedOn: null, needsIntegration: true, collection: 'list', pk: 'list-one', field: 'title', value: 'second' },
{ operation: 'modify', createdOn: 1, sharedOn: null, needsIntegration: true, collection: 'list', pk: 'list-one', field: 'title', value: 'first' },
];
test({ logEntries: logEntries, expectedOperations: [
{ operation: 'updateOneObject', collection: 'list', args: [{ id: 'list-one' }, { title: 'second' }] }
] });
});
it('should choose the newest write when finding more than two entries for the same object field', function () {
var logEntries = [
{ operation: 'modify', createdOn: 2, sharedOn: null, needsIntegration: true, collection: 'list', pk: 'list-one', field: 'title', value: 'second' },
{ operation: 'modify', createdOn: 3, sharedOn: null, needsIntegration: true, collection: 'list', pk: 'list-one', field: 'title', value: 'third' },
{ operation: 'modify', createdOn: 1, sharedOn: null, needsIntegration: true, collection: 'list', pk: 'list-one', field: 'title', value: 'first' },
];
test({ logEntries: logEntries, expectedOperations: [
{ operation: 'updateOneObject', collection: 'list', args: [{ id: 'list-one' }, { title: 'third' }] }
] });
});
it('should ignore writes to an object that needs deletion', function () {
var logEntries = [
{ operation: 'modify', createdOn: 2, sharedOn: null, needsIntegration: true, collection: 'list', pk: 'list-one', field: 'title', value: 'second' },
{ operation: 'delete', createdOn: 1, sharedOn: null, needsIntegration: true, collection: 'list', pk: 'list-one' },
];
test({ logEntries: logEntries, expectedOperations: [
{ operation: 'deleteOneObject', collection: 'list', args: [{ id: 'list-one' }] }
] });
});
it('should ignore writes to an already deleted object', function () {
var logEntries = [
{ operation: 'modify', createdOn: 2, sharedOn: null, needsIntegration: true, collection: 'list', pk: 'list-one', field: 'title', value: 'second' },
{ operation: 'delete', createdOn: 4, sharedOn: 3, needsIntegration: true, collection: 'list', pk: 'list-one' },
{ operation: 'delete', createdOn: 1, sharedOn: 3, needsIntegration: true, collection: 'list', pk: 'list-one' },
];
test({ logEntries: logEntries, expectedOperations: [] });
});
it('should work with only one delete', function () {
var logEntries = [
{ operation: 'delete', createdOn: 1, sharedOn: null, needsIntegration: true, collection: 'list', pk: 'list-one' },
];
test({ logEntries: logEntries, expectedOperations: [
{ operation: 'deleteOneObject', collection: 'list', args: [{ id: 'list-one' }] }
] });
});
it('should ignore double deletes', function () {
var logEntries = [
{ operation: 'delete', createdOn: 4, sharedOn: null, needsIntegration: true, collection: 'list', pk: 'list-one' },
{ operation: 'delete', createdOn: 1, sharedOn: null, needsIntegration: true, collection: 'list', pk: 'list-one' },
];
test({ logEntries: logEntries, expectedOperations: [
{ operation: 'deleteOneObject', collection: 'list', args: [{ id: 'list-one' }] }
] });
});
it('should work with deletes having compound keys', function () {
var logEntries = [
{ operation: 'delete', createdOn: 4, sharedOn: null, needsIntegration: true, collection: 'listEntry', pk: ['list-one', 3] },
];
test({ logEntries: logEntries, expectedOperations: [
{ operation: 'deleteOneObject', collection: 'listEntry', args: [{ id: ['list-one', 3] }] }
] });
});
it('should ignore writes that are already synced', function () {
var logEntries = [
{ operation: 'modify', createdOn: 1, sharedOn: null, needsIntegration: true, collection: 'list', pk: 'list-one', field: 'title', value: 'second' },
{ operation: 'modify', createdOn: 2, sharedOn: 3, needsIntegration: true, collection: 'list', pk: 'list-one', field: 'title', value: 'second' },
];
test({ logEntries: logEntries, expectedOperations: [] });
});
it('should create objects', function () {
var logEntries = [
{ operation: 'create', createdOn: 1, sharedOn: null, needsIntegration: true, collection: 'list', pk: 'list-one', value: { title: 'first' } }
];
test({ logEntries: logEntries, expectedOperations: [
{ operation: 'createObject', collection: 'list', args: { id: 'list-one', title: 'first' } }
] });
});
it('should consolidate object creation with object updates', function () {
var logEntries = [
{ operation: 'modify', createdOn: 2, sharedOn: null, needsIntegration: true, collection: 'list', pk: 'list-one', field: 'title', value: 'second' },
{ operation: 'create', createdOn: 1, sharedOn: null, needsIntegration: true, collection: 'list', pk: 'list-one', value: { title: 'first', prio: 5 } },
];
test({ logEntries: logEntries, expectedOperations: [
{ operation: 'createObject', collection: 'list', args: { id: 'list-one', title: 'second', prio: 5 } }
] });
});
it('should consolidate object creation with object deletion', function () {
var logEntries = [
{ operation: 'modify', createdOn: 2, sharedOn: null, needsIntegration: true, collection: 'list', pk: 'list-one', field: 'title', value: 'second' },
{ operation: 'create', createdOn: 1, sharedOn: null, needsIntegration: true, collection: 'list', pk: 'list-one', value: { pk: 'list-one', title: 'first', prio: 5 } },
{ operation: 'delete', createdOn: 3, sharedOn: null, needsIntegration: true, collection: 'list', pk: 'list-one' },
];
test({ logEntries: logEntries, expectedOperations: [] });
});
it('should complain about double creates', function () {
var logEntries = [
{ operation: 'create', createdOn: 1, sharedOn: 1, needsIntegration: true, collection: 'list', pk: 'list-one', value: { pk: 'list-one', title: 'first', prio: 5 } },
{ operation: 'create', createdOn: 2, sharedOn: null, needsIntegration: true, collection: 'list', pk: 'list-one', value: { pk: 'list-one', title: 'first', prio: 5 } },
];
expect(function () { return test({ logEntries: logEntries }); }).toThrow("Detected double create in collection 'list', pk '\"list-one\"'");
});
it('should complain about modifications made to an object before creation', function () {
var logEntries = [
{ operation: 'modify', createdOn: 1, sharedOn: null, needsIntegration: true, collection: 'list', pk: 'list-one', field: 'title', value: 'second' },
{ operation: 'create', createdOn: 2, sharedOn: null, needsIntegration: true, collection: 'list', pk: 'list-one', value: { pk: 'list-one', title: 'first', prio: 5 } },
];
expect(function () { return test({ logEntries: logEntries }); }).toThrow("Detected modification to collection 'list', pk '\"list-one\"' before it was created (likely pk collision)");
});
it('should complain about modifications made to an object before creation even if received in the right order', function () {
var logEntries = [
{ operation: 'create', createdOn: 2, sharedOn: null, needsIntegration: true, collection: 'list', pk: 'list-one', value: { pk: 'list-one', title: 'first', prio: 5 } },
{ operation: 'modify', createdOn: 1, sharedOn: null, needsIntegration: true, collection: 'list', pk: 'list-one', field: 'title', value: 'second' },
];
expect(function () { return test({ logEntries: logEntries }); }).toThrow("Detected modification to collection 'list', pk '\"list-one\"' before it was created (likely pk collision)");
});
});
//# sourceMappingURL=default.test.js.map