@worldbrain/storex-sync
Version:
Offline-first syncing between multiple databases using Storex
277 lines (268 loc) • 11.4 kB
text/typescript
import * as expect from 'expect'
import StorageManager, { CollectionFields } from '@worldbrain/storex'
import { DexieStorageBackend } from '@worldbrain/storex-backend-dexie'
import inMemory from '@worldbrain/storex-backend-dexie/lib/in-memory'
import { registerModuleCollections } from '@worldbrain/storex-pattern-modules';
import { ClientSyncLogStorage } from '../client-sync-log';
import { SyncLoggingMiddleware } from '.';
async function setupTest({now, userFields} : {now : () => number, userFields? : CollectionFields}) {
const backend = new DexieStorageBackend({idbImplementation: inMemory(), dbName: 'unittest'})
const storageManager = new StorageManager({backend: backend as any})
storageManager.registry.registerCollections({
user: {
version: new Date('2019-02-19'),
fields: userFields || {
displayName: {type: 'string'}
}
}
})
const clientSyncLog = new ClientSyncLogStorage({storageManager})
registerModuleCollections(storageManager.registry, clientSyncLog)
await storageManager.finishInitialization()
const loggingMiddleware = new SyncLoggingMiddleware({ clientSyncLog, storageManager, includeCollections: ['user'] });
loggingMiddleware._getNow = now
storageManager.setMiddleware([loggingMiddleware])
return { storageManager, clientSyncLog }
}
describe('Sync logging middleware', () => {
it('should write createObject operations to the ClientSyncLog in a batch write', async () => {
const { storageManager, clientSyncLog } = await setupTest({now: () => 3})
await storageManager.collection('user').createObject({id: 53, displayName: 'John Doe'})
expect(await clientSyncLog.getEntriesCreatedAfter(1)).toEqual([
{
id: expect.anything(),
createdOn: 3,
sharedOn: null,
needsIntegration: false,
collection: 'user', pk: 53,
operation: 'create', value: {displayName: 'John Doe'}
},
])
})
it('should write updateObject operations done by pk on a single field to the ClientSyncLog in a batch write', async () => {
let now = 2
const { storageManager, clientSyncLog } = await setupTest({now: () => ++now})
await storageManager.collection('user').createObject({id: 53, displayName: 'John Doe'})
await storageManager.collection('user').updateOneObject({id: 53}, {displayName: 'Jack Doe'})
expect(await clientSyncLog.getEntriesCreatedAfter(1)).toEqual([
{
id: expect.anything(),
createdOn: 3,
sharedOn: null,
needsIntegration: false,
collection: 'user', pk: 53,
operation: 'create', value: {displayName: 'John Doe'}
},
{
id: expect.anything(),
createdOn: 4,
sharedOn: null,
needsIntegration: false,
collection: 'user', pk: 53,
operation: 'modify', field: 'displayName',
value: 'Jack Doe',
},
])
})
it('should write updateObject operations done by pk on multiple fields to the ClientSyncLog in a batch write', async () => {
let now = 2
const { storageManager, clientSyncLog } = await setupTest({now: () => ++now, userFields: {
firstName: {type: 'string'},
lastName: {type: 'string'},
}})
await storageManager.collection('user').createObject({id: 53, firstName: 'John', lastName: 'Doe'})
await storageManager.collection('user').updateOneObject({id: 53}, {firstName: 'Jack', lastName: 'Trump'})
expect(await clientSyncLog.getEntriesCreatedAfter(1)).toEqual([
{
id: expect.anything(),
createdOn: 3,
sharedOn: null,
needsIntegration: false,
collection: 'user', pk: 53,
operation: 'create', value: {firstName: 'John', lastName: 'Doe'}
},
{
id: expect.anything(),
createdOn: 4,
sharedOn: null,
needsIntegration: false,
collection: 'user', pk: 53,
operation: 'modify', field: 'firstName',
value: 'Jack',
},
{
id: expect.anything(),
createdOn: 5,
sharedOn: null,
needsIntegration: false,
collection: 'user', pk: 53,
operation: 'modify', field: 'lastName',
value: 'Trump',
},
])
})
it('should write updateObjects operations done on a single field to the ClientSyncLog in a batch write', async () => {
let now = 2
const { storageManager, clientSyncLog } = await setupTest({now: () => ++now, userFields: {
firstName: {type: 'string'},
lastName: {type: 'string'},
}})
await storageManager.collection('user').createObject({id: 53, firstName: 'John', lastName: 'Doe'})
await storageManager.collection('user').createObject({id: 54, firstName: 'Jane', lastName: 'Doe'})
await storageManager.collection('user').createObject({id: 55, firstName: 'Jack', lastName: 'Daniels'})
await storageManager.collection('user').updateObjects({lastName: 'Doe'}, {lastName: 'Trump'})
expect(await clientSyncLog.getEntriesCreatedAfter(1)).toEqual([
{
id: expect.anything(),
createdOn: 3,
sharedOn: null,
needsIntegration: false,
collection: 'user', pk: 53,
operation: 'create', value: {firstName: 'John', lastName: 'Doe'}
},
{
id: expect.anything(),
createdOn: 4,
sharedOn: null,
needsIntegration: false,
collection: 'user', pk: 54,
operation: 'create', value: {firstName: 'Jane', lastName: 'Doe'}
},
{
id: expect.anything(),
createdOn: 5,
sharedOn: null,
needsIntegration: false,
collection: 'user', pk: 55,
operation: 'create', value: {firstName: 'Jack', lastName: 'Daniels'}
},
{
id: expect.anything(),
createdOn: 6,
sharedOn: null,
needsIntegration: false,
collection: 'user', pk: 53,
operation: 'modify', field: 'lastName',
value: 'Trump',
},
{
id: expect.anything(),
createdOn: 7,
sharedOn: null,
needsIntegration: false,
collection: 'user', pk: 54,
operation: 'modify', field: 'lastName',
value: 'Trump',
},
])
})
it('should write updateObjects operations done on multiple fields to the ClientSyncLog in a batch write', async () => {
let now = 2
const { storageManager, clientSyncLog } = await setupTest({now: () => ++now, userFields: {
firstName: {type: 'string'},
lastName: {type: 'string'},
}})
await storageManager.collection('user').createObject({id: 53, firstName: 'John', lastName: 'Doe'})
await storageManager.collection('user').createObject({id: 54, firstName: 'Jane', lastName: 'Doe'})
await storageManager.collection('user').createObject({id: 55, firstName: 'Jack', lastName: 'Daniels'})
await storageManager.collection('user').updateObjects({lastName: 'Doe'}, {firstName: 'Pinata', lastName: 'Trump'})
expect(await clientSyncLog.getEntriesCreatedAfter(1)).toEqual([
{
id: expect.anything(),
createdOn: 3,
sharedOn: null,
needsIntegration: false,
collection: 'user', pk: 53,
operation: 'create', value: {firstName: 'John', lastName: 'Doe'}
},
{
id: expect.anything(),
createdOn: 4,
sharedOn: null,
needsIntegration: false,
collection: 'user', pk: 54,
operation: 'create', value: {firstName: 'Jane', lastName: 'Doe'}
},
{
id: expect.anything(),
createdOn: 5,
sharedOn: null,
needsIntegration: false,
collection: 'user', pk: 55,
operation: 'create', value: {firstName: 'Jack', lastName: 'Daniels'}
},
{
id: expect.anything(),
createdOn: 6,
sharedOn: null,
needsIntegration: false,
collection: 'user', pk: 53,
operation: 'modify', field: 'firstName',
value: 'Pinata',
},
{
id: expect.anything(),
createdOn: 7,
sharedOn: null,
needsIntegration: false,
collection: 'user', pk: 53,
operation: 'modify', field: 'lastName',
value: 'Trump',
},
{
id: expect.anything(),
createdOn: 8,
sharedOn: null,
needsIntegration: false,
collection: 'user', pk: 54,
operation: 'modify', field: 'firstName',
value: 'Pinata',
},
{
id: expect.anything(),
createdOn: 9,
sharedOn: null,
needsIntegration: false,
collection: 'user', pk: 54,
operation: 'modify', field: 'lastName',
value: 'Trump',
},
])
})
it('should correctly process batch operations with createObject operations', async () => {
let now = 2
const { storageManager, clientSyncLog } = await setupTest({now: () => ++now})
await storageManager.operation('executeBatch', [
{
placeholder: 'john',
operation: 'createObject',
collection: 'user',
args: {id: 53, displayName: 'John Doe'}
},
{
placeholder: 'jane',
operation: 'createObject',
collection: 'user',
args: {id: 54, displayName: 'Jane Does'}
},
])
expect(await clientSyncLog.getEntriesCreatedAfter(1)).toEqual([
{
id: expect.anything(),
createdOn: 3,
sharedOn: null,
needsIntegration: false,
collection: 'user', pk: 53,
operation: 'create', value: {displayName: 'John Doe'}
},
{
id: expect.anything(),
createdOn: 4,
sharedOn: null,
needsIntegration: false,
collection: 'user', pk: 54,
operation: 'create', value: {displayName: 'Jane Does'}
},
])
})
})