UNPKG

@getanthill/datastore

Version:

Event-Sourced Datastore

1,337 lines (1,107 loc) 34.9 kB
import Datastore from './Datastore'; import * as utils from './utils'; import setup from '../../test/setup'; import thingsModelConfig from '../templates/examples/things.json'; describe('sdk/utils (integration)', () => { let app; let ds; let datastores; let uuid; let modelNames: string[]; let res: { entity: any; query: any; query_iteration: any; batch_id: number; index: number; }[] = []; function handler(entity, query, queryIteration, batchId, index) { res.push({ entity, query, query_iteration: queryIteration, batch_id: batchId, index, }); } beforeAll(async () => { [, , , , , ds as Datastore, , app] = await setup.startApi({ features: { api: { admin: true, updateSpecOnModelsChange: true } }, }); datastores = new Map([['default', ds]]); }); beforeEach(async () => { uuid = setup.uuid(); modelNames = [`users_${uuid}`, `accounts_${uuid}`]; await Promise.all( modelNames.map((modelName) => ds.createModel({ ...thingsModelConfig, name: modelName, correlation_field: 'correlation_id', description: 'Users information', }), ), ); res = []; }); afterAll(async () => { jest.restoreAllMocks(); await setup.teardownDb(app.services.mongodb); await setup.stopApi(app); }); describe('#walkMulti', () => { let uuid; beforeEach(() => { uuid = setup.uuid(); }); it('walk over entities in order (2 entities)', async () => { const { data: entityA } = await ds.create(modelNames[0], { firstname: 'John', }); const { data: entityB } = await ds.create(modelNames[1], { firstname: 'John', }); const queryA = { datastore: 'default', model: modelNames[0], query: {}, source: 'entities', }; const queryB = { datastore: 'default', model: modelNames[1], query: {}, source: 'entities', }; // @ts-ignore await utils.walkMulti(datastores, [queryB, queryA], 1, handler); expect(res).toEqual([ expect.objectContaining({ entity: entityA, query: queryA }), expect.objectContaining({ entity: entityB, query: queryB }), ]); }); it('walk over entities in order (chunkSize = 1)', async () => { const { data: entityA } = await ds.create(modelNames[0], { firstname: 'John', }); const { data: entityB } = await ds.create(modelNames[1], { firstname: 'John', }); const queryA = { datastore: 'default', model: modelNames[0], query: {}, source: 'entities', }; const queryB = { datastore: 'default', model: modelNames[1], query: {}, source: 'entities', }; // @ts-ignore await utils.walkMulti(datastores, [queryB, queryA], 1, handler, { chunk_size: 1, }); expect(res).toEqual([ expect.objectContaining({ entity: entityA, query: queryA }), expect.objectContaining({ entity: entityB, query: queryB }), ]); }); it('walk over entities in order (3 entities)', async () => { const { data: entityA } = await ds.create(modelNames[0], { firstname: 'John', }); const { data: entityB } = await ds.create(modelNames[1], { firstname: 'John', }); const { data: entityC } = await ds.create(modelNames[0], { firstname: 'John', }); const queryA = { datastore: 'default', model: modelNames[0], query: {}, source: 'entities', }; const queryB = { datastore: 'default', model: modelNames[1], query: {}, source: 'entities', }; // @ts-ignore await utils.walkMulti(datastores, [queryA, queryB], 1, handler); expect(res).toEqual([ expect.objectContaining({ entity: entityA, query: queryA }), expect.objectContaining({ entity: entityB, query: queryB }), expect.objectContaining({ entity: entityC, query: queryA }), ]); }); it('walk over events in order (2 events)', async () => { const { data: entityA } = await ds.create(modelNames[0], { firstname: 'John', }); const { data: entityB } = await ds.create(modelNames[1], { firstname: 'John', }); const { data: eventsA } = await ds.allEvents(modelNames[0], {}); const { data: eventsB } = await ds.allEvents(modelNames[1], {}); const queryA = { datastore: 'default', model: modelNames[0], query: {}, source: 'events', }; const queryB = { datastore: 'default', model: modelNames[1], query: {}, source: 'events', }; // @ts-ignore await utils.walkMulti(datastores, [queryB, queryA], 1, handler); expect(res).toEqual([ expect.objectContaining({ entity: eventsA[0], query: queryA }), expect.objectContaining({ entity: eventsB[0], query: queryB }), ]); }); it('walk over events in order (3 events)', async () => { const { data: entityA } = await ds.create(modelNames[0], { firstname: 'John', }); const { data: entityB } = await ds.create(modelNames[1], { firstname: 'John', }); const { data: entityC } = await ds.create(modelNames[0], { firstname: 'John', }); const { data: eventsA } = await ds.allEvents(modelNames[0], {}); const { data: eventsB } = await ds.allEvents(modelNames[1], {}); const queryA = { datastore: 'default', model: modelNames[0], query: {}, source: 'events', }; const queryB = { datastore: 'default', model: modelNames[1], query: {}, source: 'events', }; // @ts-ignore await utils.walkMulti(datastores, [queryB, queryA], 1, handler); expect(res).toEqual([ expect.objectContaining({ entity: eventsA[0], query: queryA }), expect.objectContaining({ entity: eventsB[0], query: queryB }), expect.objectContaining({ entity: eventsA[1], query: queryA }), ]); }); it('walk over events in order without a pageSize defined (3 events)', async () => { const { data: entityA } = await ds.create(modelNames[0], { firstname: 'John', }); const { data: entityB } = await ds.create(modelNames[1], { firstname: 'John', }); const { data: entityC } = await ds.create(modelNames[0], { firstname: 'John', }); const { data: eventsA } = await ds.allEvents(modelNames[0], {}); const { data: eventsB } = await ds.allEvents(modelNames[1], {}); const queryA = { datastore: 'default', model: modelNames[0], query: {}, source: 'events', }; const queryB = { datastore: 'default', model: modelNames[1], query: {}, source: 'events', }; // @ts-ignore await utils.walkMulti(datastores, [queryB, queryA], undefined, handler); expect(res).toEqual([ expect.objectContaining({ entity: eventsA[0], query: queryA }), expect.objectContaining({ entity: eventsB[0], query: queryB }), expect.objectContaining({ entity: eventsA[1], query: queryA }), ]); }); it('walk over events in order with a pageSize of 2 (3 events)', async () => { const { data: entityA } = await ds.create(modelNames[0], { firstname: 'John', }); const { data: entityB } = await ds.create(modelNames[1], { firstname: 'John', }); const { data: entityC } = await ds.create(modelNames[0], { firstname: 'John', }); const { data: eventsA } = await ds.allEvents(modelNames[0], {}); const { data: eventsB } = await ds.allEvents(modelNames[1], {}); const queryA = { datastore: 'default', model: modelNames[0], query: {}, source: 'events', }; const queryB = { datastore: 'default', model: modelNames[1], query: {}, source: 'events', }; // @ts-ignore await utils.walkMulti(datastores, [queryB, queryA], 2, handler); expect(res).toEqual([ expect.objectContaining({ entity: eventsA[0], query: queryA }), expect.objectContaining({ entity: eventsB[0], query: queryB }), expect.objectContaining({ entity: eventsA[1], query: queryA }), ]); }); it('(backward) walk over entities in order with exact same `created_at` timestamp', async () => { const createdAt = new Date(); const { data: entityA } = await ds.create( modelNames[0], { firstname: 'Alice' }, { 'created-at': createdAt.toISOString() }, ); const { data: entityC } = await ds.create( modelNames[0], { firstname: 'Eve' }, { 'created-at': createdAt.toISOString() }, ); const _walkNext = ds.walkNext; function mockWalkNext( model: string, query: object, source: string, page: number, pageSize: number, opts: { current_version: number; version_ordered?: boolean; cursor_last_id?: string; cursor_last_correlation_id: string; headers?: any; }, ) { opts.cursor_last_correlation_id = ''; return _walkNext.call(ds, model, query, source, page, pageSize, opts); } ds.walkNext = mockWalkNext.bind(ds); const queryA = { datastore: 'default', model: modelNames[0], query: {}, source: 'entities', }; // @ts-ignore await utils.walkMulti(datastores, [queryA], 1, handler); expect(res).toHaveLength(2); ds.walkNext = _walkNext; }); it('(backward) walk over entities in order with exact same `created_at` timestamp', async () => { const createdAt = new Date(); const { data: entityA } = await ds.create( modelNames[0], { firstname: 'Alice' }, { 'created-at': createdAt.toISOString() }, ); const { data: entityC } = await ds.create( modelNames[0], { firstname: 'Eve' }, { 'created-at': createdAt.toISOString() }, ); const _walkNext = ds.walkNext; function mockWalkNext( model: string, query: object, source: string, page: number, pageSize: number, opts: { current_version: number; version_ordered?: boolean; cursor_last_id?: string; cursor_last_correlation_id: string; headers?: any; }, ) { opts.cursor_last_correlation_id = ''; return _walkNext.call(ds, model, query, source, page, pageSize, opts); } ds.walkNext = mockWalkNext.bind(ds); const queryA = { datastore: 'default', model: modelNames[0], query: { _sort: { created_at: -1 } }, source: 'entities', }; // @ts-ignore await utils.walkMulti(datastores, [queryA], 1, handler); expect(res).toHaveLength(2); ds.walkNext = _walkNext; }); it('(backward) walk over events in order with exact same `created_at` timestamp', async () => { const createdAt = new Date(); const { data: entityA } = await ds.create( modelNames[0], { firstname: 'Alice' }, { 'created-at': createdAt.toISOString() }, ); const { data: entityC } = await ds.create( modelNames[0], { firstname: 'Eve' }, { 'created-at': createdAt.toISOString() }, ); const _walkNext = ds.walkNext; function mockWalkNext( model: string, query: object, source: string, page: number, pageSize: number, opts: { current_version: number; version_ordered?: boolean; cursor_last_id?: string; cursor_last_correlation_id: string; headers?: any; }, ) { opts.cursor_last_correlation_id = ''; return _walkNext.call(ds, model, query, source, page, pageSize, opts); } ds.walkNext = mockWalkNext.bind(ds); const queryA = { datastore: 'default', model: modelNames[0], query: {}, source: 'events', }; // @ts-ignore await utils.walkMulti(datastores, [queryA], 1, handler); expect(res).toHaveLength(2); ds.walkNext = _walkNext; }); it('walk over entities in order with exact same `created_at` timestamp', async () => { const createdAt = new Date(); const { data: entityA } = await ds.create( modelNames[0], { firstname: 'Alice' }, { 'created-at': createdAt.toISOString() }, ); const { data: entityB } = await ds.create( modelNames[1], { firstname: 'Bernard' }, { 'created-at': createdAt.toISOString() }, ); const { data: entityC } = await ds.create( modelNames[0], { firstname: 'Eve' }, { 'created-at': createdAt.toISOString() }, ); const { data: eventsA } = await ds.allEvents(modelNames[0], {}); const { data: eventsB } = await ds.allEvents(modelNames[1], {}); const queryA = { datastore: 'default', model: modelNames[0], query: { _sort: { created_at: -1 } }, source: 'entities', }; const queryB = { datastore: 'default', model: modelNames[1], query: { _sort: { created_at: -1 } }, source: 'entities', }; // @ts-ignore await utils.walkMulti(datastores, [queryB, queryA], 1, handler); expect(res).toHaveLength(3); }); it('walk over events in order with exact same `created_at` timestamp', async () => { const createdAt = new Date(); const { data: entityA } = await ds.create( modelNames[0], { firstname: 'Alice' }, { 'created-at': createdAt.toISOString() }, ); const { data: entityB } = await ds.create( modelNames[1], { firstname: 'Bernard' }, { 'created-at': createdAt.toISOString() }, ); const { data: entityC } = await ds.create( modelNames[0], { firstname: 'Eve' }, { 'created-at': createdAt.toISOString() }, ); const { data: eventsA } = await ds.allEvents(modelNames[0], {}); const { data: eventsB } = await ds.allEvents(modelNames[1], {}); const queryA = { datastore: 'default', model: modelNames[0], query: {}, source: 'events', }; const queryB = { datastore: 'default', model: modelNames[1], query: {}, source: 'events', }; // @ts-ignore await utils.walkMulti(datastores, [queryB, queryA], 1, handler); expect(res).toHaveLength(3); }); it('walk over events in order with exact same `created_at` timestamp and fields filtering', async () => { const createdAt = new Date(); const { data: entityA } = await ds.create( modelNames[0], { firstname: 'Alice' }, { 'created-at': createdAt.toISOString() }, ); const { data: entityB } = await ds.create( modelNames[1], { firstname: 'Bernard' }, { 'created-at': createdAt.toISOString() }, ); const { data: entityC } = await ds.create( modelNames[0], { firstname: 'Eve' }, { 'created-at': createdAt.toISOString() }, ); const { data: eventsA } = await ds.allEvents(modelNames[0], {}); const { data: eventsB } = await ds.allEvents(modelNames[1], {}); const queryA = { datastore: 'default', model: modelNames[0], query: { _fields: { firstname: 1 } }, source: 'events', }; const queryB = { datastore: 'default', model: modelNames[1], query: { _fields: { firstname: 1 } }, source: 'events', }; // @ts-ignore await utils.walkMulti(datastores, [queryB, queryA], 1, handler); expect(res.map((r) => r.entity.firstname)).toEqual([ 'Bernard', 'Alice', 'Eve', ]); }); it('walk over events in temporal order and not version order', async () => { const { data: entityA } = await ds.create(modelNames[0], { firstname: 'Alice', }); const { data: entityB } = await ds.create(modelNames[1], { firstname: 'Bernard', }); await ds.update(modelNames[0], entityA.correlation_id, { firstname: 'Alizzz', }); const { data: entityC } = await ds.create(modelNames[0], { firstname: 'Eve', }); const { data: eventsA } = await ds.allEvents(modelNames[0], {}); const { data: eventsB } = await ds.allEvents(modelNames[1], {}); const queryA = { datastore: 'default', model: modelNames[0], query: {}, source: 'events', }; const queryB = { datastore: 'default', model: modelNames[1], query: {}, source: 'events', }; // @ts-ignore await utils.walkMulti(datastores, [queryB, queryA], 2, handler, { version_ordered: false, }); expect(res).toEqual([ expect.objectContaining({ entity: eventsA[0], query: queryA }), expect.objectContaining({ entity: eventsB[0], query: queryB }), expect.objectContaining({ entity: eventsA[1], query: queryA }), expect.objectContaining({ entity: eventsA[2], query: queryA }), ]); }); it('walk over events in temporal order and not version order with a handle in order', async () => { const { data: entityA } = await ds.create(modelNames[0], { firstname: 'Alice', }); const { data: entityB } = await ds.create(modelNames[1], { firstname: 'Bernard', }); await ds.update(modelNames[0], entityA.correlation_id, { firstname: 'Alizzz', }); const { data: entityC } = await ds.create(modelNames[0], { firstname: 'Eve', }); const { data: eventsA } = await ds.allEvents(modelNames[0], {}); const { data: eventsB } = await ds.allEvents(modelNames[1], {}); const queryA = { datastore: 'default', model: modelNames[0], query: {}, source: 'events', }; const queryB = { datastore: 'default', model: modelNames[1], query: {}, source: 'events', }; // @ts-ignore await utils.walkMulti(datastores, [queryB, queryA], 2, handler, { version_ordered: false, handle_in_order: true, }); expect(res).toEqual([ expect.objectContaining({ entity: eventsA[0], query: queryA, batch_id: 0, index: 0, }), expect.objectContaining({ entity: eventsB[0], query: queryB, batch_id: 1, index: 0, }), expect.objectContaining({ entity: eventsA[1], query: queryA, batch_id: 0, index: 0, }), expect.objectContaining({ entity: eventsA[2], query: queryA, batch_id: 1, index: 0, }), ]); }); it('walk over events in temporal order and not version order with a handle in parallel', async () => { const { data: entityA } = await ds.create(modelNames[0], { firstname: 'Alice', }); const { data: entityB } = await ds.create(modelNames[1], { firstname: 'Bernard', }); await ds.update(modelNames[0], entityA.correlation_id, { firstname: 'Alizzz', }); const { data: entityC } = await ds.create(modelNames[0], { firstname: 'Eve', }); const { data: eventsA } = await ds.allEvents(modelNames[0], {}); const { data: eventsB } = await ds.allEvents(modelNames[1], {}); const queryA = { datastore: 'default', model: modelNames[0], query: {}, source: 'events', }; const queryB = { datastore: 'default', model: modelNames[1], query: {}, source: 'events', }; // @ts-ignore await utils.walkMulti(datastores, [queryB, queryA], 4, handler, { version_ordered: false, handle_in_parallel: true, }); expect(res).toEqual([ expect.objectContaining({ entity: eventsA[0], query: queryA, batch_id: 0, index: 0, }), expect.objectContaining({ entity: eventsB[0], query: queryB, batch_id: 0, index: 1, }), expect.objectContaining({ entity: eventsA[1], query: queryA, batch_id: 0, index: 2, }), expect.objectContaining({ entity: eventsA[2], query: queryA, batch_id: 0, index: 3, }), ]); }); it('walk over events in order of versions', async () => { const { data: entityA } = await ds.create(modelNames[0], { firstname: 'Alice', }); const { data: entityB } = await ds.create(modelNames[1], { firstname: 'Bernard', }); await ds.update(modelNames[0], entityA.correlation_id, { firstname: 'Alizzz', }); const { data: entityC } = await ds.create(modelNames[0], { firstname: 'Eve', }); const { data: eventsA } = await ds.allEvents(modelNames[0], {}); const { data: eventsB } = await ds.allEvents(modelNames[1], {}); const queryA = { datastore: 'default', model: modelNames[0], query: {}, source: 'events', }; const queryB = { datastore: 'default', model: modelNames[1], query: {}, source: 'events', }; // @ts-ignore await utils.walkMulti(datastores, [queryB, queryA], 2, handler, { version_ordered: true, }); expect(res).toEqual([ expect.objectContaining({ entity: eventsA[0], query: queryA }), expect.objectContaining({ entity: eventsB[0], query: queryB }), expect.objectContaining({ entity: eventsA[2], query: queryA }), expect.objectContaining({ entity: eventsA[1], query: queryA }), ]); }); }); describe('#walkMulti (with mutation)', () => { let uuid; beforeEach(() => { uuid = setup.uuid(); }); it('walk over entities without any mutation', async () => { const { data: alice } = await ds.create(modelNames[0], { mutated_attribute: 'created', firstname: 'alice', }); const { data: bernard } = await ds.create(modelNames[0], { mutated_attribute: 'created', firstname: 'bernard', }); const queryA = { datastore: 'default', model: modelNames[0], query: { mutated_attribute: 'created' }, source: 'entities' as 'entities', }; // @ts-ignore await utils.walkMulti( datastores, [queryA], 1, async (result) => { // Noop res.push(result); }, { is_mutating: true }, ); // Then expect(res).toHaveLength(2); expect(res).toEqual([alice, bernard]); }); it('walk over entities with total mutation', async () => { const { data: alice } = await ds.create(modelNames[0], { mutated_attribute: 'created', firstname: 'alice', }); const { data: bernard } = await ds.create(modelNames[0], { mutated_attribute: 'created', firstname: 'bernard', }); const queryA = { datastore: 'default', model: modelNames[0], query: { mutated_attribute: 'created' }, source: 'entities' as 'entities', }; // @ts-ignore await utils.walkMulti( datastores, [queryA], 1, async (result) => { const { data: mutatedResult } = await ds.update( modelNames[0], result.correlation_id, { mutated_attribute: 'consumed' }, ); res.push(result); }, { is_mutating: true }, ); // Then expect(res).toHaveLength(2); expect(res).toEqual([alice, bernard]); }); it('walk over entities with partial mutation', async () => { const { data: alice } = await ds.create(modelNames[0], { mutated_attribute: 'created', firstname: 'alice', }); const { data: bernard } = await ds.create(modelNames[0], { mutated_attribute: 'created', firstname: 'bernard', }); const queryA = { datastore: 'default', model: modelNames[0], query: { mutated_attribute: 'created' }, source: 'entities' as 'entities', }; const mutatedEntities: unknown[] = []; // @ts-ignore await utils.walkMulti( datastores, [queryA], 1, async (result) => { res.push(result); if (result.firstname === 'alice') { return; } const { data: mutatedResult } = await ds.update( modelNames[0], result.correlation_id, { mutated_attribute: 'consumed' }, ); mutatedEntities.push(mutatedResult); }, { is_mutating: true }, ); // Then expect(res).toHaveLength(2); expect(res).toEqual([alice, bernard]); expect(mutatedEntities).toHaveLength(1); expect(mutatedEntities).toMatchObject([ { mutated_attribute: 'consumed', firstname: 'bernard', version: 1 }, ]); }); it('walk over entities with mutation with sort order on another field', async () => { const { data: alice } = await ds.create(modelNames[0], { mutated_attribute: 'created', firstname: 'alice', }); const { data: bernard } = await ds.create(modelNames[0], { mutated_attribute: 'created', firstname: 'bernard', }); const queryA = { datastore: 'default', model: modelNames[0], query: { mutated_attribute: 'created', _sort: { firstname: -1 } }, source: 'entities' as 'entities', }; const mutatedEntities: unknown[] = []; // @ts-ignore await utils.walkMulti( datastores, [queryA], 1, async (result) => { res.push(result); const { data: mutatedResult } = await ds.update( modelNames[0], result.correlation_id, { mutated_attribute: 'consumed' }, ); mutatedEntities.push(mutatedResult); }, { is_mutating: true }, ); // Then expect(res).toHaveLength(2); expect(res).toEqual([alice, bernard]); }); it('walk over entities with high number of entities', async () => { for (let i = 0; i < 50; i++) { const { data: alice } = await ds.create(modelNames[0], { mutated_attribute: 'created', firstname: `alice-${i}`, }); } const queryA = { datastore: 'default', model: modelNames[0], query: { mutated_attribute: 'created' }, source: 'entities' as 'entities', }; // @ts-ignore await utils.walkMulti( datastores, [queryA], 1, async (result) => { res.push(result); await ds.update(modelNames[0], result.correlation_id, { mutated_attribute: 'consumed', }); }, { is_mutating: true }, ); // Then expect(res).toHaveLength(50); }); it('walk over entities with high number of entities and page size of 5', async () => { for (let i = 0; i < 50; i++) { const { data: alice } = await ds.create(modelNames[0], { mutated_attribute: 'created', firstname: `alice-${i}`, }); } const queryA = { datastore: 'default', model: modelNames[0], query: { mutated_attribute: 'created' }, source: 'entities' as 'entities', }; // @ts-ignore await utils.walkMulti( datastores, [queryA], 5, async (result) => { res.push(result); await ds.update(modelNames[0], result.correlation_id, { mutated_attribute: 'consumed', }); }, { is_mutating: true }, ); // Then expect(res).toHaveLength(50); }); it('walk over entities with high number of entities and page size of 7 for 50 entities', async () => { for (let i = 0; i < 50; i++) { const { data: alice } = await ds.create(modelNames[0], { mutated_attribute: 'created', firstname: `alice-${i}`, }); } const queryA = { datastore: 'default', model: modelNames[0], query: { mutated_attribute: 'created' }, source: 'entities' as 'entities', }; // @ts-ignore await utils.walkMulti( datastores, [queryA], 7, async (result) => { res.push(result); await ds.update(modelNames[0], result.correlation_id, { mutated_attribute: 'consumed', }); }, { is_mutating: true }, ); // Then expect(res).toHaveLength(50); }); it('walk over entities from multiple triggers with mutation', async () => { const { data: alice } = await ds.create(modelNames[0], { mutated_attribute: 'created', firstname: 'alice', }); const { data: bernard } = await ds.create(modelNames[1], { mutated_attribute: 'created', firstname: 'bernard', }); const queryA = { datastore: 'default', model: modelNames[0], query: { mutated_attribute: 'created' }, source: 'entities' as 'entities', }; const queryB = { datastore: 'default', model: modelNames[1], query: { mutated_attribute: 'created' }, source: 'entities' as 'entities', }; const mutatedEntities: unknown[] = []; // @ts-ignore await utils.walkMulti( datastores, [queryA, queryB], 1, async (result, query) => { res.push(result); const { data: mutatedResult } = await ds.update( query.model, result.correlation_id, { mutated_attribute: 'consumed' }, ); mutatedEntities.push(mutatedResult); }, { is_mutating: true }, ); // Then expect(res).toHaveLength(2); expect(res).toEqual([alice, bernard]); }); it('walk over entities changing the order', async () => { const { data: alice } = await ds.create(modelNames[0], { mutated_attribute: 'created', firstname: 'alice', }); const { data: bernard } = await ds.create(modelNames[0], { mutated_attribute: 'created', firstname: 'bernard', }); const queryA = { datastore: 'default', model: modelNames[0], query: { _sort: { firstname: 1 } }, source: 'entities' as 'entities', }; const mutatedEntities: unknown[] = []; // @ts-ignore await utils.walkMulti( datastores, [queryA], 1, async (result, query) => { res.push(result); if (result.firstname === 'alice') { const { data: mutatedResult } = await ds.update( query.model, result.correlation_id, { firstname: 'eve' }, ); mutatedEntities.push(mutatedResult); } }, { is_mutating: true }, ); // Then expect(res).toHaveLength(2); expect(res).toEqual([alice, bernard]); }); }); describe('#walkMulti (errors)', () => { let uuid; beforeEach(() => { uuid = setup.uuid(); }); it('error on invokation with mutation and `source=events`', async () => { let error; try { await utils.walkMulti( datastores, [ { datastore: 'default', model: modelNames[0], query: {}, source: 'events' as 'events', }, ], 1, async () => {}, { is_mutating: true }, ); } catch (err) { error = err; } expect(error).toHaveProperty( 'message', utils.ERRORS.INCOMPATIBLE_MUTATION_ON_EVENTS, ); }); it('error on invokation with mutation and `source=events`', async () => { let error; try { await utils.walkMulti( datastores, [ { datastore: 'default', model: modelNames[0], query: {}, source: 'events' as 'events', }, ], 1, async () => {}, { handle_in_order: true, handle_in_parallel: true }, ); } catch (err) { error = err; } expect(error).toHaveProperty( 'message', utils.ERRORS.INCOMPATIBLE_MULTIPLE_HANDLE_OPTIONS, ); }); }); describe('#getLastMatchingCorrelationIdIndex', () => { it('returns -1 if no correlationId is defined in `before`', () => { // Given // When const index = utils.getLastMatchingCorrelationIdIndex([], []); // Then expect(index).toEqual(-1); }); it('returns -1 if the last correlationId from `before` is not found in `after`', () => { // Given // When const index = utils.getLastMatchingCorrelationIdIndex( ['id-0', 'id-1'], [], ); // Then expect(index).toEqual(-1); }); it('returns 0 if the last correlationId from `before` is found at first place in `after`', () => { // Given // When const index = utils.getLastMatchingCorrelationIdIndex( ['id-0', 'id-1'], ['id-1'], ); // Then expect(index).toEqual(0); }); it('returns 1 if the last correlationId from `before` is found at second place in `after`', () => { // Given // When const index = utils.getLastMatchingCorrelationIdIndex( ['id-0', 'id-1', 'id-2'], // id-0 would have been mutated ['id-1', 'id-2', 'id-3'], ); // Then expect(index).toEqual(1); }); }); });