UNPKG

@getanthill/datastore

Version:

Event-Sourced Datastore

529 lines (464 loc) 14.3 kB
import setup from '../../test/setup'; import PostgreSQLClient from './pg'; describe('services/pg', () => { let pg; let app; beforeEach(async () => { app = await setup.build(); await PostgreSQLClient.init(app.services.config.pg); pg = new PostgreSQLClient(app.services.config.pg); await pg.connect(); }); afterEach(async () => { jest.resetAllMocks(); await pg.disconnect(); await setup.teardownDb(app.services.mongodb); }); describe('#connect / #end', () => { it('invokes the client connect on connect', async () => { await pg.disconnect(); pg = new PostgreSQLClient(app.services.config.pg); jest.spyOn(pg._client, 'connect').mockImplementation(() => null); await pg.connect(); expect(pg._client.connect).toHaveBeenCalledTimes(1); }); it('allows to invoke the connect several times safely', async () => { jest.spyOn(pg._client, 'connect').mockImplementation(() => null); await pg.connect(); await pg.connect(); expect(pg._client.connect).toHaveBeenCalledTimes(2); }); it('invokes the client end on disconnect', async () => { await pg.disconnect(); pg = new PostgreSQLClient(app.services.config.pg); jest.spyOn(pg._client, 'end').mockImplementation(() => null); await pg.disconnect(); expect(pg._client.end).toHaveBeenCalledTimes(1); }); it('allows to invokes the client end several times', async () => { jest.spyOn(pg._client, 'end'); await pg.disconnect(); await pg.disconnect(); expect(pg._client.end).toHaveBeenCalledTimes(2); }); }); describe('#getSqlSchemaForModelDeletion', () => { it('returns SQL to delete model tables', () => { expect( PostgreSQLClient.getSqlSchemaForModelDeletion({ name: 'users', correlation_field: 'user_id', }), ).toMatchSnapshot(); }); }); describe('#getSqlSchemaForModel', () => { it('returns SQL to create model tables', () => { expect( PostgreSQLClient.getSqlSchemaForModel({ name: 'users', correlation_field: 'user_id', }), ).toMatchSnapshot(); }); it('returns SQL to create model tables with database source name', () => { expect( PostgreSQLClient.getSqlSchemaForModel( { name: 'users', correlation_field: 'user_id', }, 'entities', ), ).toMatchSnapshot(); }); it('returns SQL to create model tables with comments', () => { expect( PostgreSQLClient.getSqlSchemaForModel({ name: 'users', correlation_field: 'user_id', description: 'Users information', }), ).toMatchSnapshot(); }); it('creates the tables effectively', async () => { const sql = PostgreSQLClient.getSqlSchemaForModels( [ { name: 'users', correlation_field: 'user_id', description: 'Users information', }, ], true, ); await pg.queryAll(sql); const d = await pg.query(`SELECT table_name, column_name, data_type FROM information_schema.columns WHERE table_name = 'users';`); expect(d.rows).toEqual([ { column_name: 'created_at', data_type: 'timestamp with time zone', table_name: 'users', }, { column_name: 'updated_at', data_type: 'timestamp with time zone', table_name: 'users', }, { column_name: 'version', data_type: 'bigint', table_name: 'users' }, { column_name: 'entity', data_type: 'json', table_name: 'users' }, { column_name: 'user_id', data_type: 'text', table_name: 'users' }, ]); }); }); describe('#getSqlSchemaFromModels', () => { it('returns SQL to create all model tables', () => { expect( PostgreSQLClient.getSqlSchemaForModels([ { name: 'users', correlation_field: 'user_id', }, { name: 'accounts', correlation_field: 'account_id', }, ]), ).toMatchSnapshot(); }); it('returns SQL to create all model tables with comments', () => { expect( PostgreSQLClient.getSqlSchemaForModels([ { name: 'users', correlation_field: 'user_id', description: 'Users information', }, { name: 'accounts', correlation_field: 'account_id', description: 'Accounts information', }, ]), ).toMatchSnapshot(); }); it('returns SQL to delete then create all model tables', () => { expect( PostgreSQLClient.getSqlSchemaForModels( [ { name: 'users', correlation_field: 'user_id', }, { name: 'accounts', correlation_field: 'account_id', }, ], true, ), ).toMatchSnapshot(); }); }); describe('#insert', () => { it('inserts an entity effectively', async () => { const modelConfig = { name: 'users', correlation_field: 'user_id', description: 'Users information', }; await pg.queryAll( PostgreSQLClient.getSqlSchemaForModels([modelConfig], true), ); const res = await pg.insert(modelConfig, 'entities', { user_id: 'user_id', created_at: '2021-01-01T00:00:00.000Z', updated_at: '2021-01-01T00:00:00.000Z', version: 0, }); expect(res.rowCount).toEqual(1); const result = await pg.query( `SELECT * FROM users WHERE user_id='user_id'`, ); expect(result.rows).toEqual([ { created_at: new Date('2021-01-01T00:00:00.000Z'), entity: { created_at: '2021-01-01T00:00:00.000Z', updated_at: '2021-01-01T00:00:00.000Z', user_id: 'user_id', version: 0, }, updated_at: new Date('2021-01-01T00:00:00.000Z'), user_id: 'user_id', version: '0', }, ]); }); it('updates an entity effectively', async () => { const modelConfig = { name: 'users', correlation_field: 'user_id', description: 'Users information', }; await pg.queryAll( PostgreSQLClient.getSqlSchemaForModels([modelConfig], true), ); const res0 = await pg.insert(modelConfig, 'entities', { user_id: 'user_id', created_at: '2021-01-01T00:00:00.000Z', updated_at: '2021-01-01T00:00:00.000Z', version: 0, }); const res1 = await pg.insert(modelConfig, 'entities', { user_id: 'user_id', created_at: '2021-01-01T00:00:00.000Z', updated_at: '2021-01-02T00:00:00.000Z', version: 1, }); expect(res1.rowCount).toEqual(1); const result = await pg.query( `SELECT * FROM users WHERE user_id='user_id'`, ); expect(result.rows).toEqual([ { created_at: new Date('2021-01-01T00:00:00.000Z'), entity: { created_at: '2021-01-01T00:00:00.000Z', updated_at: '2021-01-02T00:00:00.000Z', user_id: 'user_id', version: 1, }, updated_at: new Date('2021-01-02T00:00:00.000Z'), user_id: 'user_id', version: '1', }, ]); }); it('keeps encrypted data from entity on insert if requested', async () => { const modelConfig = { name: 'users', correlation_field: 'user_id', description: 'Users information', encrypted_fields: ['firstname'], }; await pg.queryAll( PostgreSQLClient.getSqlSchemaForModels([modelConfig], true), ); const res = await pg.insert( modelConfig, 'entities', { user_id: 'user_id', created_at: '2021-01-01T00:00:00.000Z', updated_at: '2021-01-01T00:00:00.000Z', version: 0, firstname: { hash: 'hash', encrypted: 'encrypted', }, }, { with_encrypted_data: true, }, ); expect(res.rowCount).toEqual(1); const result = await pg.query( `SELECT * FROM users WHERE user_id='user_id'`, ); expect(result.rows).toEqual([ { created_at: new Date('2021-01-01T00:00:00.000Z'), entity: { created_at: '2021-01-01T00:00:00.000Z', updated_at: '2021-01-01T00:00:00.000Z', user_id: 'user_id', version: 0, firstname: { hash: 'hash', encrypted: 'encrypted', }, }, updated_at: new Date('2021-01-01T00:00:00.000Z'), user_id: 'user_id', version: '0', }, ]); }); it('removes encrypted data from entity on insert by default', async () => { const modelConfig = { name: 'users', correlation_field: 'user_id', description: 'Users information', encrypted_fields: ['firstname'], }; await pg.queryAll( PostgreSQLClient.getSqlSchemaForModels([modelConfig], true), ); const res = await pg.insert(modelConfig, 'entities', { user_id: 'user_id', created_at: '2021-01-01T00:00:00.000Z', updated_at: '2021-01-01T00:00:00.000Z', version: 0, firstname: { hash: 'hash', encrypted: 'encrypted', }, }); expect(res.rowCount).toEqual(1); const result = await pg.query( `SELECT * FROM users WHERE user_id='user_id'`, ); expect(result.rows).toEqual([ { created_at: new Date('2021-01-01T00:00:00.000Z'), entity: { created_at: '2021-01-01T00:00:00.000Z', updated_at: '2021-01-01T00:00:00.000Z', user_id: 'user_id', version: 0, firstname: { hash: 'hash', }, }, updated_at: new Date('2021-01-01T00:00:00.000Z'), user_id: 'user_id', version: '0', }, ]); }); it('inserts an event effectively', async () => { const modelConfig = { name: 'users', correlation_field: 'user_id', description: 'Users information', }; await pg.queryAll( PostgreSQLClient.getSqlSchemaForModels([modelConfig], true), ); const res = await pg.insert(modelConfig, 'events', { user_id: 'user_id', type: 'CREATED', created_at: '2021-01-01T00:00:00.000Z', version: 0, }); expect(res.rowCount).toEqual(1); const result = await pg.query( `SELECT * FROM users_events WHERE user_id='user_id'`, ); expect(result.rows).toEqual([ { created_at: new Date('2021-01-01T00:00:00.000Z'), event: { created_at: '2021-01-01T00:00:00.000Z', type: 'CREATED', user_id: 'user_id', version: 0, }, type: 'CREATED', user_id: 'user_id', version: '0', }, ]); }); it('updates an event on contraint violation', async () => { const modelConfig = { name: 'users', correlation_field: 'user_id', description: 'Users information', }; await pg.queryAll( PostgreSQLClient.getSqlSchemaForModels([modelConfig], true), ); const res0 = await pg.insert(modelConfig, 'events', { user_id: 'user_id', type: 'CREATED', created_at: '2021-01-01T00:00:00.000Z', version: 0, }); const res1 = await pg.insert(modelConfig, 'events', { user_id: 'user_id', type: 'CREATED', created_at: '2021-01-02T00:00:00.000Z', version: 0, }); expect(res0.rowCount).toEqual(1); const result = await pg.query( `SELECT * FROM users_events WHERE user_id='user_id'`, ); expect(result.rows).toEqual([ { created_at: new Date('2021-01-02T00:00:00.000Z'), event: { created_at: '2021-01-02T00:00:00.000Z', type: 'CREATED', user_id: 'user_id', version: 0, }, type: 'CREATED', user_id: 'user_id', version: '0', }, ]); }); it('inserts multiple events effectively', async () => { const modelConfig = { name: 'users', correlation_field: 'user_id', description: 'Users information', }; await pg.queryAll( PostgreSQLClient.getSqlSchemaForModels([modelConfig], true), ); const res0 = await pg.insert(modelConfig, 'events', { user_id: 'user_id', type: 'CREATED', created_at: '2021-01-01T00:00:00.000Z', version: 0, }); const res1 = await pg.insert(modelConfig, 'events', { user_id: 'user_id', type: 'CREATED', created_at: '2021-01-02T00:00:00.000Z', version: 1, }); expect(res1.rowCount).toEqual(1); const result = await pg.query( `SELECT * FROM users_events WHERE user_id='user_id'`, ); expect(result.rows).toEqual([ { created_at: new Date('2021-01-01T00:00:00.000Z'), event: { created_at: '2021-01-01T00:00:00.000Z', type: 'CREATED', user_id: 'user_id', version: 0, }, type: 'CREATED', user_id: 'user_id', version: '0', }, { created_at: new Date('2021-01-02T00:00:00.000Z'), event: { created_at: '2021-01-02T00:00:00.000Z', type: 'CREATED', user_id: 'user_id', version: 1, }, type: 'CREATED', user_id: 'user_id', version: '1', }, ]); }); }); });