From 40da447c6642789c1464adce9a4db59fd4a55c72 Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Sun, 30 Jul 2023 22:19:19 +0200 Subject: [PATCH 01/35] DPP-1 WIP --- .../src/__tests__/contact.entities.test.ts | 1688 +++++++++++++++-- .../src/__tests__/contact.store.test.ts | 911 ++++++--- .../src/contact/AbstractContactStore.ts | 6 +- .../data-store/src/contact/ContactStore.ts | 312 ++- .../src/entities/contact/BaseConfigEntity.ts | 50 + .../src/entities/contact/ConnectionEntity.ts | 32 +- .../src/entities/contact/ContactEntity.ts | 125 +- .../entities/contact/ContactOwnerEntity.ts | 82 + .../contact/ContactRelationshipEntity.ts | 76 + .../src/entities/contact/ContactTypeEntity.ts | 91 + .../contact/CorrelationIdentifierEntity.ts | 22 +- .../entities/contact/DidAuthConfigEntity.ts | 3 +- .../src/entities/contact/IdentityEntity.ts | 35 +- .../contact/IdentityMetadataItemEntity.ts | 22 +- .../entities/contact/OpenIdConfigEntity.ts | 2 +- .../entities/contact/OrganizationEntity.ts | 59 + .../src/entities/contact/PersonEntity.ts | 62 + packages/data-store/src/index.ts | 10 + .../types/contact/IAbstractContactStore.ts | 32 +- .../data-store/src/types/contact/contact.ts | 90 +- packages/data-store/src/types/index.ts | 1 + .../src/types/validation/validation.ts | 3 + .../data-store/src/utils/ValidatorUtils.ts | 10 + 23 files changed, 3102 insertions(+), 622 deletions(-) create mode 100644 packages/data-store/src/entities/contact/ContactOwnerEntity.ts create mode 100644 packages/data-store/src/entities/contact/ContactRelationshipEntity.ts create mode 100644 packages/data-store/src/entities/contact/ContactTypeEntity.ts create mode 100644 packages/data-store/src/entities/contact/OrganizationEntity.ts create mode 100644 packages/data-store/src/entities/contact/PersonEntity.ts create mode 100644 packages/data-store/src/types/validation/validation.ts create mode 100644 packages/data-store/src/utils/ValidatorUtils.ts diff --git a/packages/data-store/src/__tests__/contact.entities.test.ts b/packages/data-store/src/__tests__/contact.entities.test.ts index d2a69185f..78604a4eb 100644 --- a/packages/data-store/src/__tests__/contact.entities.test.ts +++ b/packages/data-store/src/__tests__/contact.entities.test.ts @@ -1,24 +1,34 @@ -import { DataSource } from 'typeorm' +import { DataSource, FindOptionsWhere } from 'typeorm' +import { DataStoreContactEntities } from '../index' import { + IBasicContact, + ContactTypeEnum, + IPerson, + IOrganization, + IdentityRoleEnum, CorrelationIdentifierEnum, - DataStoreContactEntities, - DataStoreMigrations, - contactEntityFrom, - connectionEntityFrom, - identityEntityFrom, - didAuthConfigEntityFrom, - openIdConfigEntityFrom, - ContactEntity, - IdentityEntity, ConnectionTypeEnum, - OpenIdConfigEntity, - DidAuthConfigEntity, - ConnectionEntity, - CorrelationIdentifierEntity, - IdentityMetadataItemEntity, - IdentityRoleEnum, -} from '../index' + BasicContactType, + BasicOrganization, + BasicPerson, + IBasicConnection, + IBasicIdentity, + BasicDidAuthConfig, + BasicOpenIdConfig, +} from '../types' +import { PersonEntity, personEntityFrom } from '../entities/contact/PersonEntity' +import { OrganizationEntity, organizationEntityFrom } from '../entities/contact/OrganizationEntity' +import { ContactRelationshipEntity, contactRelationshipEntityFrom } from '../entities/contact/ContactRelationshipEntity' +import { ContactTypeEntity, contactTypeEntityFrom } from '../entities/contact/ContactTypeEntity' +import { ContactEntity, contactEntityFrom } from '../entities/contact/ContactEntity' +import { IdentityEntity, identityEntityFrom } from '../entities/contact/IdentityEntity' +import { OpenIdConfigEntity, openIdConfigEntityFrom } from '../entities/contact/OpenIdConfigEntity' +import { DidAuthConfigEntity, didAuthConfigEntityFrom } from '../entities/contact/DidAuthConfigEntity' +import { ConnectionEntity, connectionEntityFrom } from '../entities/contact/ConnectionEntity' +import { CorrelationIdentifierEntity } from '../entities/contact/CorrelationIdentifierEntity' +import { IdentityMetadataItemEntity } from '../entities/contact/IdentityMetadataItemEntity' +import { ContactOwnerEntity } from '../entities/contact/ContactOwnerEntity' describe('Database entities tests', (): void => { let dbConnection: DataSource @@ -29,44 +39,316 @@ describe('Database entities tests', (): void => { database: ':memory:', //logging: 'all', migrationsRun: false, - migrations: DataStoreMigrations, - synchronize: false, + // migrations: DataStoreMigrations, + synchronize: true, //false entities: DataStoreContactEntities, }).initialize() - await dbConnection.runMigrations() - expect(await dbConnection.showMigrations()).toBeFalsy() + // await dbConnection.runMigrations() + // expect(await dbConnection.showMigrations()).toBeFalsy() }) afterEach(async (): Promise => { await (await dbConnection).destroy() }) - it('Should save contact to database', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + it('Should save person contact to database', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + await dbConnection.getRepository(ContactEntity).save(contactEntity, { + transaction: true, + }) + + const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: contactEntity.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.identities?.length).toEqual(0) + expect(fromDb?.uri).toEqual(contact.uri) + expect(fromDb?.contactType).toBeDefined() + expect(fromDb?.contactType.type).toEqual(contact.contactType.type) + expect(fromDb?.contactType.tenantId).toEqual(contact.contactType.tenantId) + expect(fromDb?.contactType.name).toEqual(contact.contactType.name) + expect(fromDb?.contactOwner).toBeDefined() + expect((fromDb?.contactOwner).firstName).toEqual((contact.contactOwner).firstName) + expect((fromDb?.contactOwner).middleName).toEqual((contact.contactOwner).middleName) + expect((fromDb?.contactOwner).lastName).toEqual((contact.contactOwner).lastName) + expect((fromDb?.contactOwner).displayName).toEqual((contact.contactOwner).displayName) + }) + + it('Should save organization contact to database', async (): Promise => { + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.ORGANIZATION, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + legalName: 'example_legal_name', + displayName: 'example_display_name', + cocNumber: 'example_coc_number', + }, } const contactEntity: ContactEntity = contactEntityFrom(contact) - await dbConnection.getRepository(ContactEntity).save(contactEntity) + await dbConnection.getRepository(ContactEntity).save(contactEntity, { + transaction: true, + }) - const fromDb = await dbConnection.getRepository(ContactEntity).findOne({ - where: { name: contact.name }, + const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: contactEntity.id }, }) expect(fromDb).toBeDefined() expect(fromDb?.identities?.length).toEqual(0) - expect(fromDb?.name).toEqual(contact.name) - expect(fromDb?.alias).toEqual(contact.alias) expect(fromDb?.uri).toEqual(contact.uri) + expect(fromDb?.contactType).toBeDefined() + expect(fromDb?.contactType.type).toEqual(contact.contactType.type) + expect(fromDb?.contactType.tenantId).toEqual(contact.contactType.tenantId) + expect(fromDb?.contactType.name).toEqual(contact.contactType.name) + expect(fromDb?.contactOwner).toBeDefined() + expect((fromDb?.contactOwner).legalName).toEqual((contact.contactOwner).legalName) + expect((fromDb?.contactOwner).displayName).toEqual((contact.contactOwner).displayName) + expect((fromDb?.contactOwner).cocNumber).toEqual((contact.contactOwner).cocNumber) + }) + + it('Should result in contact relation for the owner side only', async (): Promise => { + const contact1: IBasicContact = { + uri: 'example1.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const contactEntity1: ContactEntity = contactEntityFrom(contact1) + const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + transaction: true, + }) + + const contact2: IBasicContact = { + uri: 'example2.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + + const contactEntity2: ContactEntity = contactEntityFrom(contact2) + const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + transaction: true, + }) + + const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ + left: savedContact1, + right: savedContact2, + }) + + await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { + transaction: true, + }) + + const fromDb1: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: savedContact1.id }, + }) + + const fromDb2: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: savedContact2.id }, + }) + + expect(fromDb1).toBeDefined() + expect(fromDb1?.relationships.length).toEqual(1) + expect(fromDb2).toBeDefined() + expect(fromDb2?.relationships.length).toEqual(0) + }) + + it('should throw error when saving person contact with blank first name', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: '', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrow('Blank first names are not allowed') + }) + + it('should throw error when saving person contact with blank middle name', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: '', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrow('Blank middle names are not allowed') + }) + + it('should throw error when saving person contact with blank last name', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: '', + displayName: 'example_display_name', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrow('Blank last names are not allowed') + }) + + it('should throw error when saving person contact with blank display name', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: '', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrow('Blank display names are not allowed') + }) + + it('should throw error when saving organization contact with blank legal name', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.ORGANIZATION, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + legalName: '', + displayName: 'example_legal_name', + cocNumber: 'example_coc_number', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrow('Blank legal names are not allowed') + }) + + it('should throw error when saving organization contact with blank display name', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.ORGANIZATION, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + legalName: 'example_first_name', + displayName: '', + cocNumber: '12345678ABC', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrow('Blank display names are not allowed') + }) + + it('should throw error when saving organization contact with blank coc number', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.ORGANIZATION, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + legalName: 'example_first_name', + displayName: 'example_display_name', + cocNumber: '', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrow('Blank coc numbers are not allowed') }) - it('should throw error when saving contact with blank name', async (): Promise => { - const contact = { - name: '', - alias: 'test_alias', + it('should throw error when saving contact with blank contact type name', async (): Promise => { + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: '', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } const contactEntity: ContactEntity = contactEntityFrom(contact) @@ -74,65 +356,132 @@ describe('Database entities tests', (): void => { await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrow('Blank names are not allowed') }) - it('should throw error when saving contact with blank alias', async (): Promise => { - const contact = { - name: 'test_name', - alias: '', + it('should throw error when saving contact with blank contact type description', async (): Promise => { + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + description: '', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } const contactEntity: ContactEntity = contactEntityFrom(contact) - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrow('Blank aliases are not allowed') + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrow('Blank descriptions are not allowed') }) - it('Should enforce unique name for a contact', async (): Promise => { - const contactName = 'non_unique_name' - const contact1 = { - name: contactName, - alias: 'unique_alias1', + it('should throw error when saving contact with blank contact type tenant id', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrow("Blank tenant id's are not allowed") + }) + + // TODO should wew enforce unique combinations of first/middle/last names + // Example, hans kraai, we have a jr and sr + it('Should enforce unique display name for a person contact', async (): Promise => { + const contactDisplayName = 'non_unique_name' + const contact1: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: contactDisplayName, + }, } const contact1Entity: ContactEntity = contactEntityFrom(contact1) await dbConnection.getRepository(ContactEntity).save(contact1Entity) - const contact2 = { - name: contactName, - alias: 'unique_alias2', + const contact2: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: contactDisplayName, + }, } const contact2Entity: ContactEntity = contactEntityFrom(contact2) await expect(dbConnection.getRepository(ContactEntity).save(contact2Entity)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: Contact.name' + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: contact_type_entity.name' ) }) - it('Should enforce unique alias for a contact', async (): Promise => { - const alias = 'non_unique_alias' - const contact1 = { - name: 'unique_name1', - alias, + it('Should enforce unique display name for a organization contact', async (): Promise => { + const contactDisplayName = 'non_unique_name' + const contact1: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.ORGANIZATION, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name', + }, + contactOwner: { + legalName: 'example_first_name', + displayName: contactDisplayName, + cocNumber: '12345678ABC', + }, } const contact1Entity: ContactEntity = contactEntityFrom(contact1) await dbConnection.getRepository(ContactEntity).save(contact1Entity) - const contact2 = { - name: 'unique_name2', - alias, + const contact2: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.ORGANIZATION, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + legalName: 'example_first_name', + displayName: contactDisplayName, + cocNumber: '12345678ABC', + }, } const contact2Entity: ContactEntity = contactEntityFrom(contact2) await expect(dbConnection.getRepository(ContactEntity).save(contact2Entity)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: Contact.alias' + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: contact_type_entity.name' ) }) it('Should enforce unique alias for an identity', async (): Promise => { const alias = 'non_unique_alias' - const identity1 = { + const identity1: IBasicIdentity = { alias, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -143,7 +492,7 @@ describe('Database entities tests', (): void => { const identity1Entity: IdentityEntity = identityEntityFrom(identity1) await dbConnection.getRepository(IdentityEntity).save(identity1Entity) - const identity2 = { + const identity2: IBasicIdentity = { alias: alias, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -159,7 +508,7 @@ describe('Database entities tests', (): void => { it('Should enforce unique correlationId for a identity', async (): Promise => { const correlationId = 'non_unique_correlationId' - const identity1 = { + const identity1: IBasicIdentity = { alias: 'unique_alias1', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -170,7 +519,7 @@ describe('Database entities tests', (): void => { const identity1Entity: IdentityEntity = identityEntityFrom(identity1) await dbConnection.getRepository(IdentityEntity).save(identity1Entity) - const identity2 = { + const identity2: IBasicIdentity = { alias: 'unique_alias2', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -186,7 +535,7 @@ describe('Database entities tests', (): void => { it('Should save identity to database', async (): Promise => { const correlationId = 'example_did' - const identity = { + const identity: IBasicIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -199,7 +548,7 @@ describe('Database entities tests', (): void => { await dbConnection.getRepository(IdentityEntity).save(identityEntity) - const fromDb = await dbConnection.getRepository(IdentityEntity).findOne({ + const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ where: { identifier: { correlationId, @@ -215,7 +564,7 @@ describe('Database entities tests', (): void => { }) it('should throw error when saving identity with blank alias', async (): Promise => { - const identity = { + const identity: IBasicIdentity = { alias: '', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -230,7 +579,7 @@ describe('Database entities tests', (): void => { }) it('should throw error when saving identity with blank correlation id', async (): Promise => { - const identity = { + const identity: IBasicIdentity = { alias: 'example_did', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -246,7 +595,7 @@ describe('Database entities tests', (): void => { it('should throw error when saving identity with blank metadata label', async (): Promise => { const correlationId = 'example_did' - const identity = { + const identity: IBasicIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -268,7 +617,7 @@ describe('Database entities tests', (): void => { it('should throw error when saving identity with blank metadata value', async (): Promise => { const correlationId = 'example_did' - const identity = { + const identity: IBasicIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -290,7 +639,7 @@ describe('Database entities tests', (): void => { it('Should save identity with openid connection to database', async (): Promise => { const correlationId = 'example.com' - const identity = { + const identity: IBasicIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -306,7 +655,7 @@ describe('Database entities tests', (): void => { issuer: 'https://example.com/app-test', redirectUrl: 'app:/callback', dangerouslyAllowInsecureHttpRequests: true, - clientAuthMethod: 'post' as const, + clientAuthMethod: 'post', }, }, } @@ -315,7 +664,7 @@ describe('Database entities tests', (): void => { await dbConnection.getRepository(IdentityEntity).save(identityEntity) - const fromDb = await dbConnection.getRepository(IdentityEntity).findOne({ + const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ where: { identifier: { correlationId, @@ -328,14 +677,14 @@ describe('Database entities tests', (): void => { expect(fromDb?.identifier).toBeDefined() expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) expect(fromDb?.identifier.type).toEqual(identity.identifier.type) - expect(fromDb?.connection?.type).toEqual(identity.connection.type) + expect(fromDb?.connection?.type).toEqual(identity.connection?.type) expect(fromDb?.connection?.config).toBeDefined() - expect((fromDb?.connection?.config as OpenIdConfigEntity).clientId).toEqual(identity.connection.config.clientId) + expect((fromDb?.connection?.config).clientId).toEqual((identity.connection?.config).clientId) }) it('Should save identity with didauth connection to database', async (): Promise => { const correlationId = 'example.com' - const identity = { + const identity: IBasicIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -362,7 +711,7 @@ describe('Database entities tests', (): void => { await dbConnection.getRepository(IdentityEntity).save(identityEntity) - const fromDb = await dbConnection.getRepository(IdentityEntity).findOne({ + const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ where: { identifier: { correlationId, @@ -375,13 +724,13 @@ describe('Database entities tests', (): void => { expect(fromDb?.identifier).toBeDefined() expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) expect(fromDb?.identifier.type).toEqual(identity.identifier.type) - expect(fromDb?.connection?.type).toEqual(identity.connection.type) + expect(fromDb?.connection?.type).toEqual(identity.connection?.type) expect(fromDb?.connection?.config).toBeDefined() - expect((fromDb?.connection?.config as DidAuthConfigEntity).identifier).toEqual(identity.connection.config.identifier.did) + expect((fromDb?.connection?.config).identifier).toEqual((identity.connection?.config).identifier.did) }) it('Should save connection with openid config to database', async (): Promise => { - const connection = { + const connection: IBasicConnection = { type: ConnectionTypeEnum.OPENID_CONNECT, config: { clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', @@ -390,32 +739,32 @@ describe('Database entities tests', (): void => { issuer: 'https://example.com/app-test', redirectUrl: 'app:/callback', dangerouslyAllowInsecureHttpRequests: true, - clientAuthMethod: 'post' as const, + clientAuthMethod: 'post', }, } - const connectionEntity = connectionEntityFrom(connection) + const connectionEntity: ConnectionEntity = connectionEntityFrom(connection) await dbConnection.getRepository(ConnectionEntity).save(connectionEntity, { transaction: true, }) - const fromDb = await dbConnection.getRepository(ConnectionEntity).findOne({ + const fromDb: ConnectionEntity | null = await dbConnection.getRepository(ConnectionEntity).findOne({ where: { type: connection.type }, }) expect(fromDb).toBeDefined() - const fromDbConfig = await dbConnection.getRepository(OpenIdConfigEntity).findOne({ + const fromDbConfig: OpenIdConfigEntity | null = await dbConnection.getRepository(OpenIdConfigEntity).findOne({ where: { id: fromDb?.id }, }) expect(fromDbConfig).toBeDefined() expect(fromDb?.type).toEqual(connection.type) expect(fromDb?.config).toBeDefined() - expect((fromDb?.config as OpenIdConfigEntity).clientId).toEqual(connection.config.clientId) + expect((fromDb?.config).clientId).toEqual((connection.config).clientId) }) it('Should save connection with didauth config to database', async (): Promise => { - const connection = { + const connection: IBasicConnection = { type: ConnectionTypeEnum.SIOPv2, config: { identifier: { @@ -429,55 +778,55 @@ describe('Database entities tests', (): void => { sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', }, } - const connectionEntity = connectionEntityFrom(connection) + const connectionEntity: ConnectionEntity = connectionEntityFrom(connection) await dbConnection.getRepository(ConnectionEntity).save(connectionEntity, { transaction: true, }) - const fromDb = await dbConnection.getRepository(ConnectionEntity).findOne({ + const fromDb: ConnectionEntity | null = await dbConnection.getRepository(ConnectionEntity).findOne({ where: { type: connection.type }, }) expect(fromDb).toBeDefined() - const fromDbConfig = await dbConnection.getRepository(DidAuthConfigEntity).findOne({ + const fromDbConfig: DidAuthConfigEntity | null = await dbConnection.getRepository(DidAuthConfigEntity).findOne({ where: { id: fromDb?.id }, }) expect(fromDbConfig).toBeDefined() expect(fromDb?.type).toEqual(connection.type) expect(fromDb?.config).toBeDefined() - expect((fromDb?.config as DidAuthConfigEntity).identifier).toEqual(connection.config.identifier.did) + expect((fromDb?.config).identifier).toEqual((connection.config).identifier.did) }) it('Should save openid config to database', async (): Promise => { const clientId = '138d7bf8-c930-4c6e-b928-97d3a4928b01' - const config = { + const config: BasicOpenIdConfig = { clientId, clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', scopes: ['auth'], issuer: 'https://example.com/app-test', redirectUrl: 'app:/callback', dangerouslyAllowInsecureHttpRequests: true, - clientAuthMethod: 'post' as const, + clientAuthMethod: 'post', } - const configEntity = openIdConfigEntityFrom(config) + const configEntity: OpenIdConfigEntity = openIdConfigEntityFrom(config) await dbConnection.getRepository(OpenIdConfigEntity).save(configEntity, { transaction: true, }) - const fromDb = await dbConnection.getRepository(OpenIdConfigEntity).findOne({ + const fromDb: OpenIdConfigEntity | null = await dbConnection.getRepository(OpenIdConfigEntity).findOne({ where: { clientId: config.clientId }, }) expect(fromDb).toBeDefined() - expect((fromDb as OpenIdConfigEntity).clientId).toEqual(config.clientId) + expect((fromDb).clientId).toEqual(config.clientId) }) it('Should save didauth config to database', async (): Promise => { const sessionId = 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01' - const config = { + const config: BasicDidAuthConfig = { identifier: { did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', provider: 'test_provider', @@ -489,31 +838,62 @@ describe('Database entities tests', (): void => { sessionId, } - const configEntity = didAuthConfigEntityFrom(config) + const configEntity: DidAuthConfigEntity = didAuthConfigEntityFrom(config) await dbConnection.getRepository(DidAuthConfigEntity).save(configEntity, { transaction: true, }) - const fromDb = await dbConnection.getRepository(DidAuthConfigEntity).findOne({ + const fromDb: DidAuthConfigEntity | null = await dbConnection.getRepository(DidAuthConfigEntity).findOne({ where: { sessionId: config.sessionId }, }) expect(fromDb).toBeDefined() - expect((fromDb as DidAuthConfigEntity).identifier).toEqual(config.identifier.did) + expect((fromDb).identifier).toEqual(config.identifier.did) }) it('Should delete contact and all child relations', async (): Promise => { - const contact = { - name: 'relation_test_name', - alias: 'relation_test_alias', + const contact1: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, } - const contactEntity: ContactEntity = contactEntityFrom(contact) - const savedContact = await dbConnection.getRepository(ContactEntity).save(contactEntity) + const contactEntity1: ContactEntity = contactEntityFrom(contact1) + const savedContact1: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity1) + + expect(savedContact1).toBeDefined() + + const contact2: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + + const contactEntity2: ContactEntity = contactEntityFrom(contact2) + const savedContact2: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity2) + + expect(savedContact2).toBeDefined() const correlationId = 'relation_example.com' - const identity = { + const identity: IBasicIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -529,7 +909,7 @@ describe('Database entities tests', (): void => { issuer: 'https://example.com/app-test', redirectUrl: 'app:/callback', dangerouslyAllowInsecureHttpRequests: true, - clientAuthMethod: 'post' as const, + clientAuthMethod: 'post', }, }, metadata: [ @@ -541,29 +921,42 @@ describe('Database entities tests', (): void => { } const identityEntity: IdentityEntity = identityEntityFrom(identity) - identityEntity.contact = savedContact + identityEntity.contact = savedContact1 + + const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) + + expect(savedIdentity).toBeDefined() + + const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ + left: savedContact1, + right: savedContact2, + }) + + const savedRelationship: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { + transaction: true, + }) - const savedIdentity = await dbConnection.getRepository(IdentityEntity).save(identityEntity) + expect(savedRelationship).toBeDefined() expect( await dbConnection.getRepository(ContactEntity).findOne({ - where: { name: contact.name }, + where: { id: savedContact1.id }, }) ).toBeDefined() - await dbConnection.getRepository(ContactEntity).delete({ id: savedContact.id }) + await dbConnection.getRepository(ContactEntity).delete({ id: savedContact1.id }) // check contact await expect( await dbConnection.getRepository(ContactEntity).findOne({ - where: { name: contact.name }, + where: { id: savedContact1.id }, }) ).toBeNull() // check identity expect( await dbConnection.getRepository(IdentityEntity).findOne({ - where: { alias: correlationId }, + where: { id: savedContact1.id }, }) ).toBeNull() @@ -594,20 +987,52 @@ describe('Database entities tests', (): void => { where: { id: savedIdentity.metadata![0].id }, }) ).toBeNull() + + // check contact owner + expect( + await dbConnection.getRepository(ContactOwnerEntity).findOne({ + where: { id: savedContact1.contactOwner.id }, + }) + ).toBeNull() + + // check contact type + expect( + await dbConnection.getRepository(ContactTypeEntity).findOne({ + where: { id: savedContact1.contactType.id }, + }) + ).toBeDefined() + + // check relation + expect( + await dbConnection.getRepository(ContactRelationshipEntity).findOne({ + where: { id: savedRelationship.id }, + }) + ).toBeNull() }) it('Should delete identity and all child relations', async (): Promise => { - const contact = { - name: 'relation_test_name', - alias: 'relation_test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } const contactEntity: ContactEntity = contactEntityFrom(contact) - const savedContact = await dbConnection.getRepository(ContactEntity).save(contactEntity) + const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) + + expect(savedContact).toBeDefined() const correlationId = 'relation_example.com' - const identity = { + const identity: IBasicIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -639,11 +1064,11 @@ describe('Database entities tests', (): void => { const identityEntity: IdentityEntity = identityEntityFrom(identity) identityEntity.contact = savedContact - const savedIdentity = await dbConnection.getRepository(IdentityEntity).save(identityEntity) + const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) expect( await dbConnection.getRepository(ContactEntity).findOne({ - where: { name: contact.name }, + where: { id: savedContact.id }, }) ).toBeDefined() @@ -686,17 +1111,28 @@ describe('Database entities tests', (): void => { }) it('Should not delete contact when deleting identity', async (): Promise => { - const contact = { - name: 'relation_test_name', - alias: 'relation_test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } const contactEntity: ContactEntity = contactEntityFrom(contact) - const savedContact = await dbConnection.getRepository(ContactEntity).save(contactEntity) + const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) + + expect(savedContact).toBeDefined() const correlationId = 'relation_example.com' - const identity = { + const identity: IBasicIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -728,7 +1164,9 @@ describe('Database entities tests', (): void => { const identityEntity: IdentityEntity = identityEntityFrom(identity) identityEntity.contact = savedContact - const savedIdentity = await dbConnection.getRepository(IdentityEntity).save(identityEntity) + const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) + + expect(savedIdentity).toBeDefined() await dbConnection.getRepository(IdentityEntity).delete({ id: savedIdentity.id }) @@ -742,23 +1180,32 @@ describe('Database entities tests', (): void => { // check contact expect( await dbConnection.getRepository(ContactEntity).findOne({ - where: { name: contact.name }, + where: { id: savedContact.id }, }) ).toBeDefined() }) it('Should set creation date when saving contact', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } const contactEntity: ContactEntity = contactEntityFrom(contact) - await dbConnection.getRepository(ContactEntity).save(contactEntity) + const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) - const fromDb = await dbConnection.getRepository(ContactEntity).findOne({ - where: { name: contact.name }, + const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: savedContact.id }, }) expect(fromDb).toBeDefined() @@ -766,28 +1213,47 @@ describe('Database entities tests', (): void => { }) it('Should not update creation date when updating contact', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } const contactEntity: ContactEntity = contactEntityFrom(contact) - const savedContact = await dbConnection.getRepository(ContactEntity).save(contactEntity) - const newContactName = 'new_name' - await dbConnection.getRepository(ContactEntity).save({ ...savedContact, name: newContactName }) + const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) + + expect(savedContact).toBeDefined() + + const newContactFirstName = 'new_first_name' + await dbConnection.getRepository(ContactEntity).save({ + ...savedContact, + contactOwner: { + ...savedContact.contactOwner, + firstName: newContactFirstName, + }, + }) - const fromDb = await dbConnection.getRepository(ContactEntity).findOne({ + const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ where: { id: savedContact.id }, }) expect(fromDb).toBeDefined() + expect((fromDb?.contactOwner).firstName).toEqual(newContactFirstName) expect(fromDb?.createdAt).toEqual(savedContact?.createdAt) }) it('Should set creation date when saving identity', async (): Promise => { const correlationId = 'example_did' - const identity = { + const identity: IBasicIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -799,7 +1265,7 @@ describe('Database entities tests', (): void => { const identityEntity: IdentityEntity = identityEntityFrom(identity) await dbConnection.getRepository(IdentityEntity).save(identityEntity) - const fromDb = await dbConnection.getRepository(IdentityEntity).findOne({ + const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ where: { identifier: { correlationId, @@ -813,7 +1279,7 @@ describe('Database entities tests', (): void => { it('Should not update creation date when saving identity', async (): Promise => { const correlationId = 'example_did' - const identity = { + const identity: IBasicIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -823,13 +1289,13 @@ describe('Database entities tests', (): void => { } const identityEntity: IdentityEntity = identityEntityFrom(identity) - const savedIdentity = await dbConnection.getRepository(IdentityEntity).save(identityEntity) + const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) const newCorrelationId = 'new_example_did' await dbConnection .getRepository(IdentityEntity) .save({ ...savedIdentity, identifier: { ...savedIdentity.identifier, correlationId: newCorrelationId } }) - const fromDb = await dbConnection.getRepository(IdentityEntity).findOne({ + const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ where: { identifier: { correlationId: newCorrelationId, @@ -842,50 +1308,115 @@ describe('Database entities tests', (): void => { }) it('Should set last updated date when saving contact', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } const contactEntity: ContactEntity = contactEntityFrom(contact) - await dbConnection.getRepository(ContactEntity).save(contactEntity) + const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) - const fromDb = await dbConnection.getRepository(ContactEntity).findOne({ - where: { name: contact.name }, + const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: savedContact.id }, }) expect(fromDb).toBeDefined() expect(fromDb?.lastUpdatedAt).toBeDefined() }) + // TODO there is still an issue when updating nested objects, the parent does not update it('Should update last updated date when updating contact', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } const contactEntity: ContactEntity = contactEntityFrom(contact) - const savedContact = await dbConnection.getRepository(ContactEntity).save(contactEntity) + const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) + + expect(savedContact).toBeDefined() // waiting here to get a different timestamp await new Promise((resolve) => setTimeout(resolve, 2000)) - const newContactName = 'new_name' - await dbConnection.getRepository(ContactEntity).save({ ...savedContact, name: newContactName }) + const newContactFirstName = 'new_first_name' + await dbConnection.getRepository(ContactEntity).save({ + ...savedContact, + uri: 'new uri', // TODO remove this to trigger the bug + contactOwner: { + ...savedContact.contactOwner, + firstName: newContactFirstName, + }, + }) - const fromDb = await dbConnection.getRepository(ContactEntity).findOne({ + const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ where: { id: savedContact.id }, }) expect(fromDb).toBeDefined() + expect((fromDb?.contactOwner).firstName).toEqual(newContactFirstName) expect(fromDb?.lastUpdatedAt).not.toEqual(savedContact?.lastUpdatedAt) }) + it('Should set last updated date when saving contact type', async (): Promise => { + const contactType: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + } + + const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) + const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) + + const fromDb: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).findOne({ + where: { id: savedContactType.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.lastUpdatedAt).toBeDefined() + }) + + it('Should set last creation date when saving contact type', async (): Promise => { + const contactType: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + } + + const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) + const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) + + const fromDb: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).findOne({ + where: { id: savedContactType.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.createdAt).toBeDefined() + }) + it('Should set last updated date when saving identity', async (): Promise => { const correlationId = 'example_did' - const identity = { + const identity: IBasicIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -897,7 +1428,7 @@ describe('Database entities tests', (): void => { const identityEntity: IdentityEntity = identityEntityFrom(identity) await dbConnection.getRepository(IdentityEntity).save(identityEntity) - const fromDb = await dbConnection.getRepository(IdentityEntity).findOne({ + const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ where: { identifier: { correlationId, @@ -908,4 +1439,849 @@ describe('Database entities tests', (): void => { expect(fromDb).toBeDefined() expect(fromDb?.lastUpdatedAt).toBeDefined() }) + + it('Should enforce unique type and tenant id combination when saving contact type', async (): Promise => { + const tenantId = 'non_unique_value' + const name = 'non_unique_value' + const contactType1: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId, + name, + } + + const contactTypeEntity1: ContactTypeEntity = contactTypeEntityFrom(contactType1) + const savedContactType1: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity1) + + expect(savedContactType1).toBeDefined() + + const contactType2: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId, + name, + } + + const contactTypeEntity2: ContactTypeEntity = contactTypeEntityFrom(contactType2) + await expect(dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity2)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: contact_type_entity.type, contact_type_entity.tenantId' + ) + }) + + it('Should enforce unique name when saving contact type', async (): Promise => { + const name = 'non_unique_value' + const contactType1: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name, + } + + const contactTypeEntity1: ContactTypeEntity = contactTypeEntityFrom(contactType1) + const savedContactType1: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity1) + + expect(savedContactType1).toBeDefined() + + const contactType2: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name, + } + + const contactTypeEntity2: ContactTypeEntity = contactTypeEntityFrom(contactType2) + await expect(dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity2)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: contact_type_entity.name' + ) + }) + + it('Should enforce unique legal name when saving organization', async (): Promise => { + const legalName = 'non_unique_value' + const organization1: BasicOrganization = { + legalName, + displayName: 'example_display_name', + } + + const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) + const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { + transaction: true, + }) + + expect(savedOrganization1).toBeDefined() + + const organization2: BasicOrganization = { + legalName, + displayName: 'example_display_name', + } + + const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) + await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.legalName' + ) + }) + + it('Should enforce unique display name when saving organization', async (): Promise => { + const displayName = 'non_unique_value' + const organization1: BasicOrganization = { + legalName: 'example_legal_name1', + displayName, + } + + const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) + const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { + transaction: true, + }) + + expect(savedOrganization1).toBeDefined() + + const organization2: BasicOrganization = { + legalName: 'example_legal_name2', + displayName, + } + + const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) + await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.displayName' + ) + }) + + it('Should enforce unique legal name when saving organization', async (): Promise => { + const legalName = 'example_legal_name' + const organization1: BasicOrganization = { + legalName, + displayName: 'example_display_name', + } + + const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) + const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { + transaction: true, + }) + + expect(savedOrganization1).toBeDefined() + + const organization2: BasicOrganization = { + legalName, + displayName: 'example_display_name', + } + + const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) + await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.legalName' + ) + }) + + it('Should enforce unique coc number when saving organization', async (): Promise => { + const legalName = 'example_legal_name' + const organization1: BasicOrganization = { + legalName, + displayName: 'example_display_name1', + cocNumber: '1234567890' + } + + const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) + const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { + transaction: true, + }) + + expect(savedOrganization1).toBeDefined() + + const organization2: BasicOrganization = { + legalName, + displayName: 'example_display_name2', + cocNumber: '1234567890' + } + + const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) + await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.cocNumber' + ) + }) + + it('Should enforce unique display name when saving person', async (): Promise => { + const displayName = 'non_unique_value' + const person1: BasicPerson = { + firstName: 'example_first_name1', + lastName: 'lastName2', + displayName, + } + + const personEntity1: PersonEntity = personEntityFrom(person1) + const savedPerson1: PersonEntity | null = await dbConnection.getRepository(PersonEntity).save(personEntity1, { + transaction: true, + }) + + expect(savedPerson1).toBeDefined() + + const person2: BasicPerson = { + firstName: 'example_first_name2', + lastName: 'lastName2', + displayName, + } + + const personEntity2: PersonEntity = personEntityFrom(person2) + await expect(dbConnection.getRepository(PersonEntity).save(personEntity2)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.displayName' + ) + }) + + it('Should save contact relation to database', async (): Promise => { + const contact1: IBasicContact = { + uri: 'example1.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const contactEntity1: ContactEntity = contactEntityFrom(contact1) + const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + transaction: true, + }) + + expect(savedContact1).toBeDefined() + + const contact2: IBasicContact = { + uri: 'example2.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + + const contactEntity2: ContactEntity = contactEntityFrom(contact2) + const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + transaction: true, + }) + + expect(savedContact2).toBeDefined() + + const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ + left: savedContact1, + right: savedContact2, + }) + + await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { + transaction: true, + }) + + // TODO check the relation field + const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: contactEntity1.id }, + }) + + expect(fromDb).toBeDefined() + }) + + it('Should set last updated date when saving contact relation', async (): Promise => { + const contact1: IBasicContact = { + uri: 'example1.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const contactEntity1: ContactEntity = contactEntityFrom(contact1) + const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + transaction: true, + }) + + const contact2: IBasicContact = { + uri: 'example2.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + + const contactEntity2: ContactEntity = contactEntityFrom(contact2) + const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + transaction: true, + }) + + const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ + left: savedContact1, + right: savedContact2, + }) + + await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { + transaction: true, + }) + + const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: contactEntity1.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.lastUpdatedAt).toBeDefined() + }) + + it('Should set creation date when saving contact relation', async (): Promise => { + const contact1: IBasicContact = { + uri: 'example1.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const contactEntity1: ContactEntity = contactEntityFrom(contact1) + const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + transaction: true, + }) + + const contact2: IBasicContact = { + uri: 'example2.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + + const contactEntity2: ContactEntity = contactEntityFrom(contact2) + const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + transaction: true, + }) + + const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ + left: savedContact1, + right: savedContact2, + }) + + await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { + transaction: true, + }) + + const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: contactEntity1.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.createdAt).toBeDefined() + }) + + it('Should save bidirectional contact relations to database', async (): Promise => { + const contact1: IBasicContact = { + uri: 'example1.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const contactEntity1: ContactEntity = contactEntityFrom(contact1) + const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + transaction: true, + }) + + expect(savedContact1).toBeDefined() + + const contact2: IBasicContact = { + uri: 'example2.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + + const contactEntity2: ContactEntity = contactEntityFrom(contact2) + const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + transaction: true, + }) + + expect(savedContact2).toBeDefined() + + const relationship1: ContactRelationshipEntity = contactRelationshipEntityFrom({ + left: savedContact1, + right: savedContact2, + }) + + const savedRelationship1: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship1, { + transaction: true, + }) + + expect(savedRelationship1).toBeDefined() + + const relationship2: ContactRelationshipEntity = contactRelationshipEntityFrom({ + left: savedContact2, + right: savedContact1, + }) + + const savedRelationship2: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship2, { + transaction: true, + }) + + expect(savedRelationship2).toBeDefined() + + const fromDb: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).findOne({ + where: { id: savedRelationship2.id }, + }) + + expect(fromDb).toBeDefined() + }) + + it('Should enforce unique owner combination for contact relation', async (): Promise => { + const contact1: IBasicContact = { + uri: 'example1.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const contactEntity1: ContactEntity = contactEntityFrom(contact1) + const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + transaction: true, + }) + + expect(savedContact1).toBeDefined() + + const contact2: IBasicContact = { + uri: 'example2.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + + const contactEntity2: ContactEntity = contactEntityFrom(contact2) + const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + transaction: true, + }) + + expect(savedContact2).toBeDefined() + + const relationship1: ContactRelationshipEntity = contactRelationshipEntityFrom({ + left: savedContact1, + right: savedContact2, + }) + + const savedRelationship1: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship1, { + transaction: true, + }) + + expect(savedRelationship1).toBeDefined() + + const relationship2: ContactRelationshipEntity = contactRelationshipEntityFrom({ + left: savedContact1, + right: savedContact2, + }) + + await expect(dbConnection.getRepository(ContactRelationshipEntity).save(relationship2)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: contact_relationship_entity.leftId, contact_relationship_entity.rightId' + ) + }) + + it('Should save contact type to database', async (): Promise => { + const contactType: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + } + + const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) + const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) + + const fromDb: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).findOne({ + where: { id: savedContactType.id }, + }) + + expect(fromDb).toBeDefined() + }) + + it('Should save person to database', async (): Promise => { + const person: BasicPerson = { + firstName: 'example_first_name', + lastName: 'lastName2', + displayName: 'displayName', + } + + const personEntity: PersonEntity = personEntityFrom(person) + const savedPerson: PersonEntity | null = await dbConnection.getRepository(PersonEntity).save(personEntity, { + transaction: true, + }) + + const fromDb: PersonEntity | null = await dbConnection.getRepository(PersonEntity).findOne({ + where: { id: savedPerson.id }, + }) + + expect(fromDb).toBeDefined() + }) + + it('Should set last updated date when saving person', async (): Promise => { + const person: BasicPerson = { + firstName: 'example_first_name', + lastName: 'lastName2', + displayName: 'displayName', + } + + const personEntity: PersonEntity = personEntityFrom(person) + const savedPerson: PersonEntity | null = await dbConnection.getRepository(PersonEntity).save(personEntity, { + transaction: true, + }) + + const fromDb: PersonEntity | null = await dbConnection.getRepository(PersonEntity).findOne({ + where: { id: savedPerson.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.lastUpdatedAt).toBeDefined() + }) + + it('Should set creation date when saving person', async (): Promise => { + const person: BasicPerson = { + firstName: 'example_first_name', + lastName: 'lastName2', + displayName: 'displayName', + } + + const personEntity: PersonEntity = personEntityFrom(person) + const savedPerson: PersonEntity | null = await dbConnection.getRepository(PersonEntity).save(personEntity, { + transaction: true, + }) + + const fromDb: PersonEntity | null = await dbConnection.getRepository(PersonEntity).findOne({ + where: { id: savedPerson.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.createdAt).toBeDefined() + }) + + it('Should save organization to database', async (): Promise => { + const organization: BasicOrganization = { + legalName: 'example_legal_name', + displayName: 'example_display_name', + } + + const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) + const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { + transaction: true, + }) + + const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ + where: { id: savedOrganization.id }, + }) + + expect(fromDb).toBeDefined() + }) + + it('Should set last updated date when saving organization', async (): Promise => { + const organization: BasicOrganization = { + legalName: 'example_legal_name', + displayName: 'example_display_name', + } + + const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) + const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { + transaction: true, + }) + + const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ + where: { id: savedOrganization.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.lastUpdatedAt).toBeDefined() + }) + + it('Should set creation date when saving organization', async (): Promise => { + const organization: BasicOrganization = { + legalName: 'example_legal_name', + displayName: 'example_display_name', + } + + const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) + const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { + transaction: true, + }) + + const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ + where: { id: savedOrganization.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.createdAt).toBeDefined() + }) + + it('Should get contact based on person information', async (): Promise => { + const firstName = 'example_first_name' + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName, + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + await dbConnection.getRepository(ContactEntity).save(contactEntity, { + transaction: true, + }) + + const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { + contactOwner: { + firstName, + } as FindOptionsWhere, + }, + }) + + expect(fromDb).toBeDefined() + }) + + it('Should get contact based on organization information', async (): Promise => { + const legalName = 'example_legal_name' + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.ORGANIZATION, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + legalName, + displayName: 'example_display_name', + cocNumber: '12345678ABC', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + await dbConnection.getRepository(ContactEntity).save(contactEntity, { + transaction: true, + }) + + const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { + contactOwner: { + legalName, + } as FindOptionsWhere, + }, + }) + + expect(fromDb).toBeDefined() + }) + + it('Should enforce unique contact id\'s for relationship sides', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + const savedContact: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity, { + transaction: true, + }) + + expect(savedContact).toBeDefined() + + const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ + left: savedContact, + right: savedContact, + }) + + await expect(dbConnection.getRepository(ContactRelationshipEntity).save(relationship)).rejects.toThrowError( + 'Cannot use the same id for both sides of the relationship' + ) + }) + + it('Should delete contact relation', async (): Promise => { + const contact1: IBasicContact = { + uri: 'example1.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const contactEntity1: ContactEntity = contactEntityFrom(contact1) + const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + transaction: true, + }) + + expect(savedContact1).toBeDefined() + + const contact2: IBasicContact = { + uri: 'example2.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + + const contactEntity2: ContactEntity = contactEntityFrom(contact2) + const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + transaction: true, + }) + + expect(savedContact2).toBeDefined() + + const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ + left: savedContact1, + right: savedContact2, + }) + + const savedRelationship: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { + transaction: true, + }) + + expect(savedRelationship).toBeDefined() + + await dbConnection.getRepository(ContactRelationshipEntity).delete({ id: savedRelationship.id }) + + await expect( + await dbConnection.getRepository(ContactRelationshipEntity).findOne({ + where: { id: savedRelationship.id }, + }) + ).toBeNull() + }) + + it('Should delete contact type', async (): Promise => { + const contactType: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + } + + const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) + const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) + + expect(savedContactType).toBeDefined() + + await dbConnection.getRepository(ContactTypeEntity).delete({ id: savedContactType.id }) + + await expect( + await dbConnection.getRepository(ContactTypeEntity).findOne({ + where: { id: savedContactType.id }, + }) + ).toBeNull() + }) + + it('Should not be able to remove contact type when used by contacts', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity, { + transaction: true, + }) + + expect(savedContact).toBeDefined() + + await expect(dbConnection.getRepository(ContactTypeEntity).delete({ id: savedContact.contactType.id })).rejects.toThrowError( + 'FOREIGN KEY constraint failed' + ) + }) + + // TODO not update creation date when saving contact type + // TODO add test for updating nested field and checking last updated at on parent }) diff --git a/packages/data-store/src/__tests__/contact.store.test.ts b/packages/data-store/src/__tests__/contact.store.test.ts index c6afc3d4d..833a27e5f 100644 --- a/packages/data-store/src/__tests__/contact.store.test.ts +++ b/packages/data-store/src/__tests__/contact.store.test.ts @@ -1,7 +1,20 @@ import { DataSource } from 'typeorm' +import { BasicContactRelationship, DataStoreContactEntities, IContactRelationship } from '../index' import { ContactStore } from '../contact/ContactStore' -import { CorrelationIdentifierEnum, DataStoreContactEntities, DataStoreMigrations, IdentityRoleEnum } from '../index' +import { + IdentityRoleEnum, + ContactTypeEnum, + IBasicContact, + IContact, + CorrelationIdentifierEnum, + IIdentity, + IPerson, + BasicPerson, + IBasicIdentity, + IGetIdentitiesArgs, + IGetContactsArgs, +} from '../types' describe('Contact store tests', (): void => { let dbConnection: DataSource @@ -13,29 +26,54 @@ describe('Contact store tests', (): void => { database: ':memory:', //logging: 'all', migrationsRun: false, - migrations: DataStoreMigrations, - synchronize: false, + // migrations: DataStoreMigrations, + synchronize: true, //false entities: DataStoreContactEntities, }).initialize() - await dbConnection.runMigrations() - expect(await dbConnection.showMigrations()).toBeFalsy() + // await dbConnection.runMigrations() + // expect(await dbConnection.showMigrations()).toBeFalsy() contactStore = new ContactStore(dbConnection) }) + // beforeEach(async (): Promise => { + // dbConnection = await new DataSource({ + // type: 'sqlite', + // database: ':memory:', + // //logging: 'all', + // migrationsRun: false, + // migrations: DataStoreMigrations, + // synchronize: false, + // entities: DataStoreContactEntities, + // }).initialize() + // await dbConnection.runMigrations() + // expect(await dbConnection.showMigrations()).toBeFalsy() + // contactStore = new ContactStore(dbConnection) + // }) + afterEach(async (): Promise => { await (await dbConnection).destroy() }) it('should get contact by id', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } - const savedContact = await contactStore.addContact(contact) + + const savedContact: IContact = await contactStore.addContact(contact) expect(savedContact).toBeDefined() - const result = await contactStore.getContact({ contactId: savedContact.id }) + const result: IContact = await contactStore.getContact({ contactId: savedContact.id }) expect(result).toBeDefined() }) @@ -47,49 +85,106 @@ describe('Contact store tests', (): void => { }) it('should get all contacts', async (): Promise => { - const contact1 = { - name: 'test_name1', - alias: 'test_alias1', - uri: 'example.com1', + const contact1: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, } - const savedContact1 = await contactStore.addContact(contact1) + const savedContact1: IContact = await contactStore.addContact(contact1) expect(savedContact1).toBeDefined() - const contact2 = { - name: 'test_name2', - alias: 'test_alias2', - uri: 'example.com2', + const contact2: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, } - const savedContact2 = await contactStore.addContact(contact2) + const savedContact2: IContact = await contactStore.addContact(contact2) expect(savedContact2).toBeDefined() - const result = await contactStore.getContacts() + const result: Array = await contactStore.getContacts() expect(result.length).toEqual(2) }) it('should get contacts by filter', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } - const savedContact = await contactStore.addContact(contact) + const savedContact: IContact = await contactStore.addContact(contact) expect(savedContact).toBeDefined() - const args = { - filter: [{ name: 'test_name' }, { alias: 'test_alias' }, { uri: 'example.com' }], + const args: IGetContactsArgs = { + filter: [ + { + contactOwner: { + firstName: (contact.contactOwner).firstName, + }, + }, + { + contactOwner: { + middleName: (contact.contactOwner).middleName, + }, + }, + { + contactOwner: { + lastName: (contact.contactOwner).lastName, + }, + }, + { + contactOwner: { + displayName: (contact.contactOwner).displayName, + }, + }, + ], } - const result = await contactStore.getContacts(args) + const result: Array = await contactStore.getContacts(args) expect(result.length).toEqual(1) }) it('should get whole contacts by filter', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, identities: [ { alias: 'test_alias1', @@ -117,10 +212,10 @@ describe('Contact store tests', (): void => { }, ], } - const savedContact = await contactStore.addContact(contact) + const savedContact: IContact = await contactStore.addContact(contact) expect(savedContact).toBeDefined() - const args = { + const args: IGetContactsArgs = { filter: [ { identities: { @@ -131,123 +226,177 @@ describe('Contact store tests', (): void => { }, ], } - const result = await contactStore.getContacts(args) + const result: Array = await contactStore.getContacts(args) expect(result[0].identities.length).toEqual(3) }) it('should get contacts by name', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'something', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } - const savedContact = await contactStore.addContact(contact) + + const savedContact: IContact = await contactStore.addContact(contact) expect(savedContact).toBeDefined() - const args = { - filter: [{ name: 'test_name' }], + const args: IGetContactsArgs = { + filter: [ + { + contactOwner: { + firstName: (contact.contactOwner).firstName, + }, + }, + { + contactOwner: { + middleName: (contact.contactOwner).middleName, + }, + }, + { + contactOwner: { + lastName: (contact.contactOwner).lastName, + }, + }, + ], } - const result = await contactStore.getContacts(args) + const result: Array = await contactStore.getContacts(args) expect(result.length).toEqual(1) }) - it('should get contacts by alias', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + it('should get contacts by display name', async (): Promise => { + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } - const savedContact = await contactStore.addContact(contact) + + const savedContact: IContact = await contactStore.addContact(contact) expect(savedContact).toBeDefined() - const args = { - filter: [{ alias: 'test_alias' }], + const args: IGetContactsArgs = { + filter: [ + { + contactOwner: { + displayName: (contact.contactOwner).displayName, + }, + }, + ], } - const result = await contactStore.getContacts(args) + const result: Array = await contactStore.getContacts(args) expect(result.length).toEqual(1) }) it('should get contacts by uri', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } - const savedContact = await contactStore.addContact(contact) + const savedContact: IContact = await contactStore.addContact(contact) expect(savedContact).toBeDefined() - const args = { + const args: IGetContactsArgs = { filter: [{ uri: 'example.com' }], } - const result = await contactStore.getContacts(args) + const result: Array = await contactStore.getContacts(args) expect(result.length).toEqual(1) }) it('should return no contacts if filter does not match', async (): Promise => { - const args = { - filter: [{ name: 'no_match_contact' }, { alias: 'no_match_contact_alias' }, { uri: 'no_match_example.com' }], + const args: IGetContactsArgs = { + filter: [ + { + contactOwner: { + firstName: 'no_match_firstName', + }, + }, + { + contactOwner: { + middleName: 'no_match_middleName', + }, + }, + { + contactOwner: { + lastName: 'no_match_lastName', + }, + }, + ], } - const result = await contactStore.getContacts(args) + const result: Array = await contactStore.getContacts(args) expect(result.length).toEqual(0) }) it('should add contact without identities', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } - const result = await contactStore.addContact(contact) + const result: IContact = await contactStore.addContact(contact) - expect(result.name).toEqual(contact.name) - expect(result.alias).toEqual(contact.alias) - expect(result.uri).toEqual(contact.uri) + expect(result).toBeDefined() + expect((result.contactOwner).firstName).toEqual((contact.contactOwner).firstName) + expect((result.contactOwner).middleName).toEqual((contact.contactOwner).middleName) + expect((result.contactOwner).lastName).toEqual((contact.contactOwner).lastName) + expect(result.identities.length).toEqual(0) }) it('should add contact with identities', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', - uri: 'example.com', - identities: [ - { - alias: 'test_alias1', - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId: 'example_did1', - }, - }, - { - alias: 'test_alias2', - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId: 'example_did2', - }, - }, - ], - } - - const result = await contactStore.addContact(contact) - - expect(result.name).toEqual(contact.name) - expect(result.alias).toEqual(contact.alias) - expect(result.uri).toEqual(contact.uri) - expect(result.identities.length).toEqual(2) - }) - - it('should throw error when adding contact with invalid identity', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, identities: [ { alias: 'test_alias1', @@ -268,64 +417,136 @@ describe('Contact store tests', (): void => { ], } - const result = await contactStore.addContact(contact) + const result: IContact = await contactStore.addContact(contact) - expect(result.name).toEqual(contact.name) - expect(result.alias).toEqual(contact.alias) - expect(result.uri).toEqual(contact.uri) + expect(result).toBeDefined() + expect((result.contactOwner).firstName).toEqual((contact.contactOwner).firstName) + expect((result.contactOwner).middleName).toEqual((contact.contactOwner).middleName) + expect((result.contactOwner).lastName).toEqual((contact.contactOwner).lastName) expect(result.identities.length).toEqual(2) }) - it('should throw error when adding contact with duplicate name', async (): Promise => { - const name = 'test_name' - const contact1 = { - name, - alias: 'test_alias', + // TODO fix test, its not throwing an error + // it('should throw error when adding contact with invalid identity', async (): Promise => { + // const contact: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'something', + // }, + // contactOwner: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // identities: [ + // { + // alias: 'test_alias1', + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId: 'example_did1', + // }, + // }, + // { + // alias: 'test_alias2', + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId: 'example_did2', + // }, + // }, + // ], + // } + // + // const result: IContact = await contactStore.addContact(contact) + // + // expect(result.name).toEqual(contact.name) + // expect(result.alias).toEqual(contact.alias) + // expect(result.uri).toEqual(contact.uri) + // expect(result.identities.length).toEqual(2) + // }) + + // TODO test org and person + it('should throw error when adding contact with duplicate display name', async (): Promise => { + const displayName = 'non_unique_value' + const contact1: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName, + }, } - const savedContact1 = await contactStore.addContact(contact1) + const savedContact1: IContact = await contactStore.addContact(contact1) expect(savedContact1).toBeDefined() - const alias = 'test_alias2' - const contact2 = { - name, - alias, + const contact2: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName, + }, } - await expect(contactStore.addContact(contact2)).rejects.toThrow(`Duplicate names or aliases are not allowed. Name: ${name}, Alias: ${alias}`) + await expect(contactStore.addContact(contact2)).rejects.toThrow(`Duplicate names or display are not allowed. Display name: ${displayName}`) }) - it('should throw error when adding contact with duplicate alias', async (): Promise => { - const alias = 'test_alias' - const contact1 = { - name: 'test_name', - alias, - uri: 'example.com', - } - const savedContact1 = await contactStore.addContact(contact1) - expect(savedContact1).toBeDefined() - - const name = 'test_name2' - const contact2 = { - name, - alias, - uri: 'example.com', - } - - await expect(contactStore.addContact(contact2)).rejects.toThrow(`Duplicate names or aliases are not allowed. Name: ${name}, Alias: ${alias}`) - }) + // TODO // TODO test name + // it('should throw error when adding contact with duplicate name', async (): Promise => { + // const alias = 'test_alias' + // const contact1: IBasicContact = { + // name: 'test_name', + // alias, + // uri: 'example.com', + // } + // const savedContact1: IContact = await contactStore.addContact(contact1) + // expect(savedContact1).toBeDefined() + // + // const name = 'test_name2' + // const contact2: IBasicContact = { + // name, + // alias, + // uri: 'example.com', + // } + // + // await expect(contactStore.addContact(contact2)).rejects.toThrow(`Duplicate names or aliases are not allowed. Name: ${name}, Alias: ${alias}`) + // }) it('should update contact by id', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } - const savedContact = await contactStore.addContact(contact) + const savedContact: IContact = await contactStore.addContact(contact) expect(savedContact).toBeDefined() - const identity1 = { + const identity1: IBasicIdentity = { alias: 'test_alias1', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -333,10 +554,10 @@ describe('Contact store tests', (): void => { correlationId: 'example_did1', }, } - const savedIdentity1 = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity1 }) + const savedIdentity1: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity1 }) expect(savedIdentity1).toBeDefined() - const identity2 = { + const identity2: IBasicIdentity = { alias: 'test_alias2', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -344,50 +565,79 @@ describe('Contact store tests', (): void => { correlationId: 'example_did2', }, } - const savedIdentity2 = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity2 }) + const savedIdentity2: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity2 }) expect(savedIdentity2).toBeDefined() - const contactName = 'updated_name' - const updatedContact = { + const contactFirstName = 'updated_first_name' + const updatedContact: IContact = { ...savedContact, - name: contactName, + contactOwner: { + ...savedContact.contactOwner, + firstName: contactFirstName, + }, } await contactStore.updateContact({ contact: updatedContact }) - const result = await contactStore.getContact({ contactId: savedContact.id }) + const result: IContact = await contactStore.getContact({ contactId: savedContact.id }) - expect(result.name).toEqual(contactName) + expect(result).toBeDefined() + expect((result.contactOwner).firstName).toEqual(contactFirstName) expect(result.identities.length).toEqual(2) }) it('should throw error when updating contact with unknown id', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } - const savedContact = await contactStore.addContact(contact) + const savedContact: IContact = await contactStore.addContact(contact) expect(savedContact).toBeDefined() const contactId = 'unknownContactId' - const updatedContact = { + const contactFirstName = 'updated_first_name' + const updatedContact: IContact = { ...savedContact, id: contactId, - name: 'new_name', + contactOwner: { + ...savedContact.contactOwner, + firstName: contactFirstName, + }, } + await expect(contactStore.updateContact({ contact: updatedContact })).rejects.toThrow(`No contact found for id: ${contactId}`) }) + // TODO test to update wrong contact type person to org + it('should get identity by id', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } - const savedContact = await contactStore.addContact(contact) + const savedContact: IContact = await contactStore.addContact(contact) expect(savedContact).toBeDefined() - const identity = { + const identity: IBasicIdentity = { alias: 'test_alias', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -395,24 +645,33 @@ describe('Contact store tests', (): void => { correlationId: 'example_did', }, } - const savedIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity }) + const savedIdentity: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity }) expect(savedIdentity).toBeDefined() - const result = await contactStore.getIdentity({ identityId: savedIdentity.id }) + const result: IIdentity = await contactStore.getIdentity({ identityId: savedIdentity.id }) expect(result).toBeDefined() }) it('should get holderDID identity by id', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } - const savedContact = await contactStore.addContact(contact) + const savedContact: IContact = await contactStore.addContact(contact) expect(savedContact).toBeDefined() - const identity = { + const identity: IBasicIdentity = { alias: 'test_alias', roles: [IdentityRoleEnum.HOLDER], identifier: { @@ -420,10 +679,10 @@ describe('Contact store tests', (): void => { correlationId: 'example_did', }, } - const savedIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity }) + const savedIdentity: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity }) expect(savedIdentity).toBeDefined() - const result = await contactStore.getIdentity({ identityId: savedIdentity.id }) + const result: IIdentity = await contactStore.getIdentity({ identityId: savedIdentity.id }) expect(result).toBeDefined() }) @@ -435,15 +694,24 @@ describe('Contact store tests', (): void => { }) it('should get all identities for contact', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } - const savedContact = await contactStore.addContact(contact) + const savedContact: IContact = await contactStore.addContact(contact) expect(savedContact).toBeDefined() - const identity1 = { + const identity1: IBasicIdentity = { alias: 'test_alias1', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -451,10 +719,10 @@ describe('Contact store tests', (): void => { correlationId: 'example_did1', }, } - const savedIdentity1 = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity1 }) + const savedIdentity1: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity1 }) expect(savedIdentity1).toBeDefined() - const identity2 = { + const identity2: IBasicIdentity = { alias: 'test_alias2', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -462,28 +730,37 @@ describe('Contact store tests', (): void => { correlationId: 'example_did2', }, } - const savedIdentity2 = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity2 }) + const savedIdentity2: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity2 }) expect(savedIdentity2).toBeDefined() - const args = { + const args: IGetIdentitiesArgs = { filter: [{ contactId: savedContact.id }], } - const result = await contactStore.getIdentities(args) + const result: Array = await contactStore.getIdentities(args) expect(result.length).toEqual(2) }) it('should get all identities', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } - const savedContact = await contactStore.addContact(contact) + const savedContact: IContact = await contactStore.addContact(contact) expect(savedContact).toBeDefined() - const identity1 = { + const identity1: IBasicIdentity = { alias: 'test_alias1', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -491,10 +768,10 @@ describe('Contact store tests', (): void => { correlationId: 'example_did1', }, } - const savedIdentity1 = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity1 }) + const savedIdentity1: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity1 }) expect(savedIdentity1).toBeDefined() - const identity2 = { + const identity2: IBasicIdentity = { alias: 'test_alias2', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -502,25 +779,34 @@ describe('Contact store tests', (): void => { correlationId: 'example_did2', }, } - const savedIdentity2 = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity2 }) + const savedIdentity2: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity2 }) expect(savedIdentity2).toBeDefined() - const result = await contactStore.getIdentities() + const result: Array = await contactStore.getIdentities() expect(result.length).toEqual(2) }) it('should get identities by filter', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } - const savedContact = await contactStore.addContact(contact) + const savedContact: IContact = await contactStore.addContact(contact) expect(savedContact).toBeDefined() const alias = 'test_alias1' - const identity1 = { + const identity1: IBasicIdentity = { alias, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -528,10 +814,10 @@ describe('Contact store tests', (): void => { correlationId: 'example_did1', }, } - const savedIdentity1 = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity1 }) + const savedIdentity1: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity1 }) expect(savedIdentity1).toBeDefined() - const identity2 = { + const identity2: IBasicIdentity = { alias: 'test_alias2', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -539,29 +825,38 @@ describe('Contact store tests', (): void => { correlationId: 'example_did2', }, } - const savedIdentity2 = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity2 }) + const savedIdentity2: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity2 }) expect(savedIdentity2).toBeDefined() - const args = { + const args: IGetIdentitiesArgs = { filter: [{ alias }], } - const result = await contactStore.getIdentities(args) + const result: Array = await contactStore.getIdentities(args) expect(result.length).toEqual(1) }) it('should get whole identities by filter', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } - const savedContact = await contactStore.addContact(contact) + const savedContact: IContact = await contactStore.addContact(contact) expect(savedContact).toBeDefined() const alias = 'test_alias1' - const identity1 = { + const identity1: IBasicIdentity = { alias, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -579,29 +874,38 @@ describe('Contact store tests', (): void => { }, ], } - const savedIdentity1 = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity1 }) + const savedIdentity1: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity1 }) expect(savedIdentity1).toBeDefined() - const args = { + const args: IGetIdentitiesArgs = { filter: [{ metadata: { label: 'label1' } }], } - const result = await contactStore.getIdentities(args) + const result: Array = await contactStore.getIdentities(args) expect(result[0]).toBeDefined() expect(result[0].metadata!.length).toEqual(2) }) it('should add identity to contact', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } - const savedContact = await contactStore.addContact(contact) + const savedContact: IContact = await contactStore.addContact(contact) expect(savedContact).toBeDefined() - const identity = { + const identity: IBasicIdentity = { alias: 'test_alias', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -609,10 +913,10 @@ describe('Contact store tests', (): void => { correlationId: 'example_did', }, } - const savedIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity }) + const savedIdentity: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity }) expect(savedIdentity).toBeDefined() - const result = await contactStore.getContact({ contactId: savedContact.id }) + const result: IContact = await contactStore.getContact({ contactId: savedContact.id }) expect(result.identities.length).toEqual(1) }) @@ -623,16 +927,25 @@ describe('Contact store tests', (): void => { }) it('should throw error when adding identity with invalid identifier', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } - const savedContact = await contactStore.addContact(contact) + const savedContact: IContact = await contactStore.addContact(contact) expect(savedContact).toBeDefined() const correlationId = 'missing_connection_example' - const identity = { + const identity: IBasicIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -647,16 +960,25 @@ describe('Contact store tests', (): void => { }) it('should throw error when updating identity with invalid identifier', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } - const savedContact = await contactStore.addContact(contact) + const savedContact: IContact = await contactStore.addContact(contact) expect(savedContact).toBeDefined() const correlationId = 'missing_connection_example' - const identity = { + const identity: IBasicIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER, IdentityRoleEnum.HOLDER], identifier: { @@ -664,7 +986,7 @@ describe('Contact store tests', (): void => { correlationId, }, } - const storedIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity }) + const storedIdentity: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity }) storedIdentity.identifier = { ...storedIdentity.identifier, type: CorrelationIdentifierEnum.URL } await expect(contactStore.updateIdentity({ identity: storedIdentity })).rejects.toThrow( @@ -673,15 +995,24 @@ describe('Contact store tests', (): void => { }) it('should update identity by id', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, } - const savedContact = await contactStore.addContact(contact) + const savedContact: IContact = await contactStore.addContact(contact) expect(savedContact).toBeDefined() - const identity = { + const identity: IBasicIdentity = { alias: 'example_did', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -689,22 +1020,31 @@ describe('Contact store tests', (): void => { correlationId: 'example_did', }, } - const storedIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity }) + const storedIdentity: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity }) const correlationId = 'new_update_example_did' storedIdentity.identifier = { ...storedIdentity.identifier, correlationId } await contactStore.updateIdentity({ identity: storedIdentity }) - const result = await contactStore.getIdentity({ identityId: storedIdentity.id }) + const result: IIdentity = await contactStore.getIdentity({ identityId: storedIdentity.id }) - expect(result).not.toBeNull() + expect(result).toBeDefined() expect(result.identifier.correlationId).toEqual(correlationId) }) it('should get aggregate of identity roles on contact', async (): Promise => { - const contact = { - name: 'test_name', - alias: 'test_alias', + const contact: IBasicContact = { uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, identities: [ { alias: 'test_alias1', @@ -733,11 +1073,110 @@ describe('Contact store tests', (): void => { ], } - const savedContact = await contactStore.addContact(contact) - const result = await contactStore.getContact({ contactId: savedContact.id }) + const savedContact: IContact = await contactStore.addContact(contact) + const result: IContact = await contactStore.getContact({ contactId: savedContact.id }) expect(result.roles).toBeDefined() expect(result.roles.length).toEqual(3) expect(result.roles).toEqual([IdentityRoleEnum.VERIFIER, IdentityRoleEnum.ISSUER, IdentityRoleEnum.HOLDER]) }) + + it('should add relationship', async (): Promise => { + const contact1: IBasicContact = { + uri: 'example1.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + const savedContact1: IContact = await contactStore.addContact(contact1) + expect(savedContact1).toBeDefined() + + const contact2: IBasicContact = { + uri: 'example2.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + const savedContact2: IContact = await contactStore.addContact(contact2) + expect(savedContact2).toBeDefined() + + const relationship: BasicContactRelationship = { + leftContactId: savedContact1.id, + rightContactId: savedContact2.id + } + await contactStore.addRelationship(relationship) + + const result: IContact = await contactStore.getContact({ contactId: savedContact1.id }) + + expect(result).toBeDefined() + expect(result.relationships.length).toEqual(1) + expect(result.relationships[0].leftContactId).toEqual(savedContact1.id) + expect(result.relationships[0].rightContactId).toEqual(savedContact2.id) + }) + + it('should remove relationship', async (): Promise => { + const contact1: IBasicContact = { + uri: 'example1.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + const savedContact1: IContact = await contactStore.addContact(contact1) + expect(savedContact1).toBeDefined() + + const contact2: IBasicContact = { + uri: 'example2.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + const savedContact2: IContact = await contactStore.addContact(contact2) + expect(savedContact2).toBeDefined() + + const relationship: BasicContactRelationship = { + leftContactId: savedContact1.id, + rightContactId: savedContact2.id + } + const savedRelationship: IContactRelationship = await contactStore.addRelationship(relationship) + expect(savedRelationship).toBeDefined() + + await contactStore.removeRelationship({ relationshipId: savedRelationship.id }) + + const result: IContact = await contactStore.getContact({ contactId: savedContact1.id }) + + expect(result).toBeDefined() + expect(result?.relationships?.length).toEqual(0) + }) }) diff --git a/packages/data-store/src/contact/AbstractContactStore.ts b/packages/data-store/src/contact/AbstractContactStore.ts index de8a3c5ff..a02ebf4d1 100644 --- a/packages/data-store/src/contact/AbstractContactStore.ts +++ b/packages/data-store/src/contact/AbstractContactStore.ts @@ -15,13 +15,15 @@ import { export abstract class AbstractContactStore { abstract getContact(args: IGetContactArgs): Promise - abstract getContacts(args?: IGetContactsArgs): Promise> + abstract getContacts(args?: IGetContactsArgs): Promise> // TODO support person and organizations abstract addContact(args: IAddContactArgs): Promise - abstract updateContact(args: IUpdateContactArgs): Promise + abstract updateContact(args: IUpdateContactArgs): Promise // TODO support person and organizations abstract removeContact(args: IRemoveContactArgs): Promise abstract getIdentity(args: IGetIdentityArgs): Promise abstract getIdentities(args: IGetIdentitiesArgs): Promise> abstract addIdentity(args: IAddIdentityArgs): Promise abstract updateIdentity(args: IUpdateIdentityArgs): Promise abstract removeIdentity(args: IRemoveIdentityArgs): Promise + + // TODO support creating relations } diff --git a/packages/data-store/src/contact/ContactStore.ts b/packages/data-store/src/contact/ContactStore.ts index 55d61855e..e6de04761 100644 --- a/packages/data-store/src/contact/ContactStore.ts +++ b/packages/data-store/src/contact/ContactStore.ts @@ -13,28 +13,34 @@ import { IUpdateContactArgs, IRemoveContactArgs, BasicConnectionConfig, - ConnectionConfig, ConnectionTypeEnum, CorrelationIdentifierEnum, - IConnection, IContact, - ICorrelationIdentifier, - IDidAuthConfig, IIdentity, - IMetadataItem, - IOpenIdConfig, + IRemoveRelationshipArgs, + IContactRelationship, + IAddRelationshipArgs } from '../types' -import { ContactEntity, contactEntityFrom } from '../entities/contact/ContactEntity' -import { IdentityEntity, identityEntityFrom } from '../entities/contact/IdentityEntity' +import { ContactEntity, contactEntityFrom, contactFrom } from '../entities/contact/ContactEntity' +import { IdentityEntity, identityEntityFrom, identityFrom } from '../entities/contact/IdentityEntity' import { IdentityMetadataItemEntity } from '../entities/contact/IdentityMetadataItemEntity' import { CorrelationIdentifierEntity } from '../entities/contact/CorrelationIdentifierEntity' import { ConnectionEntity } from '../entities/contact/ConnectionEntity' -import { BaseConfigEntity } from '../entities/contact/BaseConfigEntity' -import { OpenIdConfigEntity } from '../entities/contact/OpenIdConfigEntity' -import { DidAuthConfigEntity } from '../entities/contact/DidAuthConfigEntity' -import { DataSource, In } from 'typeorm' +import { + BaseConfigEntity, + isDidAuthConfig, + isOpenIdConfig +} from '../entities/contact/BaseConfigEntity' +import { DataSource, FindOptionsWhere, In, Repository } from 'typeorm' +import { PersonEntity } from '../entities/contact/PersonEntity' +import { OrganizationEntity } from '../entities/contact/OrganizationEntity' +import { + ContactRelationshipEntity, + contactRelationshipEntityFrom, + contactRelationshipFrom +} from '../entities/contact/ContactRelationshipEntity' -const debug = Debug('sphereon:ssi-sdk:contact-store') +const debug: Debug.Debugger = Debug('sphereon:ssi-sdk:contact-store') export class ContactStore extends AbstractContactStore { private readonly dbConnection: OrPromise @@ -45,7 +51,7 @@ export class ContactStore extends AbstractContactStore { } getContact = async ({ contactId }: IGetContactArgs): Promise => { - const result = await (await this.dbConnection).getRepository(ContactEntity).findOne({ + const result: ContactEntity | null = await (await this.dbConnection).getRepository(ContactEntity).findOne({ where: { id: contactId }, }) @@ -53,32 +59,43 @@ export class ContactStore extends AbstractContactStore { return Promise.reject(Error(`No contact found for id: ${contactId}`)) } - return this.contactFrom(result) + return contactFrom(result) } getContacts = async (args?: IGetContactsArgs): Promise> => { - const initialResult = await (await this.dbConnection).getRepository(ContactEntity).find({ + const contactRepository: Repository = (await this.dbConnection).getRepository(ContactEntity) + const initialResult: Array | null = await contactRepository.find({ ...(args?.filter && { where: args?.filter }), }) - const result = await (await this.dbConnection).getRepository(ContactEntity).find({ + const result: Array | null = await contactRepository.find({ where: { id: In(initialResult.map((contact: ContactEntity) => contact.id)), }, }) - return result.map((contact: ContactEntity) => this.contactFrom(contact)) + return result.map((contact: ContactEntity) => contactFrom(contact)) } addContact = async (args: IAddContactArgs): Promise => { - const { name, alias, uri, identities } = args - - const result = await (await this.dbConnection).getRepository(ContactEntity).findOne({ - where: [{ name }, { alias }], + const { identities, contactOwner } = args //, alias, name, + + const contactRepository: Repository = (await this.dbConnection).getRepository(ContactEntity) + + // TODO extend with more names? + const result: ContactEntity | null = await contactRepository.findOne({ + where: [ + { + contactOwner: { + displayName: contactOwner.displayName, + } as FindOptionsWhere, + }, + ], }) if (result) { - return Promise.reject(Error(`Duplicate names or aliases are not allowed. Name: ${name}, Alias: ${alias}`)) + // TODO correct msg? + return Promise.reject(Error(`Duplicate names or display are not allowed. Display name: ${contactOwner.displayName}`)) //Name: ${name}, } for (const identity of identities ?? []) { @@ -93,15 +110,16 @@ export class ContactStore extends AbstractContactStore { } } - const contactEntity = contactEntityFrom({ name, alias, uri, identities }) - debug('Adding contact', name) - const createdResult = await (await this.dbConnection).getRepository(ContactEntity).save(contactEntity) + const contactEntity: ContactEntity = contactEntityFrom(args) + //debug('Adding contact', name) TODO fix + const createdResult: ContactEntity = await contactRepository.save(contactEntity) - return this.contactFrom(createdResult) + return contactFrom(createdResult) } updateContact = async ({ contact }: IUpdateContactArgs): Promise => { - const result = await (await this.dbConnection).getRepository(ContactEntity).findOne({ + const contactRepository: Repository = (await this.dbConnection).getRepository(ContactEntity) + const result: ContactEntity | null = await contactRepository.findOne({ where: { id: contact.id }, }) @@ -110,31 +128,30 @@ export class ContactStore extends AbstractContactStore { } const updatedContact = { + // TODO fix type ...contact, identities: result.identities, + relationships: result.relationships, } debug('Updating contact', contact) - const updatedResult = await (await this.dbConnection).getRepository(ContactEntity).save(updatedContact, { transaction: true }) + const updatedResult: ContactEntity = await contactRepository.save(updatedContact, { transaction: true }) - return this.contactFrom(updatedResult) + return contactFrom(updatedResult) } removeContact = async ({ contactId }: IRemoveContactArgs): Promise => { + const contactRepository: Repository = (await this.dbConnection).getRepository(ContactEntity) debug('Removing contact', contactId) - ;(await this.dbConnection) - .getRepository(ContactEntity) + ;contactRepository .findOneById(contactId) - .then(async (contact: ContactEntity | null) => { + .then(async (contact: ContactEntity | null): Promise => { if (!contact) { await Promise.reject(Error(`Unable to find the contact with id to remove: ${contactId}`)) } else { await this.deleteIdentities(contact.identities) - await ( - await this.dbConnection - ) - .getRepository(ContactEntity) + await contactRepository .delete({ id: contactId }) .catch((error) => Promise.reject(Error(`Unable to remove contact with id: ${contactId}. ${error}`))) } @@ -142,48 +159,8 @@ export class ContactStore extends AbstractContactStore { .catch((error) => Promise.reject(Error(`Unable to remove contact with id: ${contactId}. ${error}`))) } - private async deleteIdentities(identities: Array): Promise { - debug('Removing identities', identities) - - identities.map(async (identity: IdentityEntity) => { - await ( - await this.dbConnection - ) - .getRepository(CorrelationIdentifierEntity) - .delete(identity.identifier.id) - .catch((error) => Promise.reject(Error(`Unable to remove identity.identifier with id: ${identity.identifier.id}. ${error}`))) - - if (identity.connection) { - await (await this.dbConnection).getRepository(BaseConfigEntity).delete(identity.connection.config.id) - - await ( - await this.dbConnection - ) - .getRepository(ConnectionEntity) - .delete(identity.connection.id) - .catch((error) => Promise.reject(Error(`Unable to remove identity.connection with id. ${error}`))) - } - - if (identity.metadata) { - identity.metadata.map(async (metadataItem: IdentityMetadataItemEntity) => { - await ( - await this.dbConnection - ) - .getRepository(IdentityMetadataItemEntity) - .delete(metadataItem.id) - .catch((error) => Promise.reject(Error(`Unable to remove metadataItem.id with id ${metadataItem.id}. ${error}`))) - }) - } - - ;(await this.dbConnection) - .getRepository(IdentityEntity) - .delete(identity.id) - .catch((error) => Promise.reject(Error(`Unable to remove metadataItem.id with id ${identity.id}. ${error}`))) - }) - } - getIdentity = async ({ identityId }: IGetIdentityArgs): Promise => { - const result = await (await this.dbConnection).getRepository(IdentityEntity).findOne({ + const result: IdentityEntity | null = await (await this.dbConnection).getRepository(IdentityEntity).findOne({ where: { id: identityId }, }) @@ -191,25 +168,26 @@ export class ContactStore extends AbstractContactStore { return Promise.reject(Error(`No identity found for id: ${identityId}`)) } - return this.identityFrom(result) + return identityFrom(result) } getIdentities = async (args?: IGetIdentitiesArgs): Promise> => { - const initialResult = await (await this.dbConnection).getRepository(IdentityEntity).find({ + const identityRepository: Repository = (await this.dbConnection).getRepository(IdentityEntity) + const initialResult: Array = await identityRepository.find({ ...(args?.filter && { where: args?.filter }), }) - const result = await (await this.dbConnection).getRepository(IdentityEntity).find({ + const result: Array = await identityRepository.find({ where: { id: In(initialResult.map((identity: IdentityEntity) => identity.id)), }, }) - return result.map((identity: IdentityEntity) => this.identityFrom(identity)) + return result.map((identity: IdentityEntity) => identityFrom(identity)) } addIdentity = async ({ identity, contactId }: IAddIdentityArgs): Promise => { - const contact = await (await this.dbConnection).getRepository(ContactEntity).findOne({ + const contact: ContactEntity | null = await (await this.dbConnection).getRepository(ContactEntity).findOne({ where: { id: contactId }, }) @@ -227,18 +205,19 @@ export class ContactStore extends AbstractContactStore { } } - const identityEntity = identityEntityFrom(identity) + const identityEntity: IdentityEntity = identityEntityFrom(identity) identityEntity.contact = contact debug('Adding identity', identity) - const result = await (await this.dbConnection).getRepository(IdentityEntity).save(identityEntity, { + const result: IdentityEntity = await (await this.dbConnection).getRepository(IdentityEntity).save(identityEntity, { transaction: true, }) - return this.identityFrom(result) + return identityFrom(result) } updateIdentity = async ({ identity }: IUpdateIdentityArgs): Promise => { - const result = await (await this.dbConnection).getRepository(IdentityEntity).findOne({ + const identityRepository: Repository = (await this.dbConnection).getRepository(IdentityEntity) + const result: IdentityEntity | null = await identityRepository.findOne({ where: { id: identity.id }, }) @@ -257,13 +236,13 @@ export class ContactStore extends AbstractContactStore { } debug('Updating identity', identity) - const updatedResult = await (await this.dbConnection).getRepository(IdentityEntity).save(identity, { transaction: true }) + const updatedResult: IdentityEntity = await identityRepository.save(identity, { transaction: true }) - return this.identityFrom(updatedResult) + return identityFrom(updatedResult) } removeIdentity = async ({ identityId }: IRemoveIdentityArgs): Promise => { - const identity = await (await this.dbConnection).getRepository(IdentityEntity).findOne({ + const identity: IdentityEntity | null = await (await this.dbConnection).getRepository(IdentityEntity).findOne({ where: { id: identityId }, }) @@ -276,96 +255,107 @@ export class ContactStore extends AbstractContactStore { await this.deleteIdentities([identity]) } - private contactFrom = (contact: ContactEntity): IContact => { - return { - id: contact.id, - name: contact.name, - alias: contact.alias, - uri: contact.uri, - roles: [...new Set(contact.identities?.flatMap((identity) => identity.roles))] ?? [], - identities: contact.identities ? contact.identities.map((identity: IdentityEntity) => this.identityFrom(identity)) : [], - createdAt: contact.createdAt, - lastUpdatedAt: contact.lastUpdatedAt, - } - } + addRelationship = async ({ leftContactId, rightContactId }: IAddRelationshipArgs): Promise => { + // if (leftContactId === rightContactId) { + // return Promise.reject(Error(`Cannot use the same id for both sides of the relationship`)) + // } - private identityFrom = (identity: IdentityEntity): IIdentity => { - return { - id: identity.id, - alias: identity.alias, - roles: identity.roles, - identifier: this.correlationIdentifierFrom(identity.identifier), - ...(identity.connection && { connection: this.connectionFrom(identity.connection) }), - metadata: identity.metadata ? identity.metadata.map((item: IdentityMetadataItemEntity) => this.metadataItemFrom(item)) : [], - createdAt: identity.createdAt, - lastUpdatedAt: identity.createdAt, - } - } + const contactRepository: Repository = (await this.dbConnection).getRepository(ContactEntity) + const leftContact: ContactEntity | null = await contactRepository.findOne({ + where: { id: leftContactId }, + }) - private correlationIdentifierFrom = (identifier: CorrelationIdentifierEntity): ICorrelationIdentifier => { - return { - id: identifier.id, - type: identifier.type, - correlationId: identifier.correlationId, + if (!leftContact) { + return Promise.reject(Error(`No contact found for left contact id: ${leftContactId}`)) } - } - private metadataItemFrom = (item: IdentityMetadataItemEntity): IMetadataItem => { - return { - id: item.id, - label: item.label, - value: item.value, - } - } + const rightContact: ContactEntity | null = await contactRepository.findOne({ + where: { id: rightContactId }, + }) - private connectionFrom = (connection: ConnectionEntity): IConnection => { - return { - id: connection.id, - type: connection.type, - config: this.configFrom(connection.type, connection.config), + if (!rightContact) { + return Promise.reject(Error(`No contact found for right contact id: ${rightContactId}`)) } + + const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ + left: leftContact, + right: rightContact, + }) + + const createdResult: ContactRelationshipEntity = await (await this.dbConnection).getRepository(ContactRelationshipEntity).save(relationship) + + return contactRelationshipFrom(createdResult) } - private configFrom = (type: ConnectionTypeEnum, config: BaseConfigEntity): ConnectionConfig => { - switch (type) { - case ConnectionTypeEnum.OPENID_CONNECT: - return { - id: (config as OpenIdConfigEntity).id, - clientId: (config as OpenIdConfigEntity).clientId, - clientSecret: (config as OpenIdConfigEntity).clientSecret, - scopes: (config as OpenIdConfigEntity).scopes, - issuer: (config as OpenIdConfigEntity).issuer!, // TODO fixme - redirectUrl: (config as OpenIdConfigEntity).redirectUrl, - dangerouslyAllowInsecureHttpRequests: (config as OpenIdConfigEntity).dangerouslyAllowInsecureHttpRequests, - clientAuthMethod: (config as OpenIdConfigEntity).clientAuthMethod, - } - case ConnectionTypeEnum.SIOPv2: - return { - id: (config as DidAuthConfigEntity).id, - identifier: { did: (config as DidAuthConfigEntity).identifier, provider: '', keys: [], services: [] }, - stateId: '', - redirectUrl: (config as DidAuthConfigEntity).redirectUrl, - sessionId: (config as DidAuthConfigEntity).sessionId, - } - default: - throw new Error('Connection type not supported') + // TODO get relationship? + // TODO get relationships? + + removeRelationship = async ({ relationshipId }: IRemoveRelationshipArgs): Promise => { + const contactRelationshipRepository: Repository = (await this.dbConnection).getRepository(ContactRelationshipEntity) + const relationship: ContactRelationshipEntity | null = await contactRelationshipRepository.findOne({ + where: { id: relationshipId }, + }) + + if (!relationship) { + return Promise.reject(Error(`No relationship found for id: ${relationshipId}`)) } + + debug('Removing relationship', relationshipId) + + await contactRelationshipRepository.delete(relationshipId) } + // TODO functions for adding/removing contact types? + private hasCorrectConfig(type: ConnectionTypeEnum, config: BasicConnectionConfig): boolean { switch (type) { case ConnectionTypeEnum.OPENID_CONNECT: - return this.isOpenIdConfig(config) + return isOpenIdConfig(config) case ConnectionTypeEnum.SIOPv2: - return this.isDidAuthConfig(config) + return isDidAuthConfig(config) default: throw new Error('Connection type not supported') } } - private isOpenIdConfig = (config: BasicConnectionConfig): config is IOpenIdConfig => - 'clientSecret' in config && 'issuer' in config && 'redirectUrl' in config + private async deleteIdentities(identities: Array): Promise { + debug('Removing identities', identities) + + identities.map(async (identity: IdentityEntity): Promise => { + await ( + await this.dbConnection + ) + .getRepository(CorrelationIdentifierEntity) + .delete(identity.identifier.id) + .catch((error) => Promise.reject(Error(`Unable to remove identity.identifier with id: ${identity.identifier.id}. ${error}`))) + + if (identity.connection) { + await (await this.dbConnection).getRepository(BaseConfigEntity).delete(identity.connection.config.id) + + await ( + await this.dbConnection + ) + .getRepository(ConnectionEntity) + .delete(identity.connection.id) + .catch((error) => Promise.reject(Error(`Unable to remove identity.connection with id. ${error}`))) + } + + if (identity.metadata) { + identity.metadata.map(async (metadataItem: IdentityMetadataItemEntity): Promise => { + await ( + await this.dbConnection + ) + .getRepository(IdentityMetadataItemEntity) + .delete(metadataItem.id) + .catch((error) => Promise.reject(Error(`Unable to remove metadataItem.id with id ${metadataItem.id}. ${error}`))) + }) + } + + ;(await this.dbConnection) + .getRepository(IdentityEntity) + .delete(identity.id) + .catch((error) => Promise.reject(Error(`Unable to remove metadataItem.id with id ${identity.id}. ${error}`))) + }) + } - private isDidAuthConfig = (config: BasicConnectionConfig): config is IDidAuthConfig => - 'identifier' in config && 'redirectUrl' in config && 'sessionId' in config } diff --git a/packages/data-store/src/entities/contact/BaseConfigEntity.ts b/packages/data-store/src/entities/contact/BaseConfigEntity.ts index c59f4d945..0565175c3 100644 --- a/packages/data-store/src/entities/contact/BaseConfigEntity.ts +++ b/packages/data-store/src/entities/contact/BaseConfigEntity.ts @@ -1,4 +1,12 @@ import { BaseEntity, Entity, PrimaryGeneratedColumn, TableInheritance } from 'typeorm' +import { + BasicConnectionConfig, + ConnectionConfig, + IDidAuthConfig, + IOpenIdConfig +} from '../../types' +import { OpenIdConfigEntity } from './OpenIdConfigEntity' +import { DidAuthConfigEntity } from './DidAuthConfigEntity' @Entity('BaseConfigEntity') // FIXME rename it to 'BaseConfig' @TableInheritance({ column: { type: 'varchar', name: 'type' } }) @@ -6,3 +14,45 @@ export abstract class BaseConfigEntity extends BaseEntity { @PrimaryGeneratedColumn('uuid') id!: string } + +export const configFrom = (config: BaseConfigEntity): ConnectionConfig => { + // @ts-ignore + if (isOpenIdConfig(config)) { + return openIdConfigFrom(config) + // @ts-ignore + } else if (isDidAuthConfig(config)) { + // @ts-ignore + return didAuthConfigFrom(config) + } + + throw new Error('config type not supported') +} + +export const openIdConfigFrom = (config: OpenIdConfigEntity): IOpenIdConfig => { + return { + id: config.id, + clientId: config.clientId, + clientSecret: config.clientSecret, + scopes: config.scopes, + issuer: config.issuer!, // FIXME + redirectUrl: config.redirectUrl, + dangerouslyAllowInsecureHttpRequests: config.dangerouslyAllowInsecureHttpRequests, + clientAuthMethod: config.clientAuthMethod, + } +} + +export const didAuthConfigFrom = (config: DidAuthConfigEntity): IDidAuthConfig => { + return { + id: config.id, + identifier: { did: config.identifier, provider: '', keys: [], services: [] }, + stateId: '', // FIXME + redirectUrl: config.redirectUrl, + sessionId: config.sessionId, + } +} + +export const isOpenIdConfig = (config: BasicConnectionConfig): config is IOpenIdConfig => + 'clientSecret' in config && 'issuer' in config && 'redirectUrl' in config + +export const isDidAuthConfig = (config: BasicConnectionConfig): config is IDidAuthConfig => + 'identifier' in config && 'redirectUrl' in config && 'sessionId' in config diff --git a/packages/data-store/src/entities/contact/ConnectionEntity.ts b/packages/data-store/src/entities/contact/ConnectionEntity.ts index b577ed3c3..1d75c7756 100644 --- a/packages/data-store/src/entities/contact/ConnectionEntity.ts +++ b/packages/data-store/src/entities/contact/ConnectionEntity.ts @@ -1,6 +1,6 @@ import { Entity, Column, PrimaryGeneratedColumn, OneToOne, JoinColumn, BaseEntity } from 'typeorm' -import { BaseConfigEntity } from './BaseConfigEntity' -import { BasicConnectionConfig, ConnectionTypeEnum, IBasicConnection, IDidAuthConfig, IOpenIdConfig } from '../../types' +import { BaseConfigEntity, configFrom, isDidAuthConfig, isOpenIdConfig } from './BaseConfigEntity' +import { BasicConnectionConfig, BasicDidAuthConfig, BasicOpenIdConfig, ConnectionTypeEnum, IBasicConnection, IConnection } from '../../types' import { IdentityEntity } from './IdentityEntity' import { OpenIdConfigEntity, openIdConfigEntityFrom } from './OpenIdConfigEntity' import { DidAuthConfigEntity, didAuthConfigEntityFrom } from './DidAuthConfigEntity' @@ -29,20 +29,28 @@ export class ConnectionEntity extends BaseEntity { } export const connectionEntityFrom = (connection: IBasicConnection): ConnectionEntity => { - const connectionEntity = new ConnectionEntity() + const connectionEntity: ConnectionEntity = new ConnectionEntity() connectionEntity.type = connection.type - connectionEntity.config = configEntityFrom(connection.type, connection.config) + connectionEntity.config = configEntityFrom(connection.config) return connectionEntity } -const configEntityFrom = (type: ConnectionTypeEnum, config: BasicConnectionConfig): BaseConfigEntity => { - switch (type) { - case ConnectionTypeEnum.OPENID_CONNECT: - return openIdConfigEntityFrom(config as IOpenIdConfig) - case ConnectionTypeEnum.SIOPv2: - return didAuthConfigEntityFrom(config as IDidAuthConfig) - default: - throw new Error('Connection type not supported') +export const connectionFrom = (connection: ConnectionEntity): IConnection => { + return { + id: connection.id, + type: connection.type, + config: configFrom(connection.config), } } + +// TODO move to base config? +const configEntityFrom = (config: BasicConnectionConfig): BaseConfigEntity => { + if (isOpenIdConfig((config))) { + return openIdConfigEntityFrom(config) + } else if (isDidAuthConfig(config)) { + return didAuthConfigEntityFrom(config) + } + + throw new Error('config type not supported') +} diff --git a/packages/data-store/src/entities/contact/ContactEntity.ts b/packages/data-store/src/entities/contact/ContactEntity.ts index f4f8061ef..e8f36f949 100644 --- a/packages/data-store/src/entities/contact/ContactEntity.ts +++ b/packages/data-store/src/entities/contact/ContactEntity.ts @@ -6,27 +6,36 @@ import { CreateDateColumn, Entity, JoinColumn, + ManyToOne, OneToMany, + OneToOne, PrimaryGeneratedColumn, UpdateDateColumn, } from 'typeorm' -import { IBasicContact, IBasicIdentity } from '../../types' -import { IdentityEntity, identityEntityFrom } from './IdentityEntity' -import { IsNotEmpty, validate, ValidationError } from 'class-validator' +import { + BasicContactOwner, + BasicOrganization, + BasicPerson, + ContactOwner, + IBasicContact, + IBasicIdentity, + IContact, + ValidationConstraint, +} from '../../types' +import { IdentityEntity, identityEntityFrom, identityFrom } from './IdentityEntity' +import { validate, ValidationError } from 'class-validator' +import { ContactTypeEntity, contactTypeEntityFrom, contactTypeFrom } from './ContactTypeEntity' +import { ContactOwnerEntity } from './ContactOwnerEntity' +import { PersonEntity, personEntityFrom, personFrom } from './PersonEntity' +import { OrganizationEntity, organizationEntityFrom, organizationFrom } from './OrganizationEntity' +import { ContactRelationshipEntity, contactRelationshipFrom } from './ContactRelationshipEntity' +import { getConstraint } from '../../utils/ValidatorUtils' @Entity('Contact') export class ContactEntity extends BaseEntity { @PrimaryGeneratedColumn('uuid') id!: string - @Column({ name: 'name', length: 255, nullable: false, unique: true }) - @IsNotEmpty({ message: 'Blank names are not allowed' }) - name!: string - - @Column({ name: 'alias', length: 255, nullable: false, unique: true }) - @IsNotEmpty({ message: 'Blank aliases are not allowed' }) - alias!: string - @Column({ name: 'uri', length: 255 }) uri?: string @@ -39,6 +48,33 @@ export class ContactEntity extends BaseEntity { @JoinColumn({ name: 'identityId' }) identities!: Array + @ManyToOne(() => ContactTypeEntity, (contactType: ContactTypeEntity) => contactType.contacts, { + // cascade: ['insert', 'update'], + cascade: true, + // onDelete: 'CASCADE', + nullable: false, + eager: true, + }) // TODO check these options + @JoinColumn({ name: 'contactTypeId' }) + contactType!: ContactTypeEntity + + @OneToOne(() => ContactOwnerEntity, (member: PersonEntity | OrganizationEntity) => member.contact, { + cascade: true, + onDelete: 'CASCADE', + eager: true, + nullable: false, + }) + contactOwner!: ContactOwnerEntity + + @OneToMany(() => ContactRelationshipEntity, (relationship: ContactRelationshipEntity) => relationship.left, { + cascade: true, + onDelete: 'CASCADE', + eager: true, + nullable: false, + }) + @JoinColumn({ name: 'relationshipId' }) + relationships!: Array + @CreateDateColumn({ name: 'created_at', nullable: false }) createdAt!: Date @@ -48,27 +84,74 @@ export class ContactEntity extends BaseEntity { // By default, @UpdateDateColumn in TypeORM updates the timestamp only when the entity's top-level properties change. @BeforeInsert() @BeforeUpdate() - updateUpdatedDate() { + updateLastUpdatedDate(): void { this.lastUpdatedAt = new Date() } @BeforeInsert() @BeforeUpdate() - async validate() { + async validate(): Promise { const validation: Array = await validate(this) if (validation.length > 0) { - return Promise.reject(Error(Object.values(validation[0].constraints!)[0])) + const constraint: ValidationConstraint | undefined = getConstraint(validation[0]) + if (constraint) { + const message: string = Object.values(constraint!)[0] + return Promise.reject(Error(message)) + } } - return } } -export const contactEntityFrom = (args: IBasicContact): ContactEntity => { - const contactEntity = new ContactEntity() - contactEntity.name = args.name - contactEntity.alias = args.alias - contactEntity.uri = args.uri - contactEntity.identities = args.identities ? args.identities.map((identity: IBasicIdentity) => identityEntityFrom(identity)) : [] +export const contactEntityFrom = (contact: IBasicContact): ContactEntity => { + const contactEntity: ContactEntity = new ContactEntity() + contactEntity.uri = contact.uri + contactEntity.identities = contact.identities ? contact.identities.map((identity: IBasicIdentity) => identityEntityFrom(identity)) : [] + contactEntity.contactType = contactTypeEntityFrom(contact.contactType) + contactEntity.contactOwner = contactOwnerEntityFrom(contact.contactOwner) return contactEntity } + +export const contactFrom = (contact: ContactEntity): IContact => { + console.log('') + return { + id: contact.id, + uri: contact.uri, + roles: [...new Set(contact.identities?.flatMap((identity: IdentityEntity) => identity.roles))] ?? [], + identities: contact.identities ? contact.identities.map((identity: IdentityEntity) => identityFrom(identity)) : [], + relationships: contact.relationships ? contact.relationships.map((relationship: ContactRelationshipEntity) => contactRelationshipFrom(relationship)) : [], + contactType: contactTypeFrom(contact.contactType), + contactOwner: contactOwnerFrom(contact.contactOwner), + createdAt: contact.createdAt, + lastUpdatedAt: contact.lastUpdatedAt, + } +} + +// TODO move +export const contactOwnerEntityFrom = (owner: BasicContactOwner): ContactOwnerEntity => { + if (isPerson(owner)) { + return personEntityFrom(owner) + } else if (isOrganization(owner)) { + return organizationEntityFrom(owner) + } + + throw new Error('Owner type not supported') +} + +export const contactOwnerFrom = (owner: ContactOwnerEntity): ContactOwner => { + if (isPerson(owner)) { + // @ts-ignore + return personFrom(owner) + } else if (isOrganization(owner)) { + // @ts-ignore + return organizationFrom(owner) + } + + throw new Error('Owner type not supported') +} + +// TODO move? +const isPerson = (owner: BasicContactOwner | ContactOwnerEntity): owner is BasicPerson => + 'firstName' in owner && 'middleName' in owner && 'lastName' in owner + +const isOrganization = (owner: BasicContactOwner | ContactOwnerEntity): owner is BasicOrganization => 'legalName' in owner && 'cocNumber' in owner diff --git a/packages/data-store/src/entities/contact/ContactOwnerEntity.ts b/packages/data-store/src/entities/contact/ContactOwnerEntity.ts new file mode 100644 index 000000000..2b0f38825 --- /dev/null +++ b/packages/data-store/src/entities/contact/ContactOwnerEntity.ts @@ -0,0 +1,82 @@ +import { BaseEntity, CreateDateColumn, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn, TableInheritance, UpdateDateColumn } from 'typeorm' +import { ContactEntity } from './ContactEntity' +// import { IPerson } from '../../types' +// import { PersonEntity } from './PersonEntity' +// import { +// // BasicContactOwner, +// // BasicOrganization, +// // BasicPerson, +// // ContactOwner +// } from '../../types' +// import { organizationEntityFrom, organizationFrom } from './OrganizationEntity' +// import { personEntityFrom, personFrom } from './PersonEntity' + +@Entity('ContactOwner') +@TableInheritance({ column: { type: 'varchar', name: 'type' } }) +export abstract class ContactOwnerEntity extends BaseEntity { + @PrimaryGeneratedColumn('uuid') + id!: string + + @CreateDateColumn({ name: 'created_at', nullable: false }) + createdAt!: Date + + @UpdateDateColumn({ name: 'last_updated_at', nullable: false }) + lastUpdatedAt!: Date + + @OneToOne(() => ContactEntity, (contact: ContactEntity) => contact.contactOwner, { + onDelete: 'CASCADE', + }) + @JoinColumn({ name: 'contactId' }) + contact!: ContactEntity +} + +// export const contactOwnerEntityFrom = (owner: BasicContactOwner): ContactOwnerEntity => { +// if (isPerson(owner)) { +// return personEntityFrom(owner) +// } else if (isOrganization(owner)) { +// return organizationEntityFrom(owner) +// } +// +// throw new Error('Owner type not supported') +// +// +// // switch (type) { +// // case ContactTypeEnum.PERSON: +// // return personEntityFrom(owner) +// // case ContactTypeEnum.ORGANIZATION: +// // return organizationEntityFrom(owner) +// // default: +// // throw new Error('Contact type not supported') +// // } +// } + +// export const contactOwnerFrom = (owner: ContactOwnerEntity): ContactOwner => { +// if (isPerson(owner)) { +// // @ts-ignore +// return personFrom(owner) +// } else if (isOrganization(owner)) { +// // @ts-ignore +// return organizationFrom(owner) +// } +// +// throw new Error('Owner type not supported') +// } +// +// // TODO move? +// const isPerson = (owner: BasicContactOwner | ContactOwnerEntity): owner is BasicPerson => +// 'firstName' in owner && 'middleName' in owner && 'lastName' in owner +// +// const isOrganization = (owner: BasicContactOwner | ContactOwnerEntity): owner is BasicOrganization => +// 'legalName' in owner && 'cocNumber' in owner + +// export const personFrom = (person: PersonEntity): IPerson => { +// return { +// id: person.id, +// firstName: person.firstName, +// middleName: person.middleName, +// lastName: person.lastName, +// displayName: person.displayName, +// createdAt: person.createdAt, +// lastUpdatedAt: person.lastUpdatedAt, +// } +// } diff --git a/packages/data-store/src/entities/contact/ContactRelationshipEntity.ts b/packages/data-store/src/entities/contact/ContactRelationshipEntity.ts new file mode 100644 index 000000000..1898a08e1 --- /dev/null +++ b/packages/data-store/src/entities/contact/ContactRelationshipEntity.ts @@ -0,0 +1,76 @@ +import { + Entity, + // JoinColumn, + PrimaryGeneratedColumn, + CreateDateColumn, + UpdateDateColumn, + ManyToOne, + // Column, + Index, BeforeInsert, BeforeUpdate, Column +} from 'typeorm' +import { ContactEntity } from './ContactEntity' +import { IContactRelationship } from '../../types' + +@Entity() +// @Index(['leftContactId', 'rightContactId'], { unique: true }) // TODO name\ +@Index(['left', 'right'], { unique: true }) // TODO name +export class ContactRelationshipEntity { + @PrimaryGeneratedColumn('uuid') + id!: string + + @ManyToOne(() => ContactEntity, { + nullable: false, + onDelete: 'CASCADE', + }) + // @JoinColumn({ name: 'left_contact_id' }) + left!: ContactEntity + + @Column({ name: 'left', nullable: true }) + leftContactId?: string + + @ManyToOne(() => ContactEntity, { + nullable: false, + onDelete: 'CASCADE', + }) + // @JoinColumn({ name: 'right_contact_id' }) + right!: ContactEntity + + @Column({ name: 'right', nullable: true }) + rightContactId?: string + + @CreateDateColumn({ name: 'created_at', nullable: false }) + createdAt!: Date + + @UpdateDateColumn({ name: 'last_updated_at', nullable: false }) + lastUpdatedAt!: Date + + @BeforeInsert() + @BeforeUpdate() + async checkRelationshipSides(): Promise { + if (this.left.id === this.right.id) { + return Promise.reject(Error('Cannot use the same id for both sides of the relationship')) + } + } +} + +// TODO interface +export const contactRelationshipEntityFrom = (relationship: { left: ContactEntity; right: ContactEntity }): ContactRelationshipEntity => { + // TODO convert IContact to ContactEntity here + + const contactRelationshipEntity: ContactRelationshipEntity = new ContactRelationshipEntity() + contactRelationshipEntity.left = relationship.left + contactRelationshipEntity.right = relationship.right + return contactRelationshipEntity +} + +export const contactRelationshipFrom = (relationship: ContactRelationshipEntity): IContactRelationship => { + console.log('') + return { + id: relationship.id, + leftContactId: relationship.left.id, + rightContactId: relationship.right.id, + createdAt: relationship.createdAt, + lastUpdatedAt: relationship.lastUpdatedAt + } + // TODO convert IContact to ContactEntity here +} diff --git a/packages/data-store/src/entities/contact/ContactTypeEntity.ts b/packages/data-store/src/entities/contact/ContactTypeEntity.ts new file mode 100644 index 000000000..c0853d315 --- /dev/null +++ b/packages/data-store/src/entities/contact/ContactTypeEntity.ts @@ -0,0 +1,91 @@ +import { + Entity, + //JoinColumn, + PrimaryGeneratedColumn, + Column, + Index, + CreateDateColumn, + UpdateDateColumn, + OneToMany, + BeforeInsert, + BeforeUpdate, +} from 'typeorm' +import { ContactEntity } from './ContactEntity' +import { BasicContactType, ContactTypeEnum, IContactType, ValidationConstraint } from '../../types' +import { IsNotEmpty, Validate, validate, ValidationError } from 'class-validator' +import { IsNonEmptyStringConstraint } from '../validators' +import { getConstraint } from '../../utils/ValidatorUtils' + +@Entity() +@Index(['type', 'tenantId'], { unique: true }) // TODO name example: 'IDX_CredentialLocaleBrandingEntity_credentialBranding_locale', +export class ContactTypeEntity { + @PrimaryGeneratedColumn('uuid') + id!: string + + @Column('simple-enum', { name: 'type', enum: ContactTypeEnum, nullable: false, unique: false }) + type!: ContactTypeEnum + + @Column({ name: 'name', length: 255, nullable: false, unique: true }) + @IsNotEmpty({ message: 'Blank names are not allowed' }) + name!: string + + @Column({ name: 'description', length: 255, nullable: true, unique: false }) + @Validate(IsNonEmptyStringConstraint, { message: 'Blank descriptions are not allowed' }) + description?: string + + // TODO why is the tenantId in this entity? + @Column({ name: 'tenantId', length: 255, nullable: false, unique: true }) + @IsNotEmpty({ message: "Blank tenant id's are not allowed" }) + tenantId!: string + + @OneToMany(() => ContactEntity, (contact: ContactEntity) => contact.contactType, { + // cascade: true, + // onDelete: 'CASCADE', + // eager: true, // TODO check this relation + nullable: false, + }) + // @JoinColumn({ name: 'contactId' }) + contacts!: Array + + @CreateDateColumn({ name: 'created_at', nullable: false }) + createdAt!: Date + + @UpdateDateColumn({ name: 'last_updated_at', nullable: false }) + lastUpdatedAt!: Date + + @BeforeInsert() + @BeforeUpdate() + async validate(): Promise { + const validation: Array = await validate(this) + if (validation.length > 0) { + const constraint: ValidationConstraint | undefined = getConstraint(validation[0]) + if (constraint) { + const message: string = Object.values(constraint!)[0] + return Promise.reject(Error(message)) + } + } + } +} + +export const contactTypeEntityFrom = (args: BasicContactType): ContactTypeEntity => { + const contactTypeEntity: ContactTypeEntity = new ContactTypeEntity() + contactTypeEntity.type = args.type + contactTypeEntity.name = args.name + contactTypeEntity.description = args.description + contactTypeEntity.tenantId = args.tenantId + // TODO contacts? + + return contactTypeEntity +} + +export const contactTypeFrom = (contactType: ContactTypeEntity): IContactType => { + return { + id: contactType.id, + type: contactType.type, + name: contactType.name, + tenantId: contactType.tenantId, + description: contactType.description, + createdAt: contactType.createdAt, + lastUpdatedAt: contactType.lastUpdatedAt, + } +} diff --git a/packages/data-store/src/entities/contact/CorrelationIdentifierEntity.ts b/packages/data-store/src/entities/contact/CorrelationIdentifierEntity.ts index caac9a437..2df6ddab3 100644 --- a/packages/data-store/src/entities/contact/CorrelationIdentifierEntity.ts +++ b/packages/data-store/src/entities/contact/CorrelationIdentifierEntity.ts @@ -1,7 +1,8 @@ import { Entity, Column, PrimaryGeneratedColumn, BaseEntity, OneToOne, JoinColumn, BeforeInsert, BeforeUpdate } from 'typeorm' -import { CorrelationIdentifierEnum, BasicCorrelationIdentifier } from '../../types' +import { CorrelationIdentifierEnum, BasicCorrelationIdentifier, ICorrelationIdentifier, ValidationConstraint } from '../../types' import { IdentityEntity } from './IdentityEntity' import { IsNotEmpty, validate, ValidationError } from 'class-validator' +import { getConstraint } from '../../utils/ValidatorUtils' @Entity('CorrelationIdentifier') export class CorrelationIdentifierEntity extends BaseEntity { @@ -23,19 +24,30 @@ export class CorrelationIdentifierEntity extends BaseEntity { @BeforeInsert() @BeforeUpdate() - async validate() { + async validate(): Promise { const validation: Array = await validate(this) if (validation.length > 0) { - return Promise.reject(Error(Object.values(validation[0].constraints!)[0])) + const constraint: ValidationConstraint | undefined = getConstraint(validation[0]) + if (constraint) { + const message: string = Object.values(constraint!)[0] + return Promise.reject(Error(message)) + } } - return } } export const correlationIdentifierEntityFrom = (identifier: BasicCorrelationIdentifier): CorrelationIdentifierEntity => { - const identifierEntity = new CorrelationIdentifierEntity() + const identifierEntity: CorrelationIdentifierEntity = new CorrelationIdentifierEntity() identifierEntity.type = identifier.type identifierEntity.correlationId = identifier.correlationId return identifierEntity } + +export const correlationIdentifierFrom = (identifier: CorrelationIdentifierEntity): ICorrelationIdentifier => { + return { + id: identifier.id, + type: identifier.type, + correlationId: identifier.correlationId, + } +} diff --git a/packages/data-store/src/entities/contact/DidAuthConfigEntity.ts b/packages/data-store/src/entities/contact/DidAuthConfigEntity.ts index 93b0a4b9a..ff2827c2e 100644 --- a/packages/data-store/src/entities/contact/DidAuthConfigEntity.ts +++ b/packages/data-store/src/entities/contact/DidAuthConfigEntity.ts @@ -14,6 +14,7 @@ export class DidAuthConfigEntity extends BaseConfigEntity { @Column({ name: 'session_id', length: 255, nullable: false }) sessionId!: string + // TODO can we move this to the base entity? @OneToOne(() => ConnectionEntity, (connection: ConnectionEntity) => connection.config, { onDelete: 'CASCADE', }) @@ -22,7 +23,7 @@ export class DidAuthConfigEntity extends BaseConfigEntity { } export const didAuthConfigEntityFrom = (config: BasicDidAuthConfig): DidAuthConfigEntity => { - const didAuthConfig = new DidAuthConfigEntity() + const didAuthConfig: DidAuthConfigEntity = new DidAuthConfigEntity() didAuthConfig.identifier = config.identifier.did didAuthConfig.redirectUrl = config.redirectUrl didAuthConfig.sessionId = config.sessionId diff --git a/packages/data-store/src/entities/contact/IdentityEntity.ts b/packages/data-store/src/entities/contact/IdentityEntity.ts index 815d5c930..57ffef968 100644 --- a/packages/data-store/src/entities/contact/IdentityEntity.ts +++ b/packages/data-store/src/entities/contact/IdentityEntity.ts @@ -13,11 +13,12 @@ import { BeforeUpdate, } from 'typeorm' import { IsNotEmpty, validate, ValidationError } from 'class-validator' -import { correlationIdentifierEntityFrom, CorrelationIdentifierEntity } from './CorrelationIdentifierEntity' -import { ConnectionEntity, connectionEntityFrom } from './ConnectionEntity' -import { IdentityMetadataItemEntity, metadataItemEntityFrom } from './IdentityMetadataItemEntity' -import { BasicMetadataItem, IBasicIdentity, IdentityRoleEnum } from '../../types' +import { correlationIdentifierEntityFrom, CorrelationIdentifierEntity, correlationIdentifierFrom } from './CorrelationIdentifierEntity' +import { ConnectionEntity, connectionEntityFrom, connectionFrom } from './ConnectionEntity' +import { IdentityMetadataItemEntity, metadataItemEntityFrom, metadataItemFrom } from './IdentityMetadataItemEntity' +import { BasicMetadataItem, IBasicIdentity, IdentityRoleEnum, IIdentity, ValidationConstraint } from '../../types' import { ContactEntity } from './ContactEntity' +import { getConstraint } from '../../utils/ValidatorUtils' @Entity('Identity') export class IdentityEntity extends BaseEntity { @@ -77,23 +78,26 @@ export class IdentityEntity extends BaseEntity { // By default, @UpdateDateColumn in TypeORM updates the timestamp only when the entity's top-level properties change. @BeforeInsert() @BeforeUpdate() - updateUpdatedDate() { + updateLastUpdatedDate(): void { this.lastUpdatedAt = new Date() } @BeforeInsert() @BeforeUpdate() - async validate() { + async validate(): Promise { const validation: Array = await validate(this) if (validation.length > 0) { - return Promise.reject(Error(Object.values(validation[0].constraints!)[0])) + const constraint: ValidationConstraint | undefined = getConstraint(validation[0]) + if (constraint) { + const message: string = Object.values(constraint!)[0] + return Promise.reject(Error(message)) + } } - return } } export const identityEntityFrom = (args: IBasicIdentity): IdentityEntity => { - const identityEntity = new IdentityEntity() + const identityEntity: IdentityEntity = new IdentityEntity() identityEntity.alias = args.alias identityEntity.roles = args.roles identityEntity.identifier = correlationIdentifierEntityFrom(args.identifier) @@ -102,3 +106,16 @@ export const identityEntityFrom = (args: IBasicIdentity): IdentityEntity => { return identityEntity } + +export const identityFrom = (identity: IdentityEntity): IIdentity => { + return { + id: identity.id, + alias: identity.alias, + roles: identity.roles, + identifier: correlationIdentifierFrom(identity.identifier), + ...(identity.connection && { connection: connectionFrom(identity.connection) }), + metadata: identity.metadata ? identity.metadata.map((item: IdentityMetadataItemEntity) => metadataItemFrom(item)) : [], + createdAt: identity.createdAt, + lastUpdatedAt: identity.createdAt, + } +} diff --git a/packages/data-store/src/entities/contact/IdentityMetadataItemEntity.ts b/packages/data-store/src/entities/contact/IdentityMetadataItemEntity.ts index 1c511a2d2..187da329d 100644 --- a/packages/data-store/src/entities/contact/IdentityMetadataItemEntity.ts +++ b/packages/data-store/src/entities/contact/IdentityMetadataItemEntity.ts @@ -1,7 +1,8 @@ import { Entity, Column, PrimaryGeneratedColumn, BaseEntity, ManyToOne, BeforeInsert, BeforeUpdate } from 'typeorm' -import { BasicMetadataItem } from '../../types' +import { BasicMetadataItem, IMetadataItem, ValidationConstraint } from '../../types' import { IdentityEntity } from './IdentityEntity' import { IsNotEmpty, validate, ValidationError } from 'class-validator' +import { getConstraint } from '../../utils/ValidatorUtils' @Entity('IdentityMetadata') export class IdentityMetadataItemEntity extends BaseEntity { @@ -21,19 +22,30 @@ export class IdentityMetadataItemEntity extends BaseEntity { @BeforeInsert() @BeforeUpdate() - async validate() { + async validate(): Promise { const validation: Array = await validate(this) if (validation.length > 0) { - return Promise.reject(Error(Object.values(validation[0].constraints!)[0])) + const constraint: ValidationConstraint | undefined = getConstraint(validation[0]) + if (constraint) { + const message: string = Object.values(constraint!)[0] + return Promise.reject(Error(message)) + } } - return } } export const metadataItemEntityFrom = (item: BasicMetadataItem): IdentityMetadataItemEntity => { - const metadataItem = new IdentityMetadataItemEntity() + const metadataItem: IdentityMetadataItemEntity = new IdentityMetadataItemEntity() metadataItem.label = item.label metadataItem.value = item.value return metadataItem } + +export const metadataItemFrom = (item: IdentityMetadataItemEntity): IMetadataItem => { + return { + id: item.id, + label: item.label, + value: item.value, + } +} diff --git a/packages/data-store/src/entities/contact/OpenIdConfigEntity.ts b/packages/data-store/src/entities/contact/OpenIdConfigEntity.ts index dcb18a368..44ba141bf 100644 --- a/packages/data-store/src/entities/contact/OpenIdConfigEntity.ts +++ b/packages/data-store/src/entities/contact/OpenIdConfigEntity.ts @@ -35,7 +35,7 @@ export class OpenIdConfigEntity extends BaseConfigEntity { } export const openIdConfigEntityFrom = (config: BasicOpenIdConfig): OpenIdConfigEntity => { - const openIdConfig = new OpenIdConfigEntity() + const openIdConfig: OpenIdConfigEntity = new OpenIdConfigEntity() openIdConfig.clientId = config.clientId openIdConfig.clientSecret = config.clientSecret openIdConfig.scopes = config.scopes diff --git a/packages/data-store/src/entities/contact/OrganizationEntity.ts b/packages/data-store/src/entities/contact/OrganizationEntity.ts new file mode 100644 index 000000000..a7516982d --- /dev/null +++ b/packages/data-store/src/entities/contact/OrganizationEntity.ts @@ -0,0 +1,59 @@ +import { JoinColumn, OneToOne, Column, ChildEntity, BeforeInsert, BeforeUpdate } from 'typeorm' +import { ContactEntity } from './ContactEntity' +import { ContactOwnerEntity } from './ContactOwnerEntity' +import { BasicOrganization, IOrganization, ValidationConstraint } from '../../types' +import { validate, IsNotEmpty, ValidationError, Validate } from 'class-validator' +import { IsNonEmptyStringConstraint } from '../validators' +import { getConstraint } from '../../utils/ValidatorUtils' + +@ChildEntity('Organization') +export class OrganizationEntity extends ContactOwnerEntity { + @Column({ name: 'legalName', length: 255, nullable: false, unique: true }) + @IsNotEmpty({ message: 'Blank legal names are not allowed' }) + legalName!: string + + @Column({ name: 'displayName', length: 255, nullable: false, unique: true }) + @IsNotEmpty({ message: 'Blank display names are not allowed' }) + displayName!: string + + @Column({ name: 'cocNumber', length: 255, nullable: true, unique: true }) + @Validate(IsNonEmptyStringConstraint, { message: 'Blank coc numbers are not allowed' }) + cocNumber?: string + + @OneToOne(() => ContactEntity) + @JoinColumn({ name: 'contactId' }) + contact!: ContactEntity + + @BeforeInsert() + @BeforeUpdate() + async validate(): Promise { + const validation: Array = await validate(this) + if (validation.length > 0) { + const constraint: ValidationConstraint | undefined = getConstraint(validation[0]) + if (constraint) { + const message: string = Object.values(constraint!)[0] + return Promise.reject(Error(message)) + } + } + } +} + +export const organizationEntityFrom = (organization: BasicOrganization): OrganizationEntity => { + const organizationEntity: OrganizationEntity = new OrganizationEntity() + organizationEntity.legalName = organization.legalName + organizationEntity.displayName = organization.displayName + organizationEntity.cocNumber = organization.cocNumber + + return organizationEntity +} + +export const organizationFrom = (organization: OrganizationEntity): IOrganization => { + return { + id: organization.id, + legalName: organization.legalName, + displayName: organization.displayName, + cocNumber: organization.cocNumber, + createdAt: organization.createdAt, + lastUpdatedAt: organization.lastUpdatedAt, + } +} diff --git a/packages/data-store/src/entities/contact/PersonEntity.ts b/packages/data-store/src/entities/contact/PersonEntity.ts new file mode 100644 index 000000000..207e2a3af --- /dev/null +++ b/packages/data-store/src/entities/contact/PersonEntity.ts @@ -0,0 +1,62 @@ +import { Column, ChildEntity, BeforeInsert, BeforeUpdate } from 'typeorm' +import { ContactOwnerEntity } from './ContactOwnerEntity' +import { BasicPerson, IPerson, ValidationConstraint } from '../../types' +import { validate, IsNotEmpty, ValidationError, Validate } from 'class-validator' +import { IsNonEmptyStringConstraint } from '../validators' +import { getConstraint } from '../../utils/ValidatorUtils' + +@ChildEntity('Person') +export class PersonEntity extends ContactOwnerEntity { + @Column({ name: 'firstName', length: 255, nullable: false, unique: false }) + @IsNotEmpty({ message: 'Blank first names are not allowed' }) + firstName!: string + + @Column({ name: 'middleName', length: 255, nullable: true, unique: false }) + @Validate(IsNonEmptyStringConstraint, { message: 'Blank middle names are not allowed' }) + middleName?: string + + @Column({ name: 'lastName', length: 255, nullable: false, unique: false }) + @IsNotEmpty({ message: 'Blank last names are not allowed' }) + lastName!: string + + // TODO do we want a suffix? + + @Column({ name: 'displayName', length: 255, nullable: false, unique: true }) + @IsNotEmpty({ message: 'Blank display names are not allowed' }) + displayName!: string + + @BeforeInsert() + @BeforeUpdate() + async validate(): Promise { + const validation: Array = await validate(this) + if (validation.length > 0) { + const constraint: ValidationConstraint | undefined = getConstraint(validation[0]) + if (constraint) { + const message: string = Object.values(constraint!)[0] + return Promise.reject(Error(message)) + } + } + } +} + +export const personEntityFrom = (person: BasicPerson): PersonEntity => { + const personEntity: PersonEntity = new PersonEntity() + personEntity.firstName = person.firstName + personEntity.middleName = person.middleName + personEntity.lastName = person.lastName + personEntity.displayName = person.displayName + + return personEntity +} + +export const personFrom = (person: PersonEntity): IPerson => { + return { + id: person.id, + firstName: person.firstName, + middleName: person.middleName, + lastName: person.lastName, + displayName: person.displayName, + createdAt: person.createdAt, + lastUpdatedAt: person.lastUpdatedAt, + } +} diff --git a/packages/data-store/src/index.ts b/packages/data-store/src/index.ts index 1f622710b..c538c896b 100644 --- a/packages/data-store/src/index.ts +++ b/packages/data-store/src/index.ts @@ -15,6 +15,11 @@ import { ImageDimensionsEntity, imageDimensionsEntityFrom } from './entities/iss import { IssuerLocaleBrandingEntity, issuerLocaleBrandingEntityFrom } from './entities/issuanceBranding/IssuerLocaleBrandingEntity' import { IssuerBrandingEntity, issuerBrandingEntityFrom } from './entities/issuanceBranding/IssuerBrandingEntity' import { TextAttributesEntity, textAttributesEntityFrom } from './entities/issuanceBranding/TextAttributesEntity' +import { ContactRelationshipEntity } from './entities/contact/ContactRelationshipEntity' +import { ContactTypeEntity } from './entities/contact/ContactTypeEntity' +import { ContactOwnerEntity } from './entities/contact/ContactOwnerEntity' +import { OrganizationEntity } from './entities/contact/OrganizationEntity' +import { PersonEntity } from './entities/contact/PersonEntity' export { ContactStore } from './contact/ContactStore' export { AbstractContactStore } from './contact/AbstractContactStore' @@ -32,6 +37,11 @@ export const DataStoreContactEntities = [ CorrelationIdentifierEntity, DidAuthConfigEntity, OpenIdConfigEntity, + ContactRelationshipEntity, + ContactTypeEntity, + ContactOwnerEntity, + OrganizationEntity, + PersonEntity, ] export const DataStoreIssuanceBrandingEntities = [ diff --git a/packages/data-store/src/types/contact/IAbstractContactStore.ts b/packages/data-store/src/types/contact/IAbstractContactStore.ts index b9b26435d..d0c504491 100644 --- a/packages/data-store/src/types/contact/IAbstractContactStore.ts +++ b/packages/data-store/src/types/contact/IAbstractContactStore.ts @@ -1,11 +1,14 @@ -import { FindOptionsWhere } from 'typeorm' -import { ContactEntity } from '../../entities/contact/ContactEntity' -import { IdentityEntity } from '../../entities/contact/IdentityEntity' -import { IBasicIdentity, IContact, IIdentity } from './contact' +// import { FindOptionsWhere } from 'typeorm' +// import { ContactEntity } from '../../entities/contact/ContactEntity' +// import { IdentityEntity } from '../../entities/contact/IdentityEntity' +import { BasicContactType, BasicContactOwner, IBasicIdentity, IContact, IIdentity, IPartialContact, IPartialIdentity } from './contact' // TODO WAL-625 refactor types to use interfaces and not the entities as the store should be replaceable -export type FindContactArgs = FindOptionsWhere[] -export type FindIdentityArgs = FindOptionsWhere[] +// export type FindContactArgs = FindOptionsWhere[] +// export type FindIdentityArgs = FindOptionsWhere[] + +export type FindContactArgs = Array +export type FindIdentityArgs = Array export interface IGetContactArgs { contactId: string @@ -16,9 +19,11 @@ export interface IGetContactsArgs { } export interface IAddContactArgs { - name: string - alias: string - uri?: string + // name: string + // alias: string + uri?: string // TODO what we do with uri? + contactType: BasicContactType // TODO we can have a situation where we want to add a contact to an existing type, so use BasicContactType | IContactType? also make a test for these 2 situations in the store + contactOwner: BasicContactOwner identities?: Array } @@ -50,3 +55,12 @@ export interface IUpdateIdentityArgs { export interface IRemoveIdentityArgs { identityId: string } + +export interface IRemoveRelationshipArgs { + relationshipId: string +} + +export interface IAddRelationshipArgs { + leftContactId: string + rightContactId: string +} diff --git a/packages/data-store/src/types/contact/contact.ts b/packages/data-store/src/types/contact/contact.ts index 33430947c..fbc711682 100644 --- a/packages/data-store/src/types/contact/contact.ts +++ b/packages/data-store/src/types/contact/contact.ts @@ -19,19 +19,27 @@ export enum CorrelationIdentifierEnum { export interface IContact { id: string - name: string - alias: string uri?: string roles: Array identities: Array + contactOwner: ContactOwner + contactType: IContactType + relationships: Array createdAt: Date lastUpdatedAt: Date } export interface IBasicContact { - name: string - alias: string uri?: string identities?: Array + contactOwner: BasicContactOwner + contactType: BasicContactType + relationships?: Array +} +export interface IPartialContact extends Partial> { + identities?: IPartialIdentity + contactOwner?: PartialContactOwner + contactType?: IPartialContactType + relationships?: IPartialContactRelationship } export interface IIdentity { @@ -51,6 +59,13 @@ export interface IBasicIdentity { connection?: IBasicConnection metadata?: Array } +export interface IPartialIdentity extends Partial> { + identifier?: IPartialCorrelationIdentifier + connection?: IPartialConnection + metadata?: IPartialMetadataItem + roles?: IdentityRoleEnum //FindOperator + contactId?: string +} export interface IMetadataItem { id: string @@ -58,6 +73,7 @@ export interface IMetadataItem { value: string } export declare type BasicMetadataItem = Omit +export interface IPartialMetadataItem extends Partial {} export interface ICorrelationIdentifier { id: string @@ -65,6 +81,7 @@ export interface ICorrelationIdentifier { correlationId: string } export declare type BasicCorrelationIdentifier = Omit +export interface IPartialCorrelationIdentifier extends Partial {} export interface IConnection { id: string @@ -75,6 +92,9 @@ export interface IBasicConnection { type: ConnectionTypeEnum config: BasicConnectionConfig } +export interface IPartialConnection extends Partial> { + config: PartialConnectionConfig +} export interface IOpenIdConfig { id: string @@ -87,6 +107,7 @@ export interface IOpenIdConfig { clientAuthMethod: 'basic' | 'post' | undefined } export declare type BasicOpenIdConfig = Omit +export interface IPartialOpenIdConfig extends Partial {} export interface IDidAuthConfig { id: string @@ -96,6 +117,67 @@ export interface IDidAuthConfig { sessionId: string } export declare type BasicDidAuthConfig = Omit +export interface IPartialDidAuthConfig extends Partial> { + identifier: Partial // TODO +} export declare type ConnectionConfig = IOpenIdConfig | IDidAuthConfig export declare type BasicConnectionConfig = BasicDidAuthConfig | BasicOpenIdConfig +export declare type PartialConnectionConfig = IPartialOpenIdConfig | IPartialDidAuthConfig + +export enum ContactTypeEnum { + PERSON = 'person', + ORGANIZATION = 'organization', +} + +export interface IPerson { + id: string + firstName: string + lastName: string + middleName?: string + displayName: string + createdAt: Date + lastUpdatedAt: Date +} +export declare type BasicPerson = Omit +export interface IPartialPerson extends Partial {} + +export interface IOrganization { + id: string + legalName: string + displayName: string + cocNumber?: string + createdAt: Date + lastUpdatedAt: Date +} +export declare type BasicOrganization = Omit +export interface IPartialOrganization extends Partial {} + +export declare type ContactOwner = IPerson | IOrganization +export declare type BasicContactOwner = BasicPerson | BasicOrganization +export declare type PartialContactOwner = IPartialPerson | IPartialOrganization + +export interface IContactType { + id: string + type: ContactTypeEnum + name: string + tenantId: string + description?: string + createdAt: Date + lastUpdatedAt: Date +} +export declare type BasicContactType = Omit +export interface IPartialContactType extends Partial {} + +export interface IContactRelationship { + id: string + leftContactId: string//IContact // TODO + rightContactId: string//IContact // TODO + createdAt: Date + lastUpdatedAt: Date +} +export declare type BasicContactRelationship = Omit +export interface IPartialContactRelationship extends Partial> { + left: IPartialContact + right: IPartialContact +} diff --git a/packages/data-store/src/types/index.ts b/packages/data-store/src/types/index.ts index 6e8803c4e..e7976ab14 100644 --- a/packages/data-store/src/types/index.ts +++ b/packages/data-store/src/types/index.ts @@ -2,3 +2,4 @@ export * from './issuanceBranding/issuanceBranding' export * from './issuanceBranding/IAbstractIssuanceBrandingStore' export * from './contact/contact' export * from './contact/IAbstractContactStore' +export * from './validation/validation' diff --git a/packages/data-store/src/types/validation/validation.ts b/packages/data-store/src/types/validation/validation.ts new file mode 100644 index 000000000..e41d161f7 --- /dev/null +++ b/packages/data-store/src/types/validation/validation.ts @@ -0,0 +1,3 @@ +export type ValidationConstraint = { + [x: string]: string +} diff --git a/packages/data-store/src/utils/ValidatorUtils.ts b/packages/data-store/src/utils/ValidatorUtils.ts new file mode 100644 index 000000000..ab7bcf659 --- /dev/null +++ b/packages/data-store/src/utils/ValidatorUtils.ts @@ -0,0 +1,10 @@ +import { ValidationError } from 'class-validator' +import { ValidationConstraint } from '../types' + +export const getConstraint = (validation: ValidationError): ValidationConstraint | undefined => { + if (validation.children && validation.children.length > 0) { + return getConstraint(validation.children[0]) + } else { + return validation.constraints + } +} From 728be583e78a363e7e68c8d9b0be7a5999a2c1b0 Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Sun, 30 Jul 2023 22:26:20 +0200 Subject: [PATCH 02/35] DPP-1 WIP --- .../entities/contact/ContactRelationshipEntity.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/data-store/src/entities/contact/ContactRelationshipEntity.ts b/packages/data-store/src/entities/contact/ContactRelationshipEntity.ts index 1898a08e1..413140b4f 100644 --- a/packages/data-store/src/entities/contact/ContactRelationshipEntity.ts +++ b/packages/data-store/src/entities/contact/ContactRelationshipEntity.ts @@ -6,7 +6,9 @@ import { UpdateDateColumn, ManyToOne, // Column, - Index, BeforeInsert, BeforeUpdate, Column + Index, + BeforeInsert, + BeforeUpdate } from 'typeorm' import { ContactEntity } from './ContactEntity' import { IContactRelationship } from '../../types' @@ -25,8 +27,8 @@ export class ContactRelationshipEntity { // @JoinColumn({ name: 'left_contact_id' }) left!: ContactEntity - @Column({ name: 'left', nullable: true }) - leftContactId?: string + // @Column({ name: 'left', nullable: true }) + // leftContactId?: string @ManyToOne(() => ContactEntity, { nullable: false, @@ -35,8 +37,8 @@ export class ContactRelationshipEntity { // @JoinColumn({ name: 'right_contact_id' }) right!: ContactEntity - @Column({ name: 'right', nullable: true }) - rightContactId?: string + // @Column({ name: 'right', nullable: true }) + // rightContactId?: string @CreateDateColumn({ name: 'created_at', nullable: false }) createdAt!: Date From 203d050d48bb12709ba6fe6ae5c30b5931ccb5fb Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Tue, 1 Aug 2023 13:18:06 +0200 Subject: [PATCH 03/35] DPP-1 WIP --- .../__tests__/localAgent.test.ts | 6 +- .../__tests__/restAgent.test.ts | 14 +- .../shared/contactManagerAgentLogic.ts | 309 ++++++++++++++---- packages/contact-manager/agent.yml | 18 +- .../src/agent/ContactManager.ts | 82 ++++- .../src/types/IContactManager.ts | 75 ++++- .../src/__tests__/contact.entities.test.ts | 22 +- .../src/__tests__/contact.store.test.ts | 18 +- .../src/contact/AbstractContactStore.ts | 31 +- .../data-store/src/contact/ContactStore.ts | 197 +++++++++-- .../src/entities/contact/BaseConfigEntity.ts | 7 +- .../src/entities/contact/ConnectionEntity.ts | 2 +- .../src/entities/contact/ContactEntity.ts | 5 +- .../entities/contact/ContactOwnerEntity.ts | 61 ---- .../contact/ContactRelationshipEntity.ts | 19 +- .../entities/contact/OrganizationEntity.ts | 1 + .../src/entities/contact/PersonEntity.ts | 2 - packages/data-store/src/index.ts | 12 +- .../types/contact/IAbstractContactStore.ts | 63 +++- .../data-store/src/types/contact/contact.ts | 4 +- .../__tests__/localAgent.test.ts | 2 +- .../__tests__/restAgent.test.ts | 2 +- 22 files changed, 706 insertions(+), 246 deletions(-) diff --git a/packages/contact-manager/__tests__/localAgent.test.ts b/packages/contact-manager/__tests__/localAgent.test.ts index 640ca6d7e..87cdfd75a 100644 --- a/packages/contact-manager/__tests__/localAgent.test.ts +++ b/packages/contact-manager/__tests__/localAgent.test.ts @@ -1,11 +1,11 @@ import { createObjects, getConfig } from '../../agent-config/dist' -import { Connection } from 'typeorm' +import { DataSource } from 'typeorm' jest.setTimeout(30000) import contactManagerAgentLogic from './shared/contactManagerAgentLogic' -let dbConnection: Promise +let dbConnection: Promise let agent: any const setup = async (): Promise => { @@ -29,6 +29,6 @@ const testContext = { tearDown, } -describe('Local integration tests', () => { +describe('Local integration tests', (): void => { contactManagerAgentLogic(testContext) }) diff --git a/packages/contact-manager/__tests__/restAgent.test.ts b/packages/contact-manager/__tests__/restAgent.test.ts index f58f177a3..2e9044520 100644 --- a/packages/contact-manager/__tests__/restAgent.test.ts +++ b/packages/contact-manager/__tests__/restAgent.test.ts @@ -1,8 +1,8 @@ import 'cross-fetch/polyfill' // @ts-ignore -import express from 'express' +import express, { Router } from 'express' import { Server } from 'http' -import { Connection } from 'typeorm' +import { DataSource } from 'typeorm' import { IAgent, createAgent, IAgentOptions } from '@veramo/core' import { AgentRestClient } from '@veramo/remote-client' import { AgentRouter, RequestWithAgentRouter } from '@veramo/remote-server' @@ -17,7 +17,7 @@ const basePath = '/agent' let serverAgent: IAgent let restServer: Server -let dbConnection: Promise +let dbConnection: Promise const getAgent = (options?: IAgentOptions) => createAgent({ @@ -41,14 +41,14 @@ const setup = async (): Promise => { exposedMethods: serverAgent.availableMethods(), }) - const requestWithAgent = RequestWithAgentRouter({ + const requestWithAgent: Router = RequestWithAgentRouter({ agent: serverAgent, }) - return new Promise((resolve) => { + return new Promise((resolve): void => { const app = express() app.use(basePath, requestWithAgent, agentRouter) - restServer = app.listen(port, () => { + restServer = app.listen(port, (): void => { resolve(true) }) }) @@ -66,6 +66,6 @@ const testContext = { tearDown, } -describe('REST integration tests', () => { +describe('REST integration tests', (): void => { contactManagerAgentLogic(testContext) }) diff --git a/packages/contact-manager/__tests__/shared/contactManagerAgentLogic.ts b/packages/contact-manager/__tests__/shared/contactManagerAgentLogic.ts index 9a0a90085..cf45d0c6a 100644 --- a/packages/contact-manager/__tests__/shared/contactManagerAgentLogic.ts +++ b/packages/contact-manager/__tests__/shared/contactManagerAgentLogic.ts @@ -1,11 +1,23 @@ import { TAgent } from '@veramo/core' import { IContactManager } from '../../src' -import { CorrelationIdentifierEnum, IContact, IdentityRoleEnum, IIdentity } from '../../../data-store/src' +import { + BasicPerson, + ContactTypeEnum, + CorrelationIdentifierEnum, + IBasicContact, + IBasicIdentity, + IContact, + IdentityRoleEnum, + IIdentity, + IPerson, + IGetContactsArgs, +} from '../../../data-store/src' +import { IContactRelationship } from '../../../data-store' type ConfiguredAgent = TAgent export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Promise; tearDown: () => Promise }): void => { - describe('Contact Manager Agent Plugin', () => { + describe('Contact Manager Agent Plugin', (): void => { let agent: ConfiguredAgent let defaultContact: IContact let defaultIdentity: IIdentity @@ -14,13 +26,22 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro await testContext.setup() agent = testContext.getAgent() - const contact = { - name: 'default_contact', - alias: 'default_contact_alias', + const contact: IBasicContact = { + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'default_first_name', + middleName: 'default_middle_name', + lastName: 'default_last_name', + displayName: 'default_display_name', + }, uri: 'example.com', } const correlationId = 'default_example_did' - const identity = { + const identity: IBasicIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -34,8 +55,8 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro afterAll(testContext.tearDown) - it('should get contact by id', async () => { - const result = await agent.cmGetContact({ contactId: defaultContact.id }) + it('should get contact by id', async (): Promise => { + const result: IContact = await agent.cmGetContact({ contactId: defaultContact.id }) expect(result.id).toEqual(defaultContact.id) }) @@ -46,119 +67,152 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro await expect(agent.cmGetContact({ contactId })).rejects.toThrow(`No contact found for id: ${contactId}`) }) - it('should get all contacts', async () => { - const result = await agent.cmGetContacts() + it('should get all contacts', async (): Promise => { + const result: Array = await agent.cmGetContacts() expect(result.length).toBeGreaterThan(0) }) it('should get contacts by filter', async (): Promise => { - const args = { - filter: [{ name: 'default_contact' }, { alias: 'default_contact_alias' }, { uri: 'example.com' }], + const args: IGetContactsArgs = { + filter: [ + { + contactType: { + type: ContactTypeEnum.PERSON, + }, + }, + { + contactOwner: { + displayName: 'default_display_name', + }, + }, + { uri: 'example.com' }, + ], } - const result = await agent.cmGetContacts(args) + const result: Array = await agent.cmGetContacts(args) expect(result.length).toBe(1) }) it('should get contacts by name', async (): Promise => { - const args = { - filter: [{ name: 'default_contact' }], + const args: IGetContactsArgs = { + filter: [ + { contactOwner: { firstName: 'default_first_name' } }, + { contactOwner: { middleName: 'default_middle_name' } }, + { contactOwner: { lastName: 'default_last_name' } }, + ], } - const result = await agent.cmGetContacts(args) + const result: Array = await agent.cmGetContacts(args) expect(result.length).toBe(1) }) - it('should get contacts by alias', async (): Promise => { - const args = { - filter: [{ alias: 'default_contact_alias' }], + it('should get contacts by display name', async (): Promise => { + const args: IGetContactsArgs = { + filter: [{ contactOwner: { displayName: 'default_display_name' } }], } - const result = await agent.cmGetContacts(args) + const result: Array = await agent.cmGetContacts(args) expect(result.length).toBe(1) }) it('should get contacts by uri', async (): Promise => { - const args = { + const args: IGetContactsArgs = { filter: [{ uri: 'example.com' }], } - const result = await agent.cmGetContacts(args) + const result: Array = await agent.cmGetContacts(args) expect(result.length).toBe(1) }) it('should return no contacts if filter does not match', async (): Promise => { - const args = { - filter: [{ name: 'no_match_contact' }, { alias: 'no_match_contact_alias' }, { uri: 'no_match_example.com' }], + const args: IGetContactsArgs = { + filter: [{ contactOwner: { displayName: 'no_match_contact_display_name' } }, { uri: 'no_match_example.com' }], } - const result = await agent.cmGetContacts(args) + const result: Array = await agent.cmGetContacts(args) expect(result.length).toBe(0) }) it('should add contact', async (): Promise => { - const contact = { - name: 'new_contact', - alias: 'new_contact_alias', + const contact: IBasicContact = { + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'new_name', + description: 'new_description', + }, + contactOwner: { + firstName: 'new_first_name', + middleName: 'new_middle_name', + lastName: 'new_last_name', + displayName: 'new_display_name', + }, uri: 'example.com', } - const result = await agent.cmAddContact(contact) + const result: IContact = await agent.cmAddContact(contact) - expect(result.name).toEqual(contact.name) - expect(result.alias).toEqual(contact.alias) + expect(result.contactType.type).toEqual(contact.contactType.type) + expect(result.contactType.name).toEqual(contact.contactType.name) + expect(result.contactType.description).toEqual(contact.contactType.description) + expect((result.contactOwner).firstName).toEqual((contact.contactOwner).firstName) + expect((result.contactOwner).middleName).toEqual((contact.contactOwner).middleName) + expect((result.contactOwner).lastName).toEqual((contact.contactOwner).lastName) + expect((result.contactOwner).displayName).toEqual((contact.contactOwner).displayName) expect(result.uri).toEqual(contact.uri) }) - it('should throw error when adding contact with duplicate name', async (): Promise => { - const name = 'default_contact' - const alias = 'default_contact_new_alias' - const contact = { - name, - alias, - uri: 'example.com', - } - - await expect(agent.cmAddContact(contact)).rejects.toThrow(`Duplicate names or aliases are not allowed. Name: ${name}, Alias: ${alias}`) - }) - - it('should throw error when adding contact with duplicate alias', async (): Promise => { - const name = 'default_new_contact' - const alias = 'default_contact_alias' - const contact = { - name, - alias, + it('should throw error when adding contact with duplicate display name', async (): Promise => { + const displayName = 'default_display_name' + const contact: IBasicContact = { + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d287', + name: 'example_name2', + }, + contactOwner: { + firstName: 'default_first_name2', + middleName: 'default_middle_name2', + lastName: 'default_last_name2', + displayName, + }, uri: 'example.com', } - await expect(agent.cmAddContact(contact)).rejects.toThrow(`Duplicate names or aliases are not allowed. Name: ${name}, Alias: ${alias}`) + await expect(agent.cmAddContact(contact)).rejects.toThrow(`Duplicate names or display are not allowed. Display name: ${displayName}`) }) it('should update contact by id', async (): Promise => { - const contactName = 'updated_contact' - const contact = { + const contactFirstName = 'updated_contact_first_name' + const contact: IContact = { ...defaultContact, - name: contactName, + contactOwner: { + ...defaultContact.contactOwner, + firstName: contactFirstName, + }, } - const result = await agent.cmUpdateContact({ contact }) + const result: IContact = await agent.cmUpdateContact({ contact }) - expect(result.name).toEqual(contactName) + expect((result.contactOwner).firstName).toEqual(contactFirstName) }) it('should throw error when updating contact with unknown id', async (): Promise => { const contactId = 'unknownContactId' - const contact = { + const contact: IContact = { ...defaultContact, id: contactId, - name: 'new_name', + contactOwner: { + ...defaultContact.contactOwner, + firstName: 'new_first_name', + }, } await expect(agent.cmUpdateContact({ contact })).rejects.toThrow(`No contact found for id: ${contactId}`) }) - it('should get identity by id', async () => { - const result = await agent.cmGetIdentity({ identityId: defaultIdentity.id }) + it('should get identity by id', async (): Promise => { + const result: IIdentity = await agent.cmGetIdentity({ identityId: defaultIdentity.id }) expect(result.id).toEqual(defaultIdentity.id) }) @@ -174,14 +228,14 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro }) it('should get all identities for contact', async (): Promise => { - const result = await agent.cmGetIdentities({ filter: [{ contactId: defaultContact.id }] }) + const result: Array = await agent.cmGetIdentities({ filter: [{ contactId: defaultContact.id }] }) expect(result.length).toBeGreaterThan(0) }) it('should add identity to contact', async (): Promise => { const correlationId = 'new_example_did' - const identity = { + const identity: IBasicIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -190,8 +244,8 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro }, } - const result = await agent.cmAddIdentity({ contactId: defaultContact.id, identity }) - const contact = await agent.cmGetContact({ contactId: defaultContact.id }) + const result: IIdentity = await agent.cmAddIdentity({ contactId: defaultContact.id, identity }) + const contact: IContact = await agent.cmGetContact({ contactId: defaultContact.id }) expect(result).not.toBeNull() expect(contact.identities.length).toEqual(2) @@ -205,7 +259,7 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro it('should throw error when adding identity with invalid identifier', async (): Promise => { const correlationId = 'missing_connection_add_example' - const identity = { + const identity: IBasicIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -221,7 +275,7 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro it('should throw error when updating identity with invalid identifier', async (): Promise => { const correlationId = 'missing_connection_update_example' - const identity = { + const identity: IBasicIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -229,7 +283,7 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro correlationId, }, } - const result = await agent.cmAddIdentity({ contactId: defaultContact.id, identity }) + const result: IIdentity = await agent.cmAddIdentity({ contactId: defaultContact.id, identity }) result.identifier = { ...result.identifier, type: CorrelationIdentifierEnum.URL } await expect(agent.cmUpdateIdentity({ identity: result })).rejects.toThrow(`Identity with correlation type url should contain a connection`) @@ -237,7 +291,7 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro it('should update identity', async (): Promise => { const correlationId = 'new_update_example_did' - const identity = { + const identity: IBasicIdentity = { alias: 'update_example_did', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -245,14 +299,131 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro correlationId: 'update_example_did', }, } - const result = await agent.cmAddIdentity({ contactId: defaultContact.id, identity }) + const result: IIdentity = await agent.cmAddIdentity({ contactId: defaultContact.id, identity }) result.identifier = { ...result.identifier, correlationId } await agent.cmUpdateIdentity({ identity: result }) - const updatedIdentity = await agent.cmGetIdentity({ identityId: result.id }) + const updatedIdentity: IIdentity = await agent.cmGetIdentity({ identityId: result.id }) expect(updatedIdentity).not.toBeNull() expect(updatedIdentity.identifier.correlationId).toEqual(correlationId) }) + + it('should add relationship', async (): Promise => { + const contact: IBasicContact = { + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d287', + name: 'relation_contact_type_name', + description: 'new_description', + }, + contactOwner: { + firstName: 'relation_first_name', + middleName: 'relation_middle_name', + lastName: 'relation_last_name', + displayName: 'relation_display_name', + }, + uri: 'example.com', + } + + const savedContact: IContact = await agent.cmAddContact(contact) + + // TODO why does this filter not work on only first name? + const args1: IGetContactsArgs = { + filter: [ + { contactOwner: { firstName: 'default_first_name' } }, + { contactOwner: { middleName: 'default_middle_name' } }, + // { contactOwner: { lastName: 'default_last_name'} }, + ], + } + const otherContacts: Array = await agent.cmGetContacts(args1) + + expect(otherContacts.length).toEqual(1) + + const relationship: IContactRelationship = await agent.cmAddRelationship({ + leftContactId: savedContact.id, + rightContactId: otherContacts[0].id, + }) + + expect(relationship).toBeDefined() + + // TODO why does this filter not work on only first name? + const args2: IGetContactsArgs = { + filter: [ + { contactOwner: { firstName: 'relation_first_name' } }, + { contactOwner: { middleName: 'relation_middle_name' } }, + // { contactOwner: { lastName: 'default_last_name'} }, + ], + } + const result: Array = await agent.cmGetContacts(args2) + + expect(result.length).toEqual(1) + expect(result[0].relationships.length).toEqual(1) + expect(result[0].relationships[0].leftContactId).toEqual(savedContact.id) + expect(result[0].relationships[0].rightContactId).toEqual(otherContacts[0].id) + }) + + it('should remove relationship', async (): Promise => { + const contact: IBasicContact = { + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d286', + name: 'remove_relation_contact_type_name', + description: 'new_description', + }, + contactOwner: { + firstName: 'remove_relation_first_name', + middleName: 'remove_relation_middle_name', + lastName: 'remove_relation_last_name', + displayName: 'remove_relation_display_name', + }, + uri: 'example.com', + } + + const savedContact: IContact = await agent.cmAddContact(contact) + + // TODO why does this filter not work on only first name? + const args1: IGetContactsArgs = { + filter: [ + { contactOwner: { firstName: 'default_first_name' } }, + { contactOwner: { middleName: 'default_middle_name' } }, + // { contactOwner: { lastName: 'default_last_name'} }, + ], + } + const otherContacts: Array = await agent.cmGetContacts(args1) + + expect(otherContacts.length).toEqual(1) + + const relationship: IContactRelationship = await agent.cmAddRelationship({ + leftContactId: savedContact.id, + rightContactId: otherContacts[0].id, + }) + + expect(relationship).toBeDefined() + + // TODO why does this filter not work on only first name? + const args2: IGetContactsArgs = { + filter: [ + { contactOwner: { firstName: 'relation_first_name' } }, + { contactOwner: { middleName: 'relation_middle_name' } }, + // { contactOwner: { lastName: 'default_last_name'} }, + ], + } + const retrievedContact: Array = await agent.cmGetContacts(args2) + + expect(retrievedContact.length).toEqual(1) + expect(retrievedContact[0].relationships.length).toEqual(1) + // expect(result[0].relationships[0].leftContactId).toEqual(savedContact.id) + // expect(result[0].relationships[0].rightContactId).toEqual(otherContacts[0].id) + + const removeRelationshipResult: boolean = await agent.cmRemoveRelationship({ relationshipId: relationship.id }) + expect(removeRelationshipResult).toBeTruthy() + + const result: IContact = await agent.cmGetContact({ contactId: savedContact.id }) + + expect(result.relationships.length).toEqual(0) + }) + + // remove relation }) } diff --git a/packages/contact-manager/agent.yml b/packages/contact-manager/agent.yml index 3e22f5048..3b4a79505 100644 --- a/packages/contact-manager/agent.yml +++ b/packages/contact-manager/agent.yml @@ -14,16 +14,26 @@ constants: - cmAddIdentity - cmUpdateIdentity - cmRemoveIdentity + - cmGetRelationship + - cmGetRelationships + - cmUpdateRelationship + - cmAddRelationship + - cmRemoveRelationship + - cmGetContactType + - cmGetContactTypes + - cmAddContactType + - cmUpdateContactType + - cmRemoveContactType dbConnection: $require: typeorm?t=function#createConnection $args: - type: sqlite database: ':memory:' - synchronize: false - migrationsRun: true - migrations: - $require: './packages/data-store?t=object#DataStoreMigrations' + synchronize: true #false + migrationsRun: true #true + # migrations: + # $require: './packages/data-store?t=object#DataStoreMigrations' entities: $require: './packages/data-store?t=object#DataStoreContactEntities' diff --git a/packages/contact-manager/src/agent/ContactManager.ts b/packages/contact-manager/src/agent/ContactManager.ts index 47abb9350..6f3211fe1 100644 --- a/packages/contact-manager/src/agent/ContactManager.ts +++ b/packages/contact-manager/src/agent/ContactManager.ts @@ -13,8 +13,24 @@ import { IUpdateIdentityArgs, IGetContactsArgs, IGetContactArgs, + IAddRelationshipArgs, + IRemoveRelationshipArgs, + IGetRelationshipArgs, + IGetRelationshipsArgs, + IUpdateRelationshipArgs, + IAddContactTypeArgs, + IGetContactTypeArgs, + IGetContactTypesArgs, + IRemoveContactTypeArgs, + IUpdateContactTypeArgs, } from '../types/IContactManager' -import { IContact, IIdentity, AbstractContactStore } from '@sphereon/ssi-sdk.data-store' +import { + IContact, + IIdentity, + AbstractContactStore, + IContactRelationship, + IContactType +} from '@sphereon/ssi-sdk.data-store' /** * {@inheritDoc IContactManager} @@ -32,6 +48,16 @@ export class ContactManager implements IAgentPlugin { cmAddIdentity: this.cmAddIdentity.bind(this), cmUpdateIdentity: this.cmUpdateIdentity.bind(this), cmRemoveIdentity: this.cmRemoveIdentity.bind(this), + cmAddRelationship: this.cmAddRelationship.bind(this), + cmRemoveRelationship: this.cmRemoveRelationship.bind(this), + cmGetRelationship: this.cmGetRelationship.bind(this), + cmGetRelationships: this.cmGetRelationships.bind(this), + cmUpdateRelationship: this.cmUpdateRelationship.bind(this), + cmGetContactType: this.cmGetContactType.bind(this), + cmGetContactTypes: this.cmGetContactTypes.bind(this), + cmAddContactType: this.cmAddContactType.bind(this), + cmUpdateContactType: this.cmUpdateContactType.bind(this), + cmRemoveContactType: this.cmRemoveContactType.bind(this) } private readonly store: AbstractContactStore @@ -71,7 +97,7 @@ export class ContactManager implements IAgentPlugin { } /** {@inheritDoc IContactManager.cmGetIdentities} */ - private async cmGetIdentities(args: IGetIdentitiesArgs, context: IRequiredContext): Promise> { + private async cmGetIdentities(args?: IGetIdentitiesArgs): Promise> { return this.store.getIdentities(args) } @@ -87,6 +113,56 @@ export class ContactManager implements IAgentPlugin { /** {@inheritDoc IContactManager.cmRemoveIdentity} */ private async cmRemoveIdentity(args: IRemoveIdentityArgs, context: IRequiredContext): Promise { - return this.store.removeIdentity(args).then(() => true) // TODO + return this.store.removeIdentity(args).then(() => true) + } + + /** {@inheritDoc IContactManager.cmAddRelationship} */ + private async cmAddRelationship(args: IAddRelationshipArgs, context: IRequiredContext): Promise { + return this.store.addRelationship(args) + } + + /** {@inheritDoc IContactManager.cmRemoveRelationship} */ + private async cmRemoveRelationship(args: IRemoveRelationshipArgs, context: IRequiredContext): Promise { + return this.store.removeRelationship(args).then(() => true) + } + + /** {@inheritDoc IContactManager.cmGetRelationship} */ + private async cmGetRelationship(args: IGetRelationshipArgs, context: IRequiredContext): Promise { + return this.store.getRelationship(args) + } + + /** {@inheritDoc IContactManager.cmGetRelationships} */ + private async cmGetRelationships(args?: IGetRelationshipsArgs): Promise> { + return this.store.getRelationships(args) + } + + /** {@inheritDoc IContactManager.cmUpdateRelationship} */ + private async cmUpdateRelationship(args: IUpdateRelationshipArgs, context: IRequiredContext): Promise { + return this.store.updateRelationship(args) + } + + /** {@inheritDoc IContactManager.cmGetContactType} */ + private async cmGetContactType(args: IGetContactTypeArgs, context: IRequiredContext): Promise { + return this.store.getContactType(args) + } + + /** {@inheritDoc IContactManager.cmGetContactTypes} */ + private async cmGetContactTypes(args?: IGetContactTypesArgs): Promise> { + return this.store.getContactTypes(args) + } + + /** {@inheritDoc IContactManager.cmAddContactType} */ + private async cmAddContactType(args: IAddContactTypeArgs, context: IRequiredContext): Promise { + return this.store.addContactType(args) + } + + /** {@inheritDoc IContactManager.cmUpdateContactType} */ + private async cmUpdateContactType(args: IUpdateContactTypeArgs, context: IRequiredContext): Promise { + return this.store.updateContactType(args) + } + + /** {@inheritDoc IContactManager.cmRemoveContactType} */ + private async cmRemoveContactType(args: IRemoveContactTypeArgs, context: IRequiredContext): Promise { + return this.store.removeContactType(args).then(() => true) } } diff --git a/packages/contact-manager/src/types/IContactManager.ts b/packages/contact-manager/src/types/IContactManager.ts index 3a1c1bd3a..0751b3704 100644 --- a/packages/contact-manager/src/types/IContactManager.ts +++ b/packages/contact-manager/src/types/IContactManager.ts @@ -1,5 +1,18 @@ import { IAgentContext, IPluginMethodMap } from '@veramo/core' -import { FindContactArgs, FindIdentityArgs, IBasicIdentity, IContact, IIdentity } from '@sphereon/ssi-sdk.data-store' +import { + BasicContactOwner, + BasicContactType, + FindContactArgs, + FindIdentityArgs, + IBasicIdentity, + IContact, + IContactRelationship, + IIdentity, + FindRelationshipArgs, + ContactTypeEnum, + FindContactTypeArgs, + IContactType +} from '@sphereon/ssi-sdk.data-store' export interface IContactManager extends IPluginMethodMap { cmGetContact(args: IGetContactArgs, context: IRequiredContext): Promise @@ -8,10 +21,20 @@ export interface IContactManager extends IPluginMethodMap { cmUpdateContact(args: IUpdateContactArgs, context: IRequiredContext): Promise cmRemoveContact(args: IRemoveContactArgs, context: IRequiredContext): Promise cmGetIdentity(args: IGetIdentityArgs, context: IRequiredContext): Promise - cmGetIdentities(args: IGetIdentitiesArgs, context: IRequiredContext): Promise> + cmGetIdentities(args?: IGetIdentitiesArgs): Promise> cmAddIdentity(args: IAddIdentityArgs, context: IRequiredContext): Promise cmUpdateIdentity(args: IUpdateIdentityArgs, context: IRequiredContext): Promise cmRemoveIdentity(args: IRemoveIdentityArgs, context: IRequiredContext): Promise + cmGetRelationship(args: IGetRelationshipArgs, context: IRequiredContext): Promise + cmGetRelationships(args?: IGetRelationshipsArgs): Promise> + cmUpdateRelationship(args: IUpdateRelationshipArgs, context: IRequiredContext): Promise + cmAddRelationship(args: IAddRelationshipArgs, context: IRequiredContext): Promise + cmRemoveRelationship(args: IRemoveRelationshipArgs, context: IRequiredContext): Promise + cmGetContactType(args: IGetContactTypeArgs, context: IRequiredContext): Promise + cmGetContactTypes(args?: IGetContactTypesArgs): Promise> + cmAddContactType(args: IAddContactTypeArgs, context: IRequiredContext): Promise + cmUpdateContactType(args: IUpdateContactTypeArgs, context: IRequiredContext): Promise + cmRemoveContactType(args: IRemoveContactTypeArgs, context: IRequiredContext): Promise } export interface IGetContactArgs { @@ -23,9 +46,9 @@ export interface IGetContactsArgs { } export interface IAddContactArgs { - name: string - alias: string uri?: string + contactType: BasicContactType // TODO we can have a situation where we want to add a contact to an existing type, so use BasicContactType | IContactType? also make a test for these 2 situations in the store + contactOwner: BasicContactOwner identities?: Array } @@ -58,4 +81,48 @@ export interface IRemoveIdentityArgs { identityId: string } +export interface IAddRelationshipArgs { + leftContactId: string + rightContactId: string +} + +export interface IRemoveRelationshipArgs { + relationshipId: string +} + +export interface IGetRelationshipArgs { + relationshipId: string +} + +export interface IGetRelationshipsArgs { + filter: FindRelationshipArgs +} + +export interface IUpdateRelationshipArgs { + relationship: IContactRelationship // TODO do we also want the omits here? +} + +export interface IAddContactTypeArgs { + type: ContactTypeEnum + name: string + tenantId: string + description?: string +} + +export interface IGetContactTypeArgs { + contactTypeId: string +} + +export interface IGetContactTypesArgs { + filter?: FindContactTypeArgs +} + +export interface IUpdateContactTypeArgs { + contactType: Omit // TODO do we also want the omits here? +} + +export interface IRemoveContactTypeArgs { + contactTypeId: string +} + export type IRequiredContext = IAgentContext diff --git a/packages/data-store/src/__tests__/contact.entities.test.ts b/packages/data-store/src/__tests__/contact.entities.test.ts index 78604a4eb..6cd262c59 100644 --- a/packages/data-store/src/__tests__/contact.entities.test.ts +++ b/packages/data-store/src/__tests__/contact.entities.test.ts @@ -127,7 +127,7 @@ describe('Database entities tests', (): void => { expect((fromDb?.contactOwner).cocNumber).toEqual((contact.contactOwner).cocNumber) }) - it('Should result in contact relation for the owner side only', async (): Promise => { + it('Should result in contact relationship for the owner side only', async (): Promise => { const contact1: IBasicContact = { uri: 'example1.com', contactType: { @@ -399,8 +399,6 @@ describe('Database entities tests', (): void => { await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrow("Blank tenant id's are not allowed") }) - // TODO should wew enforce unique combinations of first/middle/last names - // Example, hans kraai, we have a jr and sr it('Should enforce unique display name for a person contact', async (): Promise => { const contactDisplayName = 'non_unique_name' const contact1: IBasicContact = { @@ -1571,7 +1569,7 @@ describe('Database entities tests', (): void => { const organization1: BasicOrganization = { legalName, displayName: 'example_display_name1', - cocNumber: '1234567890' + cocNumber: '1234567890', } const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) @@ -1584,7 +1582,7 @@ describe('Database entities tests', (): void => { const organization2: BasicOrganization = { legalName, displayName: 'example_display_name2', - cocNumber: '1234567890' + cocNumber: '1234567890', } const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) @@ -1620,7 +1618,7 @@ describe('Database entities tests', (): void => { ) }) - it('Should save contact relation to database', async (): Promise => { + it('Should save contact relationship to database', async (): Promise => { const contact1: IBasicContact = { uri: 'example1.com', contactType: { @@ -1682,7 +1680,7 @@ describe('Database entities tests', (): void => { expect(fromDb).toBeDefined() }) - it('Should set last updated date when saving contact relation', async (): Promise => { + it('Should set last updated date when saving contact relationship', async (): Promise => { const contact1: IBasicContact = { uri: 'example1.com', contactType: { @@ -1740,7 +1738,7 @@ describe('Database entities tests', (): void => { expect(fromDb?.lastUpdatedAt).toBeDefined() }) - it('Should set creation date when saving contact relation', async (): Promise => { + it('Should set creation date when saving contact relationship', async (): Promise => { const contact1: IBasicContact = { uri: 'example1.com', contactType: { @@ -1798,7 +1796,7 @@ describe('Database entities tests', (): void => { expect(fromDb?.createdAt).toBeDefined() }) - it('Should save bidirectional contact relations to database', async (): Promise => { + it('Should save bidirectional contact relationships to database', async (): Promise => { const contact1: IBasicContact = { uri: 'example1.com', contactType: { @@ -1872,7 +1870,7 @@ describe('Database entities tests', (): void => { expect(fromDb).toBeDefined() }) - it('Should enforce unique owner combination for contact relation', async (): Promise => { + it('Should enforce unique owner combination for contact relationship', async (): Promise => { const contact1: IBasicContact = { uri: 'example1.com', contactType: { @@ -2135,7 +2133,7 @@ describe('Database entities tests', (): void => { expect(fromDb).toBeDefined() }) - it('Should enforce unique contact id\'s for relationship sides', async (): Promise => { + it("Should enforce unique contact id's for relationship sides", async (): Promise => { const contact: IBasicContact = { uri: 'example.com', contactType: { @@ -2168,7 +2166,7 @@ describe('Database entities tests', (): void => { ) }) - it('Should delete contact relation', async (): Promise => { + it('Should delete contact relationship', async (): Promise => { const contact1: IBasicContact = { uri: 'example1.com', contactType: { diff --git a/packages/data-store/src/__tests__/contact.store.test.ts b/packages/data-store/src/__tests__/contact.store.test.ts index 833a27e5f..8e68e37b2 100644 --- a/packages/data-store/src/__tests__/contact.store.test.ts +++ b/packages/data-store/src/__tests__/contact.store.test.ts @@ -1,6 +1,6 @@ import { DataSource } from 'typeorm' -import { BasicContactRelationship, DataStoreContactEntities, IContactRelationship } from '../index' +import { DataStoreContactEntities } from '../index' import { ContactStore } from '../contact/ContactStore' import { IdentityRoleEnum, @@ -14,6 +14,8 @@ import { IBasicIdentity, IGetIdentitiesArgs, IGetContactsArgs, + BasicContactRelationship, + IContactRelationship } from '../types' describe('Contact store tests', (): void => { @@ -1118,7 +1120,7 @@ describe('Contact store tests', (): void => { const relationship: BasicContactRelationship = { leftContactId: savedContact1.id, - rightContactId: savedContact2.id + rightContactId: savedContact2.id, } await contactStore.addRelationship(relationship) @@ -1167,7 +1169,7 @@ describe('Contact store tests', (): void => { const relationship: BasicContactRelationship = { leftContactId: savedContact1.id, - rightContactId: savedContact2.id + rightContactId: savedContact2.id, } const savedRelationship: IContactRelationship = await contactStore.addRelationship(relationship) expect(savedRelationship).toBeDefined() @@ -1179,4 +1181,14 @@ describe('Contact store tests', (): void => { expect(result).toBeDefined() expect(result?.relationships?.length).toEqual(0) }) + + it('should throw error when removing relationship with unknown id', async (): Promise => { + const relationshipId = 'unknownRelationshipId' + + await expect(contactStore.removeRelationship({ relationshipId })).rejects.toThrow(`No relationship found for id: ${relationshipId}`) + }) + + // TODO cannot delete contact type when used by contact }) + +// maybe add some categories for the tests to find them diff --git a/packages/data-store/src/contact/AbstractContactStore.ts b/packages/data-store/src/contact/AbstractContactStore.ts index a02ebf4d1..c776617e4 100644 --- a/packages/data-store/src/contact/AbstractContactStore.ts +++ b/packages/data-store/src/contact/AbstractContactStore.ts @@ -11,19 +11,42 @@ import { IGetContactsArgs, IRemoveContactArgs, IUpdateContactArgs, + IAddRelationshipArgs, + IContactRelationship, + IRemoveRelationshipArgs, + IAddContactTypeArgs, + IContactType, + IGetContactTypeArgs, + IUpdateContactTypeArgs, + IGetContactTypesArgs, + IRemoveContactTypeArgs, + IGetRelationshipsArgs, + IGetRelationshipArgs, + IUpdateRelationshipArgs, } from '../types' export abstract class AbstractContactStore { abstract getContact(args: IGetContactArgs): Promise - abstract getContacts(args?: IGetContactsArgs): Promise> // TODO support person and organizations + abstract getContacts(args?: IGetContactsArgs): Promise> abstract addContact(args: IAddContactArgs): Promise - abstract updateContact(args: IUpdateContactArgs): Promise // TODO support person and organizations + abstract updateContact(args: IUpdateContactArgs): Promise abstract removeContact(args: IRemoveContactArgs): Promise + abstract getIdentity(args: IGetIdentityArgs): Promise - abstract getIdentities(args: IGetIdentitiesArgs): Promise> + abstract getIdentities(args?: IGetIdentitiesArgs): Promise> abstract addIdentity(args: IAddIdentityArgs): Promise abstract updateIdentity(args: IUpdateIdentityArgs): Promise abstract removeIdentity(args: IRemoveIdentityArgs): Promise - // TODO support creating relations + abstract getRelationship(args: IGetRelationshipArgs): Promise + abstract getRelationships(args?: IGetRelationshipsArgs): Promise> + abstract addRelationship(args: IAddRelationshipArgs): Promise + abstract updateRelationship(args: IUpdateRelationshipArgs): Promise + abstract removeRelationship(args: IRemoveRelationshipArgs): Promise + + abstract getContactType(args: IGetContactTypeArgs): Promise + abstract getContactTypes(args?: IGetContactTypesArgs): Promise> + abstract addContactType(args: IAddContactTypeArgs): Promise + abstract updateContactType(args: IUpdateContactTypeArgs): Promise + abstract removeContactType(args: IRemoveContactTypeArgs): Promise } diff --git a/packages/data-store/src/contact/ContactStore.ts b/packages/data-store/src/contact/ContactStore.ts index e6de04761..065221365 100644 --- a/packages/data-store/src/contact/ContactStore.ts +++ b/packages/data-store/src/contact/ContactStore.ts @@ -19,26 +19,28 @@ import { IIdentity, IRemoveRelationshipArgs, IContactRelationship, - IAddRelationshipArgs + IAddRelationshipArgs, + IGetRelationshipArgs, + IAddContactTypeArgs, + IContactType, + IGetContactTypeArgs, + IGetContactTypesArgs, + IUpdateContactTypeArgs, + IRemoveContactTypeArgs, + IGetRelationshipsArgs, + IUpdateRelationshipArgs, } from '../types' import { ContactEntity, contactEntityFrom, contactFrom } from '../entities/contact/ContactEntity' import { IdentityEntity, identityEntityFrom, identityFrom } from '../entities/contact/IdentityEntity' import { IdentityMetadataItemEntity } from '../entities/contact/IdentityMetadataItemEntity' import { CorrelationIdentifierEntity } from '../entities/contact/CorrelationIdentifierEntity' import { ConnectionEntity } from '../entities/contact/ConnectionEntity' -import { - BaseConfigEntity, - isDidAuthConfig, - isOpenIdConfig -} from '../entities/contact/BaseConfigEntity' +import { BaseConfigEntity, isDidAuthConfig, isOpenIdConfig } from '../entities/contact/BaseConfigEntity' import { DataSource, FindOptionsWhere, In, Repository } from 'typeorm' import { PersonEntity } from '../entities/contact/PersonEntity' import { OrganizationEntity } from '../entities/contact/OrganizationEntity' -import { - ContactRelationshipEntity, - contactRelationshipEntityFrom, - contactRelationshipFrom -} from '../entities/contact/ContactRelationshipEntity' +import { ContactRelationshipEntity, contactRelationshipEntityFrom, contactRelationshipFrom } from '../entities/contact/ContactRelationshipEntity' +import { ContactTypeEntity, contactTypeEntityFrom, contactTypeFrom } from '../entities/contact/ContactTypeEntity' const debug: Debug.Debugger = Debug('sphereon:ssi-sdk:contact-store') @@ -78,11 +80,10 @@ export class ContactStore extends AbstractContactStore { } addContact = async (args: IAddContactArgs): Promise => { - const { identities, contactOwner } = args //, alias, name, + const { identities, contactOwner } = args const contactRepository: Repository = (await this.dbConnection).getRepository(ContactEntity) - // TODO extend with more names? const result: ContactEntity | null = await contactRepository.findOne({ where: [ { @@ -95,7 +96,7 @@ export class ContactStore extends AbstractContactStore { if (result) { // TODO correct msg? - return Promise.reject(Error(`Duplicate names or display are not allowed. Display name: ${contactOwner.displayName}`)) //Name: ${name}, + return Promise.reject(Error(`Duplicate names or display are not allowed. Display name: ${contactOwner.displayName}`)) } for (const identity of identities ?? []) { @@ -111,7 +112,7 @@ export class ContactStore extends AbstractContactStore { } const contactEntity: ContactEntity = contactEntityFrom(args) - //debug('Adding contact', name) TODO fix + debug('Adding contact', args) const createdResult: ContactEntity = await contactRepository.save(contactEntity) return contactFrom(createdResult) @@ -143,7 +144,7 @@ export class ContactStore extends AbstractContactStore { removeContact = async ({ contactId }: IRemoveContactArgs): Promise => { const contactRepository: Repository = (await this.dbConnection).getRepository(ContactEntity) debug('Removing contact', contactId) - ;contactRepository + contactRepository .findOneById(contactId) .then(async (contact: ContactEntity | null): Promise => { if (!contact) { @@ -256,10 +257,6 @@ export class ContactStore extends AbstractContactStore { } addRelationship = async ({ leftContactId, rightContactId }: IAddRelationshipArgs): Promise => { - // if (leftContactId === rightContactId) { - // return Promise.reject(Error(`Cannot use the same id for both sides of the relationship`)) - // } - const contactRepository: Repository = (await this.dbConnection).getRepository(ContactEntity) const leftContact: ContactEntity | null = await contactRepository.findOne({ where: { id: leftContactId }, @@ -287,8 +284,57 @@ export class ContactStore extends AbstractContactStore { return contactRelationshipFrom(createdResult) } - // TODO get relationship? - // TODO get relationships? + getRelationship = async ({ relationshipId }: IGetRelationshipArgs): Promise => { + const result: ContactRelationshipEntity | null = await (await this.dbConnection).getRepository(ContactRelationshipEntity).findOne({ + where: { id: relationshipId }, + }) + + if (!result) { + return Promise.reject(Error(`No relationship found for id: ${relationshipId}`)) + } + + return contactRelationshipFrom(result) + } + + // TODO get relationships + getRelationships = async (args?: IGetRelationshipsArgs): Promise> => { + const contactRelationshipRepository: Repository = (await this.dbConnection).getRepository(ContactRelationshipEntity) + const initialResult: Array | null = await contactRelationshipRepository.find({ + ...(args?.filter && { where: args?.filter }), + }) + + const result: Array | null = await contactRelationshipRepository.find({ + where: { + id: In(initialResult.map((contactRelationship: ContactRelationshipEntity) => contactRelationship.id)), + }, + }) + + return result.map((contactRelationship: ContactRelationshipEntity) => contactRelationshipFrom(contactRelationship)) + } + + // TODO update relationship + updateRelationship = async ({ relationship }: IUpdateRelationshipArgs): Promise => { + const contactRelationshipRepository: Repository = (await this.dbConnection).getRepository(ContactRelationshipEntity) + const result: ContactRelationshipEntity | null = await contactRelationshipRepository.findOne({ + where: { id: relationship.id }, + }) + + if (!result) { + return Promise.reject(Error(`No contact relationship found for id: ${relationship.id}`)) + } + + // const updatedContactType = { + // // TODO fix type + // ...contactType, + // identities: result.identities, + // relationships: result.relationships, + // } + + debug('Updating contact relationship', relationship) + const updatedResult: ContactRelationshipEntity = await contactRelationshipRepository.save(relationship, { transaction: true }) + + return contactRelationshipFrom(updatedResult) + } removeRelationship = async ({ relationshipId }: IRemoveRelationshipArgs): Promise => { const contactRelationshipRepository: Repository = (await this.dbConnection).getRepository(ContactRelationshipEntity) @@ -305,7 +351,87 @@ export class ContactStore extends AbstractContactStore { await contactRelationshipRepository.delete(relationshipId) } - // TODO functions for adding/removing contact types? + // TODO add contact type + addContactType = async (args: IAddContactTypeArgs): Promise => { + // TODO do we need checks? + + const contactEntity: ContactTypeEntity = contactTypeEntityFrom(args) + debug('Adding contact type', args) + const createdResult: ContactTypeEntity = await (await this.dbConnection).getRepository(ContactTypeEntity).save(contactEntity) + + return contactTypeFrom(createdResult) + } + + // TODO get contact type + getContactType = async ({ contactTypeId }: IGetContactTypeArgs): Promise => { + const result: ContactTypeEntity | null = await (await this.dbConnection).getRepository(ContactTypeEntity).findOne({ + where: { id: contactTypeId }, + }) + + if (!result) { + return Promise.reject(Error(`No contact type found for id: ${contactTypeId}`)) + } + + return contactTypeFrom(result) + } + + // TODO get contact types + getContactTypes = async (args?: IGetContactTypesArgs): Promise> => { + const contactTypeRepository: Repository = (await this.dbConnection).getRepository(ContactTypeEntity) + const initialResult: Array | null = await contactTypeRepository.find({ + ...(args?.filter && { where: args?.filter }), + }) + + const result: Array | null = await contactTypeRepository.find({ + where: { + id: In(initialResult.map((contactType: ContactTypeEntity) => contactType.id)), + }, + }) + + return result.map((contactType: ContactTypeEntity) => contactTypeFrom(contactType)) + } + + // TODO update contact type + updateContactType = async ({ contactType }: IUpdateContactTypeArgs): Promise => { + const contactTypeRepository: Repository = (await this.dbConnection).getRepository(ContactTypeEntity) + const result: ContactTypeEntity | null = await contactTypeRepository.findOne({ + where: { id: contactType.id }, + }) + + if (!result) { + return Promise.reject(Error(`No contact type found for id: ${contactType.id}`)) + } + + // const updatedContactType = { + // // TODO fix type + // ...contactType, + // identities: result.identities, + // relationships: result.relationships, + // } + + debug('Updating contact type', contactType) + const updatedResult: ContactTypeEntity = await contactTypeRepository.save(contactType, { transaction: true }) + + return contactTypeFrom(updatedResult) + } + + // TODO remove contact type + removeContactType = async ({ contactTypeId }: IRemoveContactTypeArgs): Promise => { + // TODO maybe add check if contact type is used, if used, cannot delete + + const contactTypeRepository: Repository = (await this.dbConnection).getRepository(ContactTypeEntity) + const contactType: ContactTypeEntity | null = await contactTypeRepository.findOne({ + where: { id: contactTypeId }, + }) + + if (!contactType) { + return Promise.reject(Error(`No contact type found for id: ${contactTypeId}`)) + } + + debug('Removing contact type', contactTypeId) + + await contactTypeRepository.delete(contactTypeId) + } private hasCorrectConfig(type: ConnectionTypeEnum, config: BasicConnectionConfig): boolean { switch (type) { @@ -325,9 +451,9 @@ export class ContactStore extends AbstractContactStore { await ( await this.dbConnection ) - .getRepository(CorrelationIdentifierEntity) - .delete(identity.identifier.id) - .catch((error) => Promise.reject(Error(`Unable to remove identity.identifier with id: ${identity.identifier.id}. ${error}`))) + .getRepository(CorrelationIdentifierEntity) + .delete(identity.identifier.id) + .catch((error) => Promise.reject(Error(`Unable to remove identity.identifier with id: ${identity.identifier.id}. ${error}`))) if (identity.connection) { await (await this.dbConnection).getRepository(BaseConfigEntity).delete(identity.connection.config.id) @@ -335,9 +461,9 @@ export class ContactStore extends AbstractContactStore { await ( await this.dbConnection ) - .getRepository(ConnectionEntity) - .delete(identity.connection.id) - .catch((error) => Promise.reject(Error(`Unable to remove identity.connection with id. ${error}`))) + .getRepository(ConnectionEntity) + .delete(identity.connection.id) + .catch((error) => Promise.reject(Error(`Unable to remove identity.connection with id. ${error}`))) } if (identity.metadata) { @@ -345,17 +471,16 @@ export class ContactStore extends AbstractContactStore { await ( await this.dbConnection ) - .getRepository(IdentityMetadataItemEntity) - .delete(metadataItem.id) - .catch((error) => Promise.reject(Error(`Unable to remove metadataItem.id with id ${metadataItem.id}. ${error}`))) + .getRepository(IdentityMetadataItemEntity) + .delete(metadataItem.id) + .catch((error) => Promise.reject(Error(`Unable to remove metadataItem.id with id ${metadataItem.id}. ${error}`))) }) } ;(await this.dbConnection) - .getRepository(IdentityEntity) - .delete(identity.id) - .catch((error) => Promise.reject(Error(`Unable to remove metadataItem.id with id ${identity.id}. ${error}`))) + .getRepository(IdentityEntity) + .delete(identity.id) + .catch((error) => Promise.reject(Error(`Unable to remove metadataItem.id with id ${identity.id}. ${error}`))) }) } - } diff --git a/packages/data-store/src/entities/contact/BaseConfigEntity.ts b/packages/data-store/src/entities/contact/BaseConfigEntity.ts index 0565175c3..b3d7ffd10 100644 --- a/packages/data-store/src/entities/contact/BaseConfigEntity.ts +++ b/packages/data-store/src/entities/contact/BaseConfigEntity.ts @@ -1,10 +1,5 @@ import { BaseEntity, Entity, PrimaryGeneratedColumn, TableInheritance } from 'typeorm' -import { - BasicConnectionConfig, - ConnectionConfig, - IDidAuthConfig, - IOpenIdConfig -} from '../../types' +import { BasicConnectionConfig, ConnectionConfig, IDidAuthConfig, IOpenIdConfig } from '../../types' import { OpenIdConfigEntity } from './OpenIdConfigEntity' import { DidAuthConfigEntity } from './DidAuthConfigEntity' diff --git a/packages/data-store/src/entities/contact/ConnectionEntity.ts b/packages/data-store/src/entities/contact/ConnectionEntity.ts index 1d75c7756..33dc5644b 100644 --- a/packages/data-store/src/entities/contact/ConnectionEntity.ts +++ b/packages/data-store/src/entities/contact/ConnectionEntity.ts @@ -46,7 +46,7 @@ export const connectionFrom = (connection: ConnectionEntity): IConnection => { // TODO move to base config? const configEntityFrom = (config: BasicConnectionConfig): BaseConfigEntity => { - if (isOpenIdConfig((config))) { + if (isOpenIdConfig(config)) { return openIdConfigEntityFrom(config) } else if (isDidAuthConfig(config)) { return didAuthConfigEntityFrom(config) diff --git a/packages/data-store/src/entities/contact/ContactEntity.ts b/packages/data-store/src/entities/contact/ContactEntity.ts index e8f36f949..dd2b27492 100644 --- a/packages/data-store/src/entities/contact/ContactEntity.ts +++ b/packages/data-store/src/entities/contact/ContactEntity.ts @@ -113,13 +113,14 @@ export const contactEntityFrom = (contact: IBasicContact): ContactEntity => { } export const contactFrom = (contact: ContactEntity): IContact => { - console.log('') return { id: contact.id, uri: contact.uri, roles: [...new Set(contact.identities?.flatMap((identity: IdentityEntity) => identity.roles))] ?? [], identities: contact.identities ? contact.identities.map((identity: IdentityEntity) => identityFrom(identity)) : [], - relationships: contact.relationships ? contact.relationships.map((relationship: ContactRelationshipEntity) => contactRelationshipFrom(relationship)) : [], + relationships: contact.relationships + ? contact.relationships.map((relationship: ContactRelationshipEntity) => contactRelationshipFrom(relationship)) + : [], contactType: contactTypeFrom(contact.contactType), contactOwner: contactOwnerFrom(contact.contactOwner), createdAt: contact.createdAt, diff --git a/packages/data-store/src/entities/contact/ContactOwnerEntity.ts b/packages/data-store/src/entities/contact/ContactOwnerEntity.ts index 2b0f38825..00a4bc476 100644 --- a/packages/data-store/src/entities/contact/ContactOwnerEntity.ts +++ b/packages/data-store/src/entities/contact/ContactOwnerEntity.ts @@ -1,15 +1,5 @@ import { BaseEntity, CreateDateColumn, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn, TableInheritance, UpdateDateColumn } from 'typeorm' import { ContactEntity } from './ContactEntity' -// import { IPerson } from '../../types' -// import { PersonEntity } from './PersonEntity' -// import { -// // BasicContactOwner, -// // BasicOrganization, -// // BasicPerson, -// // ContactOwner -// } from '../../types' -// import { organizationEntityFrom, organizationFrom } from './OrganizationEntity' -// import { personEntityFrom, personFrom } from './PersonEntity' @Entity('ContactOwner') @TableInheritance({ column: { type: 'varchar', name: 'type' } }) @@ -29,54 +19,3 @@ export abstract class ContactOwnerEntity extends BaseEntity { @JoinColumn({ name: 'contactId' }) contact!: ContactEntity } - -// export const contactOwnerEntityFrom = (owner: BasicContactOwner): ContactOwnerEntity => { -// if (isPerson(owner)) { -// return personEntityFrom(owner) -// } else if (isOrganization(owner)) { -// return organizationEntityFrom(owner) -// } -// -// throw new Error('Owner type not supported') -// -// -// // switch (type) { -// // case ContactTypeEnum.PERSON: -// // return personEntityFrom(owner) -// // case ContactTypeEnum.ORGANIZATION: -// // return organizationEntityFrom(owner) -// // default: -// // throw new Error('Contact type not supported') -// // } -// } - -// export const contactOwnerFrom = (owner: ContactOwnerEntity): ContactOwner => { -// if (isPerson(owner)) { -// // @ts-ignore -// return personFrom(owner) -// } else if (isOrganization(owner)) { -// // @ts-ignore -// return organizationFrom(owner) -// } -// -// throw new Error('Owner type not supported') -// } -// -// // TODO move? -// const isPerson = (owner: BasicContactOwner | ContactOwnerEntity): owner is BasicPerson => -// 'firstName' in owner && 'middleName' in owner && 'lastName' in owner -// -// const isOrganization = (owner: BasicContactOwner | ContactOwnerEntity): owner is BasicOrganization => -// 'legalName' in owner && 'cocNumber' in owner - -// export const personFrom = (person: PersonEntity): IPerson => { -// return { -// id: person.id, -// firstName: person.firstName, -// middleName: person.middleName, -// lastName: person.lastName, -// displayName: person.displayName, -// createdAt: person.createdAt, -// lastUpdatedAt: person.lastUpdatedAt, -// } -// } diff --git a/packages/data-store/src/entities/contact/ContactRelationshipEntity.ts b/packages/data-store/src/entities/contact/ContactRelationshipEntity.ts index 413140b4f..d25808568 100644 --- a/packages/data-store/src/entities/contact/ContactRelationshipEntity.ts +++ b/packages/data-store/src/entities/contact/ContactRelationshipEntity.ts @@ -5,10 +5,10 @@ import { CreateDateColumn, UpdateDateColumn, ManyToOne, - // Column, + Column, Index, BeforeInsert, - BeforeUpdate + BeforeUpdate, } from 'typeorm' import { ContactEntity } from './ContactEntity' import { IContactRelationship } from '../../types' @@ -27,8 +27,8 @@ export class ContactRelationshipEntity { // @JoinColumn({ name: 'left_contact_id' }) left!: ContactEntity - // @Column({ name: 'left', nullable: true }) - // leftContactId?: string + @Column({ name: 'leftId', nullable: false }) + leftId!: string @ManyToOne(() => ContactEntity, { nullable: false, @@ -37,8 +37,8 @@ export class ContactRelationshipEntity { // @JoinColumn({ name: 'right_contact_id' }) right!: ContactEntity - // @Column({ name: 'right', nullable: true }) - // rightContactId?: string + @Column({ name: 'rightId', nullable: false }) + rightId!: string @CreateDateColumn({ name: 'created_at', nullable: false }) createdAt!: Date @@ -66,13 +66,12 @@ export const contactRelationshipEntityFrom = (relationship: { left: ContactEntit } export const contactRelationshipFrom = (relationship: ContactRelationshipEntity): IContactRelationship => { - console.log('') return { id: relationship.id, - leftContactId: relationship.left.id, - rightContactId: relationship.right.id, + leftContactId: relationship.leftId, //relationship.left.id, + rightContactId: relationship.rightId, //relationship.right.id, createdAt: relationship.createdAt, - lastUpdatedAt: relationship.lastUpdatedAt + lastUpdatedAt: relationship.lastUpdatedAt, } // TODO convert IContact to ContactEntity here } diff --git a/packages/data-store/src/entities/contact/OrganizationEntity.ts b/packages/data-store/src/entities/contact/OrganizationEntity.ts index a7516982d..939680d46 100644 --- a/packages/data-store/src/entities/contact/OrganizationEntity.ts +++ b/packages/data-store/src/entities/contact/OrganizationEntity.ts @@ -16,6 +16,7 @@ export class OrganizationEntity extends ContactOwnerEntity { @IsNotEmpty({ message: 'Blank display names are not allowed' }) displayName!: string + // TODO uniek per tenant @Column({ name: 'cocNumber', length: 255, nullable: true, unique: true }) @Validate(IsNonEmptyStringConstraint, { message: 'Blank coc numbers are not allowed' }) cocNumber?: string diff --git a/packages/data-store/src/entities/contact/PersonEntity.ts b/packages/data-store/src/entities/contact/PersonEntity.ts index 207e2a3af..45f2f2501 100644 --- a/packages/data-store/src/entities/contact/PersonEntity.ts +++ b/packages/data-store/src/entities/contact/PersonEntity.ts @@ -19,8 +19,6 @@ export class PersonEntity extends ContactOwnerEntity { @IsNotEmpty({ message: 'Blank last names are not allowed' }) lastName!: string - // TODO do we want a suffix? - @Column({ name: 'displayName', length: 255, nullable: false, unique: true }) @IsNotEmpty({ message: 'Blank display names are not allowed' }) displayName!: string diff --git a/packages/data-store/src/index.ts b/packages/data-store/src/index.ts index c538c896b..97dc8e202 100644 --- a/packages/data-store/src/index.ts +++ b/packages/data-store/src/index.ts @@ -15,11 +15,11 @@ import { ImageDimensionsEntity, imageDimensionsEntityFrom } from './entities/iss import { IssuerLocaleBrandingEntity, issuerLocaleBrandingEntityFrom } from './entities/issuanceBranding/IssuerLocaleBrandingEntity' import { IssuerBrandingEntity, issuerBrandingEntityFrom } from './entities/issuanceBranding/IssuerBrandingEntity' import { TextAttributesEntity, textAttributesEntityFrom } from './entities/issuanceBranding/TextAttributesEntity' -import { ContactRelationshipEntity } from './entities/contact/ContactRelationshipEntity' -import { ContactTypeEntity } from './entities/contact/ContactTypeEntity' +import { ContactRelationshipEntity, contactRelationshipEntityFrom } from './entities/contact/ContactRelationshipEntity' +import { ContactTypeEntity, contactTypeEntityFrom } from './entities/contact/ContactTypeEntity' import { ContactOwnerEntity } from './entities/contact/ContactOwnerEntity' -import { OrganizationEntity } from './entities/contact/OrganizationEntity' -import { PersonEntity } from './entities/contact/PersonEntity' +import { OrganizationEntity, organizationEntityFrom } from './entities/contact/OrganizationEntity' +import { PersonEntity, personEntityFrom } from './entities/contact/PersonEntity' export { ContactStore } from './contact/ContactStore' export { AbstractContactStore } from './contact/AbstractContactStore' @@ -89,4 +89,8 @@ export { textAttributesEntityFrom, issuerLocaleBrandingEntityFrom, credentialLocaleBrandingEntityFrom, + contactRelationshipEntityFrom, + contactTypeEntityFrom, + organizationEntityFrom, + personEntityFrom, } diff --git a/packages/data-store/src/types/contact/IAbstractContactStore.ts b/packages/data-store/src/types/contact/IAbstractContactStore.ts index d0c504491..f32475143 100644 --- a/packages/data-store/src/types/contact/IAbstractContactStore.ts +++ b/packages/data-store/src/types/contact/IAbstractContactStore.ts @@ -1,14 +1,22 @@ -// import { FindOptionsWhere } from 'typeorm' -// import { ContactEntity } from '../../entities/contact/ContactEntity' -// import { IdentityEntity } from '../../entities/contact/IdentityEntity' -import { BasicContactType, BasicContactOwner, IBasicIdentity, IContact, IIdentity, IPartialContact, IPartialIdentity } from './contact' - -// TODO WAL-625 refactor types to use interfaces and not the entities as the store should be replaceable -// export type FindContactArgs = FindOptionsWhere[] -// export type FindIdentityArgs = FindOptionsWhere[] +import { + BasicContactType, + BasicContactOwner, + IBasicIdentity, + IContact, + IIdentity, + IPartialContact, + IPartialIdentity, + ContactTypeEnum, + IContactType, + IContactRelationship, + IPartialContactRelationship, + IPartialContactType +} from './contact' export type FindContactArgs = Array export type FindIdentityArgs = Array +export type FindContactTypeArgs = Array +export type FindRelationshipArgs = Array export interface IGetContactArgs { contactId: string @@ -19,9 +27,7 @@ export interface IGetContactsArgs { } export interface IAddContactArgs { - // name: string - // alias: string - uri?: string // TODO what we do with uri? + uri?: string contactType: BasicContactType // TODO we can have a situation where we want to add a contact to an existing type, so use BasicContactType | IContactType? also make a test for these 2 situations in the store contactOwner: BasicContactOwner identities?: Array @@ -64,3 +70,38 @@ export interface IAddRelationshipArgs { leftContactId: string rightContactId: string } + +export interface IGetRelationshipArgs { + relationshipId: string +} + +export interface IGetRelationshipsArgs { + filter: FindRelationshipArgs +} + +export interface IUpdateRelationshipArgs { + relationship: Omit +} + +export interface IAddContactTypeArgs { + type: ContactTypeEnum + name: string + tenantId: string + description?: string +} + +export interface IGetContactTypeArgs { + contactTypeId: string +} + +export interface IGetContactTypesArgs { + filter?: FindContactTypeArgs +} + +export interface IUpdateContactTypeArgs { + contactType: Omit +} + +export interface IRemoveContactTypeArgs { + contactTypeId: string +} diff --git a/packages/data-store/src/types/contact/contact.ts b/packages/data-store/src/types/contact/contact.ts index fbc711682..6fb3e2e8c 100644 --- a/packages/data-store/src/types/contact/contact.ts +++ b/packages/data-store/src/types/contact/contact.ts @@ -171,8 +171,8 @@ export interface IPartialContactType extends Partial {} export interface IContactRelationship { id: string - leftContactId: string//IContact // TODO - rightContactId: string//IContact // TODO + leftContactId: string + rightContactId: string createdAt: Date lastUpdatedAt: Date } diff --git a/packages/issuance-branding/__tests__/localAgent.test.ts b/packages/issuance-branding/__tests__/localAgent.test.ts index deac4b496..3345ff5ac 100644 --- a/packages/issuance-branding/__tests__/localAgent.test.ts +++ b/packages/issuance-branding/__tests__/localAgent.test.ts @@ -29,6 +29,6 @@ const testContext = { tearDown, } -describe('Local integration tests', () => { +describe('Local integration tests', (): void => { issuanceBrandingAgentLogic(testContext) }) diff --git a/packages/issuance-branding/__tests__/restAgent.test.ts b/packages/issuance-branding/__tests__/restAgent.test.ts index e5a30fc72..5957779bc 100644 --- a/packages/issuance-branding/__tests__/restAgent.test.ts +++ b/packages/issuance-branding/__tests__/restAgent.test.ts @@ -66,6 +66,6 @@ const testContext = { tearDown, } -describe('REST integration tests', () => { +describe('REST integration tests', (): void => { issuanceBrandingAgentLogic(testContext) }) From 34aa2504a393b36bb44e813008ade240d45ef120 Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Tue, 1 Aug 2023 23:36:14 +0200 Subject: [PATCH 04/35] DPP-1 WIP --- .../shared/contactManagerAgentLogic.ts | 16 +- .../src/agent/ContactManager.ts | 10 +- .../src/types/IContactManager.ts | 6 +- .../src/__tests__/contact.entities.test.ts | 122 +++- .../src/__tests__/contact.store.test.ts | 640 +++++++++++++++++- .../src/contact/AbstractContactStore.ts | 3 - .../data-store/src/contact/ContactStore.ts | 58 +- .../src/entities/contact/ContactEntity.ts | 24 +- .../contact/ContactRelationshipEntity.ts | 4 +- .../src/entities/contact/ContactTypeEntity.ts | 24 +- .../entities/contact/OrganizationEntity.ts | 2 +- .../types/contact/IAbstractContactStore.ts | 6 +- .../data-store/src/types/contact/contact.ts | 13 +- 13 files changed, 805 insertions(+), 123 deletions(-) diff --git a/packages/contact-manager/__tests__/shared/contactManagerAgentLogic.ts b/packages/contact-manager/__tests__/shared/contactManagerAgentLogic.ts index cf45d0c6a..68ea306a5 100644 --- a/packages/contact-manager/__tests__/shared/contactManagerAgentLogic.ts +++ b/packages/contact-manager/__tests__/shared/contactManagerAgentLogic.ts @@ -11,8 +11,8 @@ import { IIdentity, IPerson, IGetContactsArgs, + IContactRelationship, } from '../../../data-store/src' -import { IContactRelationship } from '../../../data-store' type ConfiguredAgent = TAgent @@ -341,8 +341,8 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro expect(otherContacts.length).toEqual(1) const relationship: IContactRelationship = await agent.cmAddRelationship({ - leftContactId: savedContact.id, - rightContactId: otherContacts[0].id, + leftId: savedContact.id, + rightId: otherContacts[0].id, }) expect(relationship).toBeDefined() @@ -359,8 +359,8 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro expect(result.length).toEqual(1) expect(result[0].relationships.length).toEqual(1) - expect(result[0].relationships[0].leftContactId).toEqual(savedContact.id) - expect(result[0].relationships[0].rightContactId).toEqual(otherContacts[0].id) + expect(result[0].relationships[0].leftId).toEqual(savedContact.id) + expect(result[0].relationships[0].rightId).toEqual(otherContacts[0].id) }) it('should remove relationship', async (): Promise => { @@ -395,8 +395,8 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro expect(otherContacts.length).toEqual(1) const relationship: IContactRelationship = await agent.cmAddRelationship({ - leftContactId: savedContact.id, - rightContactId: otherContacts[0].id, + leftId: savedContact.id, + rightId: otherContacts[0].id, }) expect(relationship).toBeDefined() @@ -424,6 +424,8 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro expect(result.relationships.length).toEqual(0) }) + // TODO test all new crud functions + // remove relation }) } diff --git a/packages/contact-manager/src/agent/ContactManager.ts b/packages/contact-manager/src/agent/ContactManager.ts index 6f3211fe1..07f057ce5 100644 --- a/packages/contact-manager/src/agent/ContactManager.ts +++ b/packages/contact-manager/src/agent/ContactManager.ts @@ -24,13 +24,7 @@ import { IRemoveContactTypeArgs, IUpdateContactTypeArgs, } from '../types/IContactManager' -import { - IContact, - IIdentity, - AbstractContactStore, - IContactRelationship, - IContactType -} from '@sphereon/ssi-sdk.data-store' +import { IContact, IIdentity, AbstractContactStore, IContactRelationship, IContactType } from '@sphereon/ssi-sdk.data-store' /** * {@inheritDoc IContactManager} @@ -57,7 +51,7 @@ export class ContactManager implements IAgentPlugin { cmGetContactTypes: this.cmGetContactTypes.bind(this), cmAddContactType: this.cmAddContactType.bind(this), cmUpdateContactType: this.cmUpdateContactType.bind(this), - cmRemoveContactType: this.cmRemoveContactType.bind(this) + cmRemoveContactType: this.cmRemoveContactType.bind(this), } private readonly store: AbstractContactStore diff --git a/packages/contact-manager/src/types/IContactManager.ts b/packages/contact-manager/src/types/IContactManager.ts index 0751b3704..6895d077d 100644 --- a/packages/contact-manager/src/types/IContactManager.ts +++ b/packages/contact-manager/src/types/IContactManager.ts @@ -11,7 +11,7 @@ import { FindRelationshipArgs, ContactTypeEnum, FindContactTypeArgs, - IContactType + IContactType, } from '@sphereon/ssi-sdk.data-store' export interface IContactManager extends IPluginMethodMap { @@ -82,8 +82,8 @@ export interface IRemoveIdentityArgs { } export interface IAddRelationshipArgs { - leftContactId: string - rightContactId: string + leftId: string + rightId: string } export interface IRemoveRelationshipArgs { diff --git a/packages/data-store/src/__tests__/contact.entities.test.ts b/packages/data-store/src/__tests__/contact.entities.test.ts index 6cd262c59..e05cf0c2b 100644 --- a/packages/data-store/src/__tests__/contact.entities.test.ts +++ b/packages/data-store/src/__tests__/contact.entities.test.ts @@ -209,7 +209,7 @@ describe('Database entities tests', (): void => { const contactEntity: ContactEntity = contactEntityFrom(contact) - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrow('Blank first names are not allowed') + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank first names are not allowed') }) it('should throw error when saving person contact with blank middle name', async (): Promise => { @@ -230,7 +230,7 @@ describe('Database entities tests', (): void => { const contactEntity: ContactEntity = contactEntityFrom(contact) - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrow('Blank middle names are not allowed') + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank middle names are not allowed') }) it('should throw error when saving person contact with blank last name', async (): Promise => { @@ -251,7 +251,7 @@ describe('Database entities tests', (): void => { const contactEntity: ContactEntity = contactEntityFrom(contact) - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrow('Blank last names are not allowed') + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank last names are not allowed') }) it('should throw error when saving person contact with blank display name', async (): Promise => { @@ -272,7 +272,7 @@ describe('Database entities tests', (): void => { const contactEntity: ContactEntity = contactEntityFrom(contact) - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrow('Blank display names are not allowed') + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank display names are not allowed') }) it('should throw error when saving organization contact with blank legal name', async (): Promise => { @@ -292,7 +292,7 @@ describe('Database entities tests', (): void => { const contactEntity: ContactEntity = contactEntityFrom(contact) - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrow('Blank legal names are not allowed') + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank legal names are not allowed') }) it('should throw error when saving organization contact with blank display name', async (): Promise => { @@ -306,13 +306,13 @@ describe('Database entities tests', (): void => { contactOwner: { legalName: 'example_first_name', displayName: '', - cocNumber: '12345678ABC', + cocNumber: 'example_coc_number', }, } const contactEntity: ContactEntity = contactEntityFrom(contact) - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrow('Blank display names are not allowed') + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank display names are not allowed') }) it('should throw error when saving organization contact with blank coc number', async (): Promise => { @@ -332,7 +332,7 @@ describe('Database entities tests', (): void => { const contactEntity: ContactEntity = contactEntityFrom(contact) - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrow('Blank coc numbers are not allowed') + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank coc numbers are not allowed') }) it('should throw error when saving contact with blank contact type name', async (): Promise => { @@ -353,7 +353,7 @@ describe('Database entities tests', (): void => { const contactEntity: ContactEntity = contactEntityFrom(contact) - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrow('Blank names are not allowed') + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank names are not allowed') }) it('should throw error when saving contact with blank contact type description', async (): Promise => { @@ -375,7 +375,7 @@ describe('Database entities tests', (): void => { const contactEntity: ContactEntity = contactEntityFrom(contact) - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrow('Blank descriptions are not allowed') + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank descriptions are not allowed') }) it('should throw error when saving contact with blank contact type tenant id', async (): Promise => { @@ -396,7 +396,7 @@ describe('Database entities tests', (): void => { const contactEntity: ContactEntity = contactEntityFrom(contact) - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrow("Blank tenant id's are not allowed") + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError("Blank tenant id's are not allowed") }) it('Should enforce unique display name for a person contact', async (): Promise => { @@ -451,7 +451,7 @@ describe('Database entities tests', (): void => { contactOwner: { legalName: 'example_first_name', displayName: contactDisplayName, - cocNumber: '12345678ABC', + cocNumber: 'example_coc_number', }, } const contact1Entity: ContactEntity = contactEntityFrom(contact1) @@ -467,7 +467,7 @@ describe('Database entities tests', (): void => { contactOwner: { legalName: 'example_first_name', displayName: contactDisplayName, - cocNumber: '12345678ABC', + cocNumber: 'example_coc_number', }, } const contact2Entity: ContactEntity = contactEntityFrom(contact2) @@ -573,7 +573,7 @@ describe('Database entities tests', (): void => { const identityEntity: IdentityEntity = identityEntityFrom(identity) - await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrow('Blank aliases are not allowed') + await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank aliases are not allowed') }) it('should throw error when saving identity with blank correlation id', async (): Promise => { @@ -588,7 +588,7 @@ describe('Database entities tests', (): void => { const identityEntity: IdentityEntity = identityEntityFrom(identity) - await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrow('Blank correlation ids are not allowed') + await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank correlation ids are not allowed') }) it('should throw error when saving identity with blank metadata label', async (): Promise => { @@ -610,7 +610,7 @@ describe('Database entities tests', (): void => { const identityEntity: IdentityEntity = identityEntityFrom(identity) - await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrow('Blank metadata labels are not allowed') + await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank metadata labels are not allowed') }) it('should throw error when saving identity with blank metadata value', async (): Promise => { @@ -632,7 +632,7 @@ describe('Database entities tests', (): void => { const identityEntity: IdentityEntity = identityEntityFrom(identity) - await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrow('Blank metadata values are not allowed') + await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank metadata values are not allowed') }) it('Should save identity with openid connection to database', async (): Promise => { @@ -1564,30 +1564,43 @@ describe('Database entities tests', (): void => { ) }) - it('Should enforce unique coc number when saving organization', async (): Promise => { - const legalName = 'example_legal_name' - const organization1: BasicOrganization = { - legalName, - displayName: 'example_display_name1', - cocNumber: '1234567890', + it('Should enforce unique coc number when saving organization per tenant id', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.ORGANIZATION, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + legalName: 'example_legal_name', + displayName: 'example_display_name', + cocNumber: 'example_coc_number', + }, } - const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) - const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { + const contactEntity: ContactEntity = contactEntityFrom(contact) + await dbConnection.getRepository(ContactEntity).save(contactEntity, { transaction: true, }) - expect(savedOrganization1).toBeDefined() - - const organization2: BasicOrganization = { - legalName, - displayName: 'example_display_name2', - cocNumber: '1234567890', + const contact2: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name2', + }, + contactOwner: { + legalName: 'example_legal_name2', + displayName: 'example_display_name2', + cocNumber: 'example_coc_number', + }, } - const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) - await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.cocNumber' + const contactEntity2: ContactEntity = contactEntityFrom(contact2) + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity2, { transaction: true })).rejects.toThrowError( + 'Coc number already in use' ) }) @@ -2113,7 +2126,7 @@ describe('Database entities tests', (): void => { contactOwner: { legalName, displayName: 'example_display_name', - cocNumber: '12345678ABC', + cocNumber: 'example_coc_number', }, } @@ -2280,6 +2293,45 @@ describe('Database entities tests', (): void => { ) }) + it('Should save contact with existing contact type', async (): Promise => { + const contactType: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + } + + const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) + const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) + + const contact: IBasicContact = { + uri: 'example.com', + contactType: savedContactType, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + contactEntity.contactType = savedContactType + await dbConnection.getRepository(ContactEntity).save(contactEntity, { + transaction: true, + }) + + const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: contactEntity.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.contactType).toBeDefined() + expect(fromDb?.contactType.id).toEqual(savedContactType.id) + expect(fromDb?.contactType.type).toEqual(savedContactType.type) + expect(fromDb?.contactType.tenantId).toEqual(savedContactType.tenantId) + expect(fromDb?.contactType.name).toEqual(savedContactType.name) + }) + // TODO not update creation date when saving contact type // TODO add test for updating nested field and checking last updated at on parent }) diff --git a/packages/data-store/src/__tests__/contact.store.test.ts b/packages/data-store/src/__tests__/contact.store.test.ts index 8e68e37b2..caa92bd62 100644 --- a/packages/data-store/src/__tests__/contact.store.test.ts +++ b/packages/data-store/src/__tests__/contact.store.test.ts @@ -15,7 +15,10 @@ import { IGetIdentitiesArgs, IGetContactsArgs, BasicContactRelationship, - IContactRelationship + IContactRelationship, + IContactType, + IGetRelationshipsArgs, + BasicContactType, } from '../types' describe('Contact store tests', (): void => { @@ -123,6 +126,7 @@ describe('Contact store tests', (): void => { const result: Array = await contactStore.getContacts() + expect(result).toBeDefined() expect(result.length).toEqual(2) }) @@ -1119,8 +1123,8 @@ describe('Contact store tests', (): void => { expect(savedContact2).toBeDefined() const relationship: BasicContactRelationship = { - leftContactId: savedContact1.id, - rightContactId: savedContact2.id, + leftId: savedContact1.id, + rightId: savedContact2.id, } await contactStore.addRelationship(relationship) @@ -1128,8 +1132,177 @@ describe('Contact store tests', (): void => { expect(result).toBeDefined() expect(result.relationships.length).toEqual(1) - expect(result.relationships[0].leftContactId).toEqual(savedContact1.id) - expect(result.relationships[0].rightContactId).toEqual(savedContact2.id) + expect(result.relationships[0].leftId).toEqual(savedContact1.id) + expect(result.relationships[0].rightId).toEqual(savedContact2.id) + }) + + it('should get relationship', async (): Promise => { + const contact1: IBasicContact = { + uri: 'example1.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + const savedContact1: IContact = await contactStore.addContact(contact1) + expect(savedContact1).toBeDefined() + + const contact2: IBasicContact = { + uri: 'example2.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + const savedContact2: IContact = await contactStore.addContact(contact2) + expect(savedContact2).toBeDefined() + + const relationship: BasicContactRelationship = { + leftId: savedContact1.id, + rightId: savedContact2.id, + } + const savedRelationship: IContactRelationship = await contactStore.addRelationship(relationship) + + const result: IContactRelationship = await contactStore.getRelationship({ relationshipId: savedRelationship.id }) + + expect(result).toBeDefined() + expect(result.leftId).toEqual(savedContact1.id) + expect(result.rightId).toEqual(savedContact2.id) + }) + + it('should throw error when getting relationship with unknown id', async (): Promise => { + const relationshipId = 'unknownRelationshipId' + + await expect(contactStore.getRelationship({ relationshipId })).rejects.toThrow(`No relationship found for id: ${relationshipId}`) + }) + + it('should get all relationships', async (): Promise => { + const contact1: IBasicContact = { + uri: 'example1.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + const savedContact1: IContact = await contactStore.addContact(contact1) + expect(savedContact1).toBeDefined() + + const contact2: IBasicContact = { + uri: 'example2.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + const savedContact2: IContact = await contactStore.addContact(contact2) + expect(savedContact2).toBeDefined() + + const relationship1: BasicContactRelationship = { + leftId: savedContact1.id, + rightId: savedContact2.id, + } + await contactStore.addRelationship(relationship1) + + const relationship2: BasicContactRelationship = { + leftId: savedContact2.id, + rightId: savedContact1.id, + } + await contactStore.addRelationship(relationship2) + + const result: Array = await contactStore.getRelationships() + + expect(result).toBeDefined() + expect(result.length).toEqual(2) + }) + + it('should get relationships by filter', async (): Promise => { + const contact1: IBasicContact = { + uri: 'example1.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + const savedContact1: IContact = await contactStore.addContact(contact1) + expect(savedContact1).toBeDefined() + + const contact2: IBasicContact = { + uri: 'example2.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + const savedContact2: IContact = await contactStore.addContact(contact2) + expect(savedContact2).toBeDefined() + + const relationship1: BasicContactRelationship = { + leftId: savedContact1.id, + rightId: savedContact2.id, + } + await contactStore.addRelationship(relationship1) + + const relationship2: BasicContactRelationship = { + leftId: savedContact2.id, + rightId: savedContact1.id, + } + await contactStore.addRelationship(relationship2) + + const args: IGetRelationshipsArgs = { + filter: [ + { + leftId: savedContact1.id, + rightId: savedContact2.id, + }, + ], + } + + const result: Array = await contactStore.getRelationships(args) + + expect(result).toBeDefined() + expect(result.length).toEqual(1) }) it('should remove relationship', async (): Promise => { @@ -1168,8 +1341,8 @@ describe('Contact store tests', (): void => { expect(savedContact2).toBeDefined() const relationship: BasicContactRelationship = { - leftContactId: savedContact1.id, - rightContactId: savedContact2.id, + leftId: savedContact1.id, + rightId: savedContact2.id, } const savedRelationship: IContactRelationship = await contactStore.addRelationship(relationship) expect(savedRelationship).toBeDefined() @@ -1188,7 +1361,458 @@ describe('Contact store tests', (): void => { await expect(contactStore.removeRelationship({ relationshipId })).rejects.toThrow(`No relationship found for id: ${relationshipId}`) }) - // TODO cannot delete contact type when used by contact + it('should return no relationships if filter does not match', async (): Promise => { + const args: IGetRelationshipsArgs = { + filter: [ + { + leftId: 'unknown_id', + }, + ], + } + const result: Array = await contactStore.getRelationships(args) + + expect(result.length).toEqual(0) + }) + + it('should update relationship by id', async (): Promise => { + const contact1: IBasicContact = { + uri: 'example1.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + const savedContact1: IContact = await contactStore.addContact(contact1) + expect(savedContact1).toBeDefined() + + const contact2: IBasicContact = { + uri: 'example2.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + const savedContact2: IContact = await contactStore.addContact(contact2) + expect(savedContact2).toBeDefined() + + const contact3: IBasicContact = { + uri: 'example3.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d287', + name: 'example_name3', + }, + contactOwner: { + firstName: 'example_first_name3', + middleName: 'example_middle_name3', + lastName: 'example_last_name3', + displayName: 'example_display_name3', + }, + } + const savedContact3: IContact = await contactStore.addContact(contact3) + expect(savedContact3).toBeDefined() + + const relationship: BasicContactRelationship = { + leftId: savedContact1.id, + rightId: savedContact2.id, + } + const savedRelationship: IContactRelationship = await contactStore.addRelationship(relationship) + + const updatedRelationship: IContactRelationship = { + ...savedRelationship, + rightId: savedContact3.id, + } + + await contactStore.updateRelationship({ relationship: updatedRelationship }) + + const result: IContact = await contactStore.getContact({ contactId: savedContact1.id }) + + expect(result).toBeDefined() + expect(result.relationships.length).toEqual(1) + expect(result.relationships[0].leftId).toEqual(savedContact1.id) + expect(result.relationships[0].rightId).toEqual(savedContact3.id) + }) + + it('should throw error when updating relationship with unknown id', async (): Promise => { + const contact1: IBasicContact = { + uri: 'example1.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + const savedContact1: IContact = await contactStore.addContact(contact1) + expect(savedContact1).toBeDefined() + + const contact2: IBasicContact = { + uri: 'example2.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + const savedContact2: IContact = await contactStore.addContact(contact2) + expect(savedContact2).toBeDefined() + + const relationship: BasicContactRelationship = { + leftId: savedContact1.id, + rightId: savedContact2.id, + } + const savedRelationship: IContactRelationship = await contactStore.addRelationship(relationship) + + const relationshipId = 'unknownRelationshipId' + const updatedRelationship: IContactRelationship = { + ...savedRelationship, + id: relationshipId, + rightId: savedContact2.id, + } + + await expect(contactStore.updateRelationship({ relationship: updatedRelationship })).rejects.toThrow( + `No contact relationship found for id: ${relationshipId}` + ) + }) + + it('should throw error when updating relationship with unknown right side id', async (): Promise => { + const contact1: IBasicContact = { + uri: 'example1.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + const savedContact1: IContact = await contactStore.addContact(contact1) + expect(savedContact1).toBeDefined() + + const contact2: IBasicContact = { + uri: 'example2.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + const savedContact2: IContact = await contactStore.addContact(contact2) + expect(savedContact2).toBeDefined() + + const relationship: BasicContactRelationship = { + leftId: savedContact1.id, + rightId: savedContact2.id, + } + const savedRelationship: IContactRelationship = await contactStore.addRelationship(relationship) + + const contactId = 'unknownContactId' + const updatedRelationship: IContactRelationship = { + ...savedRelationship, + rightId: contactId, + } + + await expect(contactStore.updateRelationship({ relationship: updatedRelationship })).rejects.toThrow( + `No contact found for right contact id: ${contactId}` + ) + }) + + it('should throw error when updating relationship with unknown left side id', async (): Promise => { + const contact1: IBasicContact = { + uri: 'example1.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + const savedContact1: IContact = await contactStore.addContact(contact1) + expect(savedContact1).toBeDefined() + + const contact2: IBasicContact = { + uri: 'example2.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + const savedContact2: IContact = await contactStore.addContact(contact2) + expect(savedContact2).toBeDefined() + + const relationship: BasicContactRelationship = { + leftId: savedContact1.id, + rightId: savedContact2.id, + } + const savedRelationship: IContactRelationship = await contactStore.addRelationship(relationship) + + const contactId = 'unknownContactId' + const updatedRelationship: IContactRelationship = { + ...savedRelationship, + leftId: contactId, + } + + await expect(contactStore.updateRelationship({ relationship: updatedRelationship })).rejects.toThrow( + `No contact found for left contact id: ${contactId}` + ) + }) + + it('should add contact type', async (): Promise => { + const contactType: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name', + description: 'example_description', + } + + const savedContactType: IContactType = await contactStore.addContactType(contactType) + const result: IContactType = await contactStore.getContactType({ contactTypeId: savedContactType.id }) + + expect(result).toBeDefined() + expect(result.name).toEqual(contactType.name) + expect(result.type).toEqual(contactType.type) + expect(result.tenantId).toEqual(contactType.tenantId) + expect(result.description).toEqual(contactType.description) + expect(result.lastUpdatedAt).toBeDefined() + expect(result.createdAt).toBeDefined() + }) + + it('should get contact types by filter', async (): Promise => { + const contactType1: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name1', + description: 'example_description1', + } + const savedContactType1: IContactType = await contactStore.addContactType(contactType1) + expect(savedContactType1).toBeDefined() + + const contactType2: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d287', + name: 'example_name2', + description: 'example_description2', + } + const savedContactType2: IContactType = await contactStore.addContactType(contactType2) + expect(savedContactType2).toBeDefined() + + const result: Array = await contactStore.getContactTypes({ + filter: [ + { + type: ContactTypeEnum.PERSON, + name: 'example_name1', + description: 'example_description1', + }, + ], + }) + + expect(result).toBeDefined() + expect(result.length).toEqual(1) + }) + + it('should return no contact types if filter does not match', async (): Promise => { + const contactType1: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name1', + description: 'example_description1', + } + const savedContactType1: IContactType = await contactStore.addContactType(contactType1) + expect(savedContactType1).toBeDefined() + + const contactType2: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d287', + name: 'example_name2', + description: 'example_description2', + } + const savedContactType2: IContactType = await contactStore.addContactType(contactType2) + expect(savedContactType2).toBeDefined() + + const result: Array = await contactStore.getContactTypes({ + filter: [ + { + type: ContactTypeEnum.PERSON, + name: 'unknown_name', + description: 'unknown_description', + }, + ], + }) + + expect(result).toBeDefined() + expect(result.length).toEqual(0) + }) + + it('should throw error when updating contact type with unknown id', async (): Promise => { + const contactType: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name', + description: 'example_description', + } + const savedContactType: IContactType = await contactStore.addContactType(contactType) + expect(savedContactType).toBeDefined() + + const contactTypeId = 'unknownContactTypeId' + const updatedContactType: IContactType = { + ...savedContactType, + id: contactTypeId, + description: 'new_example_description', + } + + await expect(contactStore.updateContactType({ contactType: updatedContactType })).rejects.toThrow( + `No contact type found for id: ${contactTypeId}` + ) + }) + + it('should update contact type by id', async (): Promise => { + const contactType: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name', + description: 'example_description', + } + const savedContactType: IContactType = await contactStore.addContactType(contactType) + expect(savedContactType).toBeDefined() + + const newDescription = 'new_example_description' + const updatedContactType: IContactType = { + ...savedContactType, + description: newDescription, + } + + const result: IContactType = await contactStore.updateContactType({ contactType: updatedContactType }) + + expect(result).toBeDefined() + expect(result.description).toEqual(newDescription) + }) + + it('should throw error when removing contact type with unknown id', async (): Promise => { + const contactTypeId = 'unknownContactTypeId' + + await expect(contactStore.removeContactType({ contactTypeId })).rejects.toThrow(`No contact type found for id: ${contactTypeId}`) + }) + + it('should remove contact type', async (): Promise => { + const contactType: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name', + description: 'example_description', + } + const savedContactType: IContactType = await contactStore.addContactType(contactType) + expect(savedContactType).toBeDefined() + + const retrievedContactType: IContactType = await contactStore.getContactType({ contactTypeId: savedContactType.id }) + expect(retrievedContactType).toBeDefined() + + await contactStore.removeContactType({ contactTypeId: savedContactType.id }) + + const result: Array = await contactStore.getContactTypes() + + expect(result).toBeDefined() + expect(result.length).toEqual(0) + }) + + it('should throw error when removing contact type attached to contact', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + const savedContact: IContact = await contactStore.addContact(contact) + expect(savedContact).toBeDefined() + + await expect(contactStore.removeContactType({ contactTypeId: savedContact.contactType.id })).rejects.toThrow( + `Unable to remove contact type with id: ${savedContact.contactType.id}. Contact type is in use` + ) + }) + + it('Should save contact with existing contact type', async (): Promise => { + const contactType: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + } + const savedContactType: IContactType = await contactStore.addContactType(contactType) + expect(savedContactType).toBeDefined() + + const contact: IBasicContact = { + uri: 'example.com', + contactType: savedContactType, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const result: IContact = await contactStore.addContact(contact) + + expect(result).toBeDefined() + expect(result?.contactType).toBeDefined() + expect(result?.contactType.id).toEqual(savedContactType.id) + expect(result?.contactType.type).toEqual(savedContactType.type) + expect(result?.contactType.tenantId).toEqual(savedContactType.tenantId) + expect(result?.contactType.name).toEqual(savedContactType.name) + }) }) // maybe add some categories for the tests to find them diff --git a/packages/data-store/src/contact/AbstractContactStore.ts b/packages/data-store/src/contact/AbstractContactStore.ts index c776617e4..7d5ac64b2 100644 --- a/packages/data-store/src/contact/AbstractContactStore.ts +++ b/packages/data-store/src/contact/AbstractContactStore.ts @@ -31,19 +31,16 @@ export abstract class AbstractContactStore { abstract addContact(args: IAddContactArgs): Promise abstract updateContact(args: IUpdateContactArgs): Promise abstract removeContact(args: IRemoveContactArgs): Promise - abstract getIdentity(args: IGetIdentityArgs): Promise abstract getIdentities(args?: IGetIdentitiesArgs): Promise> abstract addIdentity(args: IAddIdentityArgs): Promise abstract updateIdentity(args: IUpdateIdentityArgs): Promise abstract removeIdentity(args: IRemoveIdentityArgs): Promise - abstract getRelationship(args: IGetRelationshipArgs): Promise abstract getRelationships(args?: IGetRelationshipsArgs): Promise> abstract addRelationship(args: IAddRelationshipArgs): Promise abstract updateRelationship(args: IUpdateRelationshipArgs): Promise abstract removeRelationship(args: IRemoveRelationshipArgs): Promise - abstract getContactType(args: IGetContactTypeArgs): Promise abstract getContactTypes(args?: IGetContactTypesArgs): Promise> abstract addContactType(args: IAddContactTypeArgs): Promise diff --git a/packages/data-store/src/contact/ContactStore.ts b/packages/data-store/src/contact/ContactStore.ts index 065221365..4b59f785e 100644 --- a/packages/data-store/src/contact/ContactStore.ts +++ b/packages/data-store/src/contact/ContactStore.ts @@ -256,22 +256,22 @@ export class ContactStore extends AbstractContactStore { await this.deleteIdentities([identity]) } - addRelationship = async ({ leftContactId, rightContactId }: IAddRelationshipArgs): Promise => { + addRelationship = async ({ leftId, rightId }: IAddRelationshipArgs): Promise => { const contactRepository: Repository = (await this.dbConnection).getRepository(ContactEntity) const leftContact: ContactEntity | null = await contactRepository.findOne({ - where: { id: leftContactId }, + where: { id: leftId }, }) if (!leftContact) { - return Promise.reject(Error(`No contact found for left contact id: ${leftContactId}`)) + return Promise.reject(Error(`No contact found for left contact id: ${leftId}`)) } const rightContact: ContactEntity | null = await contactRepository.findOne({ - where: { id: rightContactId }, + where: { id: rightId }, }) if (!rightContact) { - return Promise.reject(Error(`No contact found for right contact id: ${rightContactId}`)) + return Promise.reject(Error(`No contact found for right contact id: ${rightId}`)) } const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ @@ -296,7 +296,6 @@ export class ContactStore extends AbstractContactStore { return contactRelationshipFrom(result) } - // TODO get relationships getRelationships = async (args?: IGetRelationshipsArgs): Promise> => { const contactRelationshipRepository: Repository = (await this.dbConnection).getRepository(ContactRelationshipEntity) const initialResult: Array | null = await contactRelationshipRepository.find({ @@ -312,7 +311,6 @@ export class ContactStore extends AbstractContactStore { return result.map((contactRelationship: ContactRelationshipEntity) => contactRelationshipFrom(contactRelationship)) } - // TODO update relationship updateRelationship = async ({ relationship }: IUpdateRelationshipArgs): Promise => { const contactRelationshipRepository: Repository = (await this.dbConnection).getRepository(ContactRelationshipEntity) const result: ContactRelationshipEntity | null = await contactRelationshipRepository.findOne({ @@ -323,12 +321,22 @@ export class ContactStore extends AbstractContactStore { return Promise.reject(Error(`No contact relationship found for id: ${relationship.id}`)) } - // const updatedContactType = { - // // TODO fix type - // ...contactType, - // identities: result.identities, - // relationships: result.relationships, - // } + const contactRepository: Repository = (await this.dbConnection).getRepository(ContactEntity) + const leftContact: ContactEntity | null = await contactRepository.findOne({ + where: { id: relationship.leftId }, + }) + + if (!leftContact) { + return Promise.reject(Error(`No contact found for left contact id: ${relationship.leftId}`)) + } + + const rightContact: ContactEntity | null = await contactRepository.findOne({ + where: { id: relationship.rightId }, + }) + + if (!rightContact) { + return Promise.reject(Error(`No contact found for right contact id: ${relationship.rightId}`)) + } debug('Updating contact relationship', relationship) const updatedResult: ContactRelationshipEntity = await contactRelationshipRepository.save(relationship, { transaction: true }) @@ -351,7 +359,6 @@ export class ContactStore extends AbstractContactStore { await contactRelationshipRepository.delete(relationshipId) } - // TODO add contact type addContactType = async (args: IAddContactTypeArgs): Promise => { // TODO do we need checks? @@ -362,7 +369,6 @@ export class ContactStore extends AbstractContactStore { return contactTypeFrom(createdResult) } - // TODO get contact type getContactType = async ({ contactTypeId }: IGetContactTypeArgs): Promise => { const result: ContactTypeEntity | null = await (await this.dbConnection).getRepository(ContactTypeEntity).findOne({ where: { id: contactTypeId }, @@ -375,7 +381,6 @@ export class ContactStore extends AbstractContactStore { return contactTypeFrom(result) } - // TODO get contact types getContactTypes = async (args?: IGetContactTypesArgs): Promise> => { const contactTypeRepository: Repository = (await this.dbConnection).getRepository(ContactTypeEntity) const initialResult: Array | null = await contactTypeRepository.find({ @@ -391,7 +396,6 @@ export class ContactStore extends AbstractContactStore { return result.map((contactType: ContactTypeEntity) => contactTypeFrom(contactType)) } - // TODO update contact type updateContactType = async ({ contactType }: IUpdateContactTypeArgs): Promise => { const contactTypeRepository: Repository = (await this.dbConnection).getRepository(ContactTypeEntity) const result: ContactTypeEntity | null = await contactTypeRepository.findOne({ @@ -402,22 +406,24 @@ export class ContactStore extends AbstractContactStore { return Promise.reject(Error(`No contact type found for id: ${contactType.id}`)) } - // const updatedContactType = { - // // TODO fix type - // ...contactType, - // identities: result.identities, - // relationships: result.relationships, - // } - debug('Updating contact type', contactType) const updatedResult: ContactTypeEntity = await contactTypeRepository.save(contactType, { transaction: true }) return contactTypeFrom(updatedResult) } - // TODO remove contact type removeContactType = async ({ contactTypeId }: IRemoveContactTypeArgs): Promise => { - // TODO maybe add check if contact type is used, if used, cannot delete + const contacts: Array | null = await (await this.dbConnection).getRepository(ContactEntity).find({ + where: { + contactType: { + id: contactTypeId, + }, + }, + }) + + if (contacts?.length > 0) { + return Promise.reject(Error(`Unable to remove contact type with id: ${contactTypeId}. Contact type is in use`)) + } const contactTypeRepository: Repository = (await this.dbConnection).getRepository(ContactTypeEntity) const contactType: ContactTypeEntity | null = await contactTypeRepository.findOne({ diff --git a/packages/data-store/src/entities/contact/ContactEntity.ts b/packages/data-store/src/entities/contact/ContactEntity.ts index dd2b27492..7b005775f 100644 --- a/packages/data-store/src/entities/contact/ContactEntity.ts +++ b/packages/data-store/src/entities/contact/ContactEntity.ts @@ -5,6 +5,7 @@ import { Column, CreateDateColumn, Entity, + FindOptionsWhere, JoinColumn, ManyToOne, OneToMany, @@ -58,7 +59,7 @@ export class ContactEntity extends BaseEntity { @JoinColumn({ name: 'contactTypeId' }) contactType!: ContactTypeEntity - @OneToOne(() => ContactOwnerEntity, (member: PersonEntity | OrganizationEntity) => member.contact, { + @OneToOne(() => ContactOwnerEntity, (owner: PersonEntity | OrganizationEntity) => owner.contact, { cascade: true, onDelete: 'CASCADE', eager: true, @@ -88,6 +89,27 @@ export class ContactEntity extends BaseEntity { this.lastUpdatedAt = new Date() } + @BeforeInsert() + @BeforeUpdate() + async checkUniqueCocNumberAndTenantId(): Promise { + const result: Array = await ContactEntity.find({ + where: { + contactOwner: { + cocNumber: (this.contactOwner).cocNumber, + } as FindOptionsWhere, + contactType: { + tenantId: this.contactType.tenantId, + }, + }, + }) + + if (result?.length > 0) { + return Promise.reject(Error('Coc number already in use')) + } + + return + } + @BeforeInsert() @BeforeUpdate() async validate(): Promise { diff --git a/packages/data-store/src/entities/contact/ContactRelationshipEntity.ts b/packages/data-store/src/entities/contact/ContactRelationshipEntity.ts index d25808568..8dc8d65b5 100644 --- a/packages/data-store/src/entities/contact/ContactRelationshipEntity.ts +++ b/packages/data-store/src/entities/contact/ContactRelationshipEntity.ts @@ -68,8 +68,8 @@ export const contactRelationshipEntityFrom = (relationship: { left: ContactEntit export const contactRelationshipFrom = (relationship: ContactRelationshipEntity): IContactRelationship => { return { id: relationship.id, - leftContactId: relationship.leftId, //relationship.left.id, - rightContactId: relationship.rightId, //relationship.right.id, + leftId: relationship.leftId, //relationship.left.id, + rightId: relationship.rightId, //relationship.right.id, createdAt: relationship.createdAt, lastUpdatedAt: relationship.lastUpdatedAt, } diff --git a/packages/data-store/src/entities/contact/ContactTypeEntity.ts b/packages/data-store/src/entities/contact/ContactTypeEntity.ts index c0853d315..13ca80956 100644 --- a/packages/data-store/src/entities/contact/ContactTypeEntity.ts +++ b/packages/data-store/src/entities/contact/ContactTypeEntity.ts @@ -1,15 +1,4 @@ -import { - Entity, - //JoinColumn, - PrimaryGeneratedColumn, - Column, - Index, - CreateDateColumn, - UpdateDateColumn, - OneToMany, - BeforeInsert, - BeforeUpdate, -} from 'typeorm' +import { Entity, PrimaryGeneratedColumn, Column, Index, CreateDateColumn, UpdateDateColumn, OneToMany, BeforeInsert, BeforeUpdate } from 'typeorm' import { ContactEntity } from './ContactEntity' import { BasicContactType, ContactTypeEnum, IContactType, ValidationConstraint } from '../../types' import { IsNotEmpty, Validate, validate, ValidationError } from 'class-validator' @@ -33,18 +22,13 @@ export class ContactTypeEntity { @Validate(IsNonEmptyStringConstraint, { message: 'Blank descriptions are not allowed' }) description?: string - // TODO why is the tenantId in this entity? - @Column({ name: 'tenantId', length: 255, nullable: false, unique: true }) + @Column({ name: 'tenantId', length: 255, nullable: false, unique: false }) @IsNotEmpty({ message: "Blank tenant id's are not allowed" }) tenantId!: string @OneToMany(() => ContactEntity, (contact: ContactEntity) => contact.contactType, { - // cascade: true, - // onDelete: 'CASCADE', - // eager: true, // TODO check this relation nullable: false, }) - // @JoinColumn({ name: 'contactId' }) contacts!: Array @CreateDateColumn({ name: 'created_at', nullable: false }) @@ -69,11 +53,13 @@ export class ContactTypeEntity { export const contactTypeEntityFrom = (args: BasicContactType): ContactTypeEntity => { const contactTypeEntity: ContactTypeEntity = new ContactTypeEntity() + if (args.id) { + contactTypeEntity.id = args.id + } contactTypeEntity.type = args.type contactTypeEntity.name = args.name contactTypeEntity.description = args.description contactTypeEntity.tenantId = args.tenantId - // TODO contacts? return contactTypeEntity } diff --git a/packages/data-store/src/entities/contact/OrganizationEntity.ts b/packages/data-store/src/entities/contact/OrganizationEntity.ts index 939680d46..aabd5f03b 100644 --- a/packages/data-store/src/entities/contact/OrganizationEntity.ts +++ b/packages/data-store/src/entities/contact/OrganizationEntity.ts @@ -17,7 +17,7 @@ export class OrganizationEntity extends ContactOwnerEntity { displayName!: string // TODO uniek per tenant - @Column({ name: 'cocNumber', length: 255, nullable: true, unique: true }) + @Column({ name: 'cocNumber', length: 255, nullable: true, unique: false }) @Validate(IsNonEmptyStringConstraint, { message: 'Blank coc numbers are not allowed' }) cocNumber?: string diff --git a/packages/data-store/src/types/contact/IAbstractContactStore.ts b/packages/data-store/src/types/contact/IAbstractContactStore.ts index f32475143..8385213ac 100644 --- a/packages/data-store/src/types/contact/IAbstractContactStore.ts +++ b/packages/data-store/src/types/contact/IAbstractContactStore.ts @@ -10,7 +10,7 @@ import { IContactType, IContactRelationship, IPartialContactRelationship, - IPartialContactType + IPartialContactType, } from './contact' export type FindContactArgs = Array @@ -67,8 +67,8 @@ export interface IRemoveRelationshipArgs { } export interface IAddRelationshipArgs { - leftContactId: string - rightContactId: string + leftId: string + rightId: string } export interface IGetRelationshipArgs { diff --git a/packages/data-store/src/types/contact/contact.ts b/packages/data-store/src/types/contact/contact.ts index 6fb3e2e8c..e1cf55899 100644 --- a/packages/data-store/src/types/contact/contact.ts +++ b/packages/data-store/src/types/contact/contact.ts @@ -166,18 +166,17 @@ export interface IContactType { createdAt: Date lastUpdatedAt: Date } -export declare type BasicContactType = Omit +export interface BasicContactType extends Omit { + id?: string +} export interface IPartialContactType extends Partial {} export interface IContactRelationship { id: string - leftContactId: string - rightContactId: string + leftId: string + rightId: string createdAt: Date lastUpdatedAt: Date } export declare type BasicContactRelationship = Omit -export interface IPartialContactRelationship extends Partial> { - left: IPartialContact - right: IPartialContact -} +export interface IPartialContactRelationship extends Partial {} From b105d31dd94175d1da08c09284e3842469ece909 Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Wed, 2 Aug 2023 12:24:42 +0200 Subject: [PATCH 05/35] DPP-1 migrations WIP --- .../src/__tests__/contact.entities.test.ts | 4568 +++++++++-------- .../migrations/generic/1-CreateContacts.ts | 136 +- .../generic/1-CreateIssuanceBranding.ts | 80 +- .../migrations/generic/2-CreateContacts.ts | 68 + .../src/migrations/generic/index.ts | 8 +- .../postgres/1690925872592-CreateContacts.ts | 61 + .../sqlite/1690925872693-CreateContacts.ts | 16 + 7 files changed, 2590 insertions(+), 2347 deletions(-) create mode 100644 packages/data-store/src/migrations/generic/2-CreateContacts.ts create mode 100644 packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts create mode 100644 packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts diff --git a/packages/data-store/src/__tests__/contact.entities.test.ts b/packages/data-store/src/__tests__/contact.entities.test.ts index e05cf0c2b..914db5ee7 100644 --- a/packages/data-store/src/__tests__/contact.entities.test.ts +++ b/packages/data-store/src/__tests__/contact.entities.test.ts @@ -1,50 +1,70 @@ -import { DataSource, FindOptionsWhere } from 'typeorm' +import { DataSource + // , FindOptionsWhere +} from 'typeorm' -import { DataStoreContactEntities } from '../index' +import { DataStoreContactEntities + , DataStoreMigrations +} from '../index' import { IBasicContact, ContactTypeEnum, IPerson, - IOrganization, - IdentityRoleEnum, - CorrelationIdentifierEnum, - ConnectionTypeEnum, - BasicContactType, - BasicOrganization, - BasicPerson, - IBasicConnection, - IBasicIdentity, - BasicDidAuthConfig, - BasicOpenIdConfig, + // IOrganization, + // IdentityRoleEnum, + // CorrelationIdentifierEnum, + // ConnectionTypeEnum, + // BasicContactType, + // BasicOrganization, + // BasicPerson, + // IBasicConnection, + // IBasicIdentity, + // BasicDidAuthConfig, + // BasicOpenIdConfig, } from '../types' -import { PersonEntity, personEntityFrom } from '../entities/contact/PersonEntity' -import { OrganizationEntity, organizationEntityFrom } from '../entities/contact/OrganizationEntity' -import { ContactRelationshipEntity, contactRelationshipEntityFrom } from '../entities/contact/ContactRelationshipEntity' -import { ContactTypeEntity, contactTypeEntityFrom } from '../entities/contact/ContactTypeEntity' +import { PersonEntity + // , personEntityFrom +} from '../entities/contact/PersonEntity' +// import { OrganizationEntity, organizationEntityFrom } from '../entities/contact/OrganizationEntity' +// import { ContactRelationshipEntity, contactRelationshipEntityFrom } from '../entities/contact/ContactRelationshipEntity' +// import { ContactTypeEntity, contactTypeEntityFrom } from '../entities/contact/ContactTypeEntity' import { ContactEntity, contactEntityFrom } from '../entities/contact/ContactEntity' -import { IdentityEntity, identityEntityFrom } from '../entities/contact/IdentityEntity' -import { OpenIdConfigEntity, openIdConfigEntityFrom } from '../entities/contact/OpenIdConfigEntity' -import { DidAuthConfigEntity, didAuthConfigEntityFrom } from '../entities/contact/DidAuthConfigEntity' -import { ConnectionEntity, connectionEntityFrom } from '../entities/contact/ConnectionEntity' -import { CorrelationIdentifierEntity } from '../entities/contact/CorrelationIdentifierEntity' -import { IdentityMetadataItemEntity } from '../entities/contact/IdentityMetadataItemEntity' -import { ContactOwnerEntity } from '../entities/contact/ContactOwnerEntity' +// import { IdentityEntity, identityEntityFrom } from '../entities/contact/IdentityEntity' +// import { OpenIdConfigEntity, openIdConfigEntityFrom } from '../entities/contact/OpenIdConfigEntity' +// import { DidAuthConfigEntity, didAuthConfigEntityFrom } from '../entities/contact/DidAuthConfigEntity' +// import { ConnectionEntity, connectionEntityFrom } from '../entities/contact/ConnectionEntity' +// import { CorrelationIdentifierEntity } from '../entities/contact/CorrelationIdentifierEntity' +// import { IdentityMetadataItemEntity } from '../entities/contact/IdentityMetadataItemEntity' +// import { ContactOwnerEntity } from '../entities/contact/ContactOwnerEntity' describe('Database entities tests', (): void => { let dbConnection: DataSource + // beforeEach(async (): Promise => { + // dbConnection = await new DataSource({ + // type: 'sqlite', + // database: ':memory:', + // logging: 'all', + // migrationsRun: false, + // // migrations: DataStoreMigrations, + // synchronize: true, //false + // entities: DataStoreContactEntities, + // }).initialize() + // // await dbConnection.runMigrations() + // // expect(await dbConnection.showMigrations()).toBeFalsy() + // }) + beforeEach(async (): Promise => { dbConnection = await new DataSource({ type: 'sqlite', database: ':memory:', - //logging: 'all', + logging: 'all', migrationsRun: false, - // migrations: DataStoreMigrations, - synchronize: true, //false + migrations: DataStoreMigrations, + synchronize: false, //false entities: DataStoreContactEntities, }).initialize() - // await dbConnection.runMigrations() - // expect(await dbConnection.showMigrations()).toBeFalsy() + await dbConnection.runMigrations() + expect(await dbConnection.showMigrations()).toBeFalsy() }) afterEach(async (): Promise => { @@ -89,2249 +109,2249 @@ describe('Database entities tests', (): void => { expect((fromDb?.contactOwner).lastName).toEqual((contact.contactOwner).lastName) expect((fromDb?.contactOwner).displayName).toEqual((contact.contactOwner).displayName) }) - - it('Should save organization contact to database', async (): Promise => { - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.ORGANIZATION, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - legalName: 'example_legal_name', - displayName: 'example_display_name', - cocNumber: 'example_coc_number', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - await dbConnection.getRepository(ContactEntity).save(contactEntity, { - transaction: true, - }) - - const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: contactEntity.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.identities?.length).toEqual(0) - expect(fromDb?.uri).toEqual(contact.uri) - expect(fromDb?.contactType).toBeDefined() - expect(fromDb?.contactType.type).toEqual(contact.contactType.type) - expect(fromDb?.contactType.tenantId).toEqual(contact.contactType.tenantId) - expect(fromDb?.contactType.name).toEqual(contact.contactType.name) - expect(fromDb?.contactOwner).toBeDefined() - expect((fromDb?.contactOwner).legalName).toEqual((contact.contactOwner).legalName) - expect((fromDb?.contactOwner).displayName).toEqual((contact.contactOwner).displayName) - expect((fromDb?.contactOwner).cocNumber).toEqual((contact.contactOwner).cocNumber) - }) - - it('Should result in contact relationship for the owner side only', async (): Promise => { - const contact1: IBasicContact = { - uri: 'example1.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name1', - }, - contactOwner: { - firstName: 'example_first_name1', - middleName: 'example_middle_name1', - lastName: 'example_last_name1', - displayName: 'example_display_name1', - }, - } - - const contactEntity1: ContactEntity = contactEntityFrom(contact1) - const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { - transaction: true, - }) - - const contact2: IBasicContact = { - uri: 'example2.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - name: 'example_name2', - }, - contactOwner: { - firstName: 'example_first_name2', - middleName: 'example_middle_name2', - lastName: 'example_last_name2', - displayName: 'example_display_name2', - }, - } - - const contactEntity2: ContactEntity = contactEntityFrom(contact2) - const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { - transaction: true, - }) - - const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ - left: savedContact1, - right: savedContact2, - }) - - await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { - transaction: true, - }) - - const fromDb1: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: savedContact1.id }, - }) - - const fromDb2: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: savedContact2.id }, - }) - - expect(fromDb1).toBeDefined() - expect(fromDb1?.relationships.length).toEqual(1) - expect(fromDb2).toBeDefined() - expect(fromDb2?.relationships.length).toEqual(0) - }) - - it('should throw error when saving person contact with blank first name', async (): Promise => { - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - firstName: '', - middleName: 'example_middle_name1', - lastName: 'example_last_name1', - displayName: 'example_display_name1', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank first names are not allowed') - }) - - it('should throw error when saving person contact with blank middle name', async (): Promise => { - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - firstName: 'example_first_name', - middleName: '', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank middle names are not allowed') - }) - - it('should throw error when saving person contact with blank last name', async (): Promise => { - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: '', - displayName: 'example_display_name', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank last names are not allowed') - }) - - it('should throw error when saving person contact with blank display name', async (): Promise => { - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: '', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank display names are not allowed') - }) - - it('should throw error when saving organization contact with blank legal name', async (): Promise => { - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.ORGANIZATION, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - legalName: '', - displayName: 'example_legal_name', - cocNumber: 'example_coc_number', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank legal names are not allowed') - }) - - it('should throw error when saving organization contact with blank display name', async (): Promise => { - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.ORGANIZATION, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - legalName: 'example_first_name', - displayName: '', - cocNumber: 'example_coc_number', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank display names are not allowed') - }) - - it('should throw error when saving organization contact with blank coc number', async (): Promise => { - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.ORGANIZATION, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - legalName: 'example_first_name', - displayName: 'example_display_name', - cocNumber: '', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank coc numbers are not allowed') - }) - - it('should throw error when saving contact with blank contact type name', async (): Promise => { - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: '', - }, - contactOwner: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank names are not allowed') - }) - - it('should throw error when saving contact with blank contact type description', async (): Promise => { - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - description: '', - }, - contactOwner: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank descriptions are not allowed') - }) - - it('should throw error when saving contact with blank contact type tenant id', async (): Promise => { - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '', - name: 'example_name', - }, - contactOwner: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError("Blank tenant id's are not allowed") - }) - - it('Should enforce unique display name for a person contact', async (): Promise => { - const contactDisplayName = 'non_unique_name' - const contact1: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - name: 'example_name', - }, - contactOwner: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: contactDisplayName, - }, - } - const contact1Entity: ContactEntity = contactEntityFrom(contact1) - await dbConnection.getRepository(ContactEntity).save(contact1Entity) - - const contact2: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: contactDisplayName, - }, - } - const contact2Entity: ContactEntity = contactEntityFrom(contact2) - - await expect(dbConnection.getRepository(ContactEntity).save(contact2Entity)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: contact_type_entity.name' - ) - }) - - it('Should enforce unique display name for a organization contact', async (): Promise => { - const contactDisplayName = 'non_unique_name' - const contact1: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.ORGANIZATION, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - name: 'example_name', - }, - contactOwner: { - legalName: 'example_first_name', - displayName: contactDisplayName, - cocNumber: 'example_coc_number', - }, - } - const contact1Entity: ContactEntity = contactEntityFrom(contact1) - await dbConnection.getRepository(ContactEntity).save(contact1Entity) - - const contact2: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.ORGANIZATION, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - legalName: 'example_first_name', - displayName: contactDisplayName, - cocNumber: 'example_coc_number', - }, - } - const contact2Entity: ContactEntity = contactEntityFrom(contact2) - - await expect(dbConnection.getRepository(ContactEntity).save(contact2Entity)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: contact_type_entity.name' - ) - }) - - it('Should enforce unique alias for an identity', async (): Promise => { - const alias = 'non_unique_alias' - const identity1: IBasicIdentity = { - alias, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId: 'unique_correlationId1', - }, - } - const identity1Entity: IdentityEntity = identityEntityFrom(identity1) - await dbConnection.getRepository(IdentityEntity).save(identity1Entity) - - const identity2: IBasicIdentity = { - alias: alias, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId: 'unique_correlationId2', - }, - } - const identity2Entity: IdentityEntity = identityEntityFrom(identity2) - await expect(dbConnection.getRepository(IdentityEntity).save(identity2Entity)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: Identity.alias' - ) - }) - - it('Should enforce unique correlationId for a identity', async (): Promise => { - const correlationId = 'non_unique_correlationId' - const identity1: IBasicIdentity = { - alias: 'unique_alias1', - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId, - }, - } - const identity1Entity: IdentityEntity = identityEntityFrom(identity1) - await dbConnection.getRepository(IdentityEntity).save(identity1Entity) - - const identity2: IBasicIdentity = { - alias: 'unique_alias2', - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId, - }, - } - const identity2Entity: IdentityEntity = identityEntityFrom(identity2) - await expect(dbConnection.getRepository(IdentityEntity).save(identity2Entity)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: CorrelationIdentifier.correlation_id' - ) - }) - - it('Should save identity to database', async (): Promise => { - const correlationId = 'example_did' - const identity: IBasicIdentity = { - alias: correlationId, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId, - }, - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - - await dbConnection.getRepository(IdentityEntity).save(identityEntity) - - const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ - where: { - identifier: { - correlationId, - }, - }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.connection).toBeNull() - expect(fromDb?.identifier).toBeDefined() - expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) - expect(fromDb?.identifier.type).toEqual(identity.identifier.type) - }) - - it('should throw error when saving identity with blank alias', async (): Promise => { - const identity: IBasicIdentity = { - alias: '', - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId: 'example_did', - }, - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - - await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank aliases are not allowed') - }) - - it('should throw error when saving identity with blank correlation id', async (): Promise => { - const identity: IBasicIdentity = { - alias: 'example_did', - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId: '', - }, - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - - await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank correlation ids are not allowed') - }) - - it('should throw error when saving identity with blank metadata label', async (): Promise => { - const correlationId = 'example_did' - const identity: IBasicIdentity = { - alias: correlationId, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId, - }, - metadata: [ - { - label: '', - value: 'example_value', - }, - ], - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - - await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank metadata labels are not allowed') - }) - - it('should throw error when saving identity with blank metadata value', async (): Promise => { - const correlationId = 'example_did' - const identity: IBasicIdentity = { - alias: correlationId, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId, - }, - metadata: [ - { - label: 'example_label', - value: '', - }, - ], - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - - await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank metadata values are not allowed') - }) - - it('Should save identity with openid connection to database', async (): Promise => { - const correlationId = 'example.com' - const identity: IBasicIdentity = { - alias: correlationId, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.URL, - correlationId, - }, - connection: { - type: ConnectionTypeEnum.OPENID_CONNECT, - config: { - clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', - clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', - scopes: ['auth'], - issuer: 'https://example.com/app-test', - redirectUrl: 'app:/callback', - dangerouslyAllowInsecureHttpRequests: true, - clientAuthMethod: 'post', - }, - }, - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - - await dbConnection.getRepository(IdentityEntity).save(identityEntity) - - const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ - where: { - identifier: { - correlationId, - }, - }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.connection).toBeDefined() - expect(fromDb?.identifier).toBeDefined() - expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) - expect(fromDb?.identifier.type).toEqual(identity.identifier.type) - expect(fromDb?.connection?.type).toEqual(identity.connection?.type) - expect(fromDb?.connection?.config).toBeDefined() - expect((fromDb?.connection?.config).clientId).toEqual((identity.connection?.config).clientId) - }) - - it('Should save identity with didauth connection to database', async (): Promise => { - const correlationId = 'example.com' - const identity: IBasicIdentity = { - alias: correlationId, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.URL, - correlationId, - }, - connection: { - type: ConnectionTypeEnum.SIOPv2, - config: { - identifier: { - did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - provider: 'test_provider', - keys: [], - services: [], - }, - redirectUrl: 'https://example.com', - stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', - sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - }, - }, - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - - await dbConnection.getRepository(IdentityEntity).save(identityEntity) - - const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ - where: { - identifier: { - correlationId, - }, - }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.connection).toBeDefined() - expect(fromDb?.identifier).toBeDefined() - expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) - expect(fromDb?.identifier.type).toEqual(identity.identifier.type) - expect(fromDb?.connection?.type).toEqual(identity.connection?.type) - expect(fromDb?.connection?.config).toBeDefined() - expect((fromDb?.connection?.config).identifier).toEqual((identity.connection?.config).identifier.did) - }) - - it('Should save connection with openid config to database', async (): Promise => { - const connection: IBasicConnection = { - type: ConnectionTypeEnum.OPENID_CONNECT, - config: { - clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', - clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', - scopes: ['auth'], - issuer: 'https://example.com/app-test', - redirectUrl: 'app:/callback', - dangerouslyAllowInsecureHttpRequests: true, - clientAuthMethod: 'post', - }, - } - const connectionEntity: ConnectionEntity = connectionEntityFrom(connection) - await dbConnection.getRepository(ConnectionEntity).save(connectionEntity, { - transaction: true, - }) - - const fromDb: ConnectionEntity | null = await dbConnection.getRepository(ConnectionEntity).findOne({ - where: { type: connection.type }, - }) - - expect(fromDb).toBeDefined() - - const fromDbConfig: OpenIdConfigEntity | null = await dbConnection.getRepository(OpenIdConfigEntity).findOne({ - where: { id: fromDb?.id }, - }) - - expect(fromDbConfig).toBeDefined() - expect(fromDb?.type).toEqual(connection.type) - expect(fromDb?.config).toBeDefined() - expect((fromDb?.config).clientId).toEqual((connection.config).clientId) - }) - - it('Should save connection with didauth config to database', async (): Promise => { - const connection: IBasicConnection = { - type: ConnectionTypeEnum.SIOPv2, - config: { - identifier: { - did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - provider: 'test_provider', - keys: [], - services: [], - }, - redirectUrl: 'https://example.com', - stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', - sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - }, - } - const connectionEntity: ConnectionEntity = connectionEntityFrom(connection) - await dbConnection.getRepository(ConnectionEntity).save(connectionEntity, { - transaction: true, - }) - - const fromDb: ConnectionEntity | null = await dbConnection.getRepository(ConnectionEntity).findOne({ - where: { type: connection.type }, - }) - - expect(fromDb).toBeDefined() - - const fromDbConfig: DidAuthConfigEntity | null = await dbConnection.getRepository(DidAuthConfigEntity).findOne({ - where: { id: fromDb?.id }, - }) - - expect(fromDbConfig).toBeDefined() - expect(fromDb?.type).toEqual(connection.type) - expect(fromDb?.config).toBeDefined() - expect((fromDb?.config).identifier).toEqual((connection.config).identifier.did) - }) - - it('Should save openid config to database', async (): Promise => { - const clientId = '138d7bf8-c930-4c6e-b928-97d3a4928b01' - const config: BasicOpenIdConfig = { - clientId, - clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', - scopes: ['auth'], - issuer: 'https://example.com/app-test', - redirectUrl: 'app:/callback', - dangerouslyAllowInsecureHttpRequests: true, - clientAuthMethod: 'post', - } - - const configEntity: OpenIdConfigEntity = openIdConfigEntityFrom(config) - await dbConnection.getRepository(OpenIdConfigEntity).save(configEntity, { - transaction: true, - }) - - const fromDb: OpenIdConfigEntity | null = await dbConnection.getRepository(OpenIdConfigEntity).findOne({ - where: { clientId: config.clientId }, - }) - - expect(fromDb).toBeDefined() - expect((fromDb).clientId).toEqual(config.clientId) - }) - - it('Should save didauth config to database', async (): Promise => { - const sessionId = 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01' - const config: BasicDidAuthConfig = { - identifier: { - did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - provider: 'test_provider', - keys: [], - services: [], - }, - redirectUrl: 'https://example.com', - stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', - sessionId, - } - - const configEntity: DidAuthConfigEntity = didAuthConfigEntityFrom(config) - await dbConnection.getRepository(DidAuthConfigEntity).save(configEntity, { - transaction: true, - }) - - const fromDb: DidAuthConfigEntity | null = await dbConnection.getRepository(DidAuthConfigEntity).findOne({ - where: { sessionId: config.sessionId }, - }) - - expect(fromDb).toBeDefined() - expect((fromDb).identifier).toEqual(config.identifier.did) - }) - - it('Should delete contact and all child relations', async (): Promise => { - const contact1: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name1', - }, - contactOwner: { - firstName: 'example_first_name1', - middleName: 'example_middle_name1', - lastName: 'example_last_name1', - displayName: 'example_display_name1', - }, - } - - const contactEntity1: ContactEntity = contactEntityFrom(contact1) - const savedContact1: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity1) - - expect(savedContact1).toBeDefined() - - const contact2: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - name: 'example_name2', - }, - contactOwner: { - firstName: 'example_first_name2', - middleName: 'example_middle_name2', - lastName: 'example_last_name2', - displayName: 'example_display_name2', - }, - } - - const contactEntity2: ContactEntity = contactEntityFrom(contact2) - const savedContact2: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity2) - - expect(savedContact2).toBeDefined() - - const correlationId = 'relation_example.com' - const identity: IBasicIdentity = { - alias: correlationId, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.URL, - correlationId, - }, - connection: { - type: ConnectionTypeEnum.OPENID_CONNECT, - config: { - clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', - clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', - scopes: ['auth'], - issuer: 'https://example.com/app-test', - redirectUrl: 'app:/callback', - dangerouslyAllowInsecureHttpRequests: true, - clientAuthMethod: 'post', - }, - }, - metadata: [ - { - label: 'example_label', - value: 'example_value', - }, - ], - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - identityEntity.contact = savedContact1 - - const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) - - expect(savedIdentity).toBeDefined() - - const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ - left: savedContact1, - right: savedContact2, - }) - - const savedRelationship: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { - transaction: true, - }) - - expect(savedRelationship).toBeDefined() - - expect( - await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: savedContact1.id }, - }) - ).toBeDefined() - - await dbConnection.getRepository(ContactEntity).delete({ id: savedContact1.id }) - - // check contact - await expect( - await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: savedContact1.id }, - }) - ).toBeNull() - - // check identity - expect( - await dbConnection.getRepository(IdentityEntity).findOne({ - where: { id: savedContact1.id }, - }) - ).toBeNull() - - // check identity identifier - expect( - await dbConnection.getRepository(CorrelationIdentifierEntity).findOne({ - where: { id: savedIdentity.identifier.id }, - }) - ).toBeNull() - - // check identity connection - expect( - await dbConnection.getRepository(ConnectionEntity).findOne({ - where: { id: savedIdentity.connection!.id }, - }) - ).toBeNull() - - // check connection config - expect( - await dbConnection.getRepository(OpenIdConfigEntity).findOne({ - where: { id: savedIdentity.connection!.config.id }, - }) - ).toBeNull() - - // check identity metadata - expect( - await dbConnection.getRepository(IdentityMetadataItemEntity).findOne({ - where: { id: savedIdentity.metadata![0].id }, - }) - ).toBeNull() - - // check contact owner - expect( - await dbConnection.getRepository(ContactOwnerEntity).findOne({ - where: { id: savedContact1.contactOwner.id }, - }) - ).toBeNull() - - // check contact type - expect( - await dbConnection.getRepository(ContactTypeEntity).findOne({ - where: { id: savedContact1.contactType.id }, - }) - ).toBeDefined() - - // check relation - expect( - await dbConnection.getRepository(ContactRelationshipEntity).findOne({ - where: { id: savedRelationship.id }, - }) - ).toBeNull() - }) - - it('Should delete identity and all child relations', async (): Promise => { - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) - - expect(savedContact).toBeDefined() - - const correlationId = 'relation_example.com' - const identity: IBasicIdentity = { - alias: correlationId, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.URL, - correlationId, - }, - connection: { - type: ConnectionTypeEnum.SIOPv2, - config: { - identifier: { - did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - provider: 'test_provider', - keys: [], - services: [], - }, - redirectUrl: 'https://example.com', - stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', - sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - }, - }, - metadata: [ - { - label: 'example_label', - value: 'example_value', - }, - ], - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - identityEntity.contact = savedContact - - const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) - - expect( - await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: savedContact.id }, - }) - ).toBeDefined() - - await dbConnection.getRepository(IdentityEntity).delete({ id: savedIdentity.id }) - - // check identity - expect( - await dbConnection.getRepository(IdentityEntity).findOne({ - where: { alias: correlationId }, - }) - ).toBeNull() - - // check identity identifier - expect( - await dbConnection.getRepository(CorrelationIdentifierEntity).findOne({ - where: { id: savedIdentity.identifier.id }, - }) - ).toBeNull() - - // check identity connection - expect( - await dbConnection.getRepository(ConnectionEntity).findOne({ - where: { id: savedIdentity.connection!.id }, - }) - ).toBeNull() - - // check connection config - expect( - await dbConnection.getRepository(OpenIdConfigEntity).findOne({ - where: { id: savedIdentity.connection!.config.id }, - }) - ).toBeNull() - - // check identity metadata - expect( - await dbConnection.getRepository(IdentityMetadataItemEntity).findOne({ - where: { id: savedIdentity.metadata![0].id }, - }) - ).toBeNull() - }) - - it('Should not delete contact when deleting identity', async (): Promise => { - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) - - expect(savedContact).toBeDefined() - - const correlationId = 'relation_example.com' - const identity: IBasicIdentity = { - alias: correlationId, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.URL, - correlationId, - }, - connection: { - type: ConnectionTypeEnum.SIOPv2, - config: { - identifier: { - did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - provider: 'test_provider', - keys: [], - services: [], - }, - redirectUrl: 'https://example.com', - stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', - sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - }, - }, - metadata: [ - { - label: 'example_label', - value: 'example_value', - }, - ], - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - identityEntity.contact = savedContact - - const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) - - expect(savedIdentity).toBeDefined() - - await dbConnection.getRepository(IdentityEntity).delete({ id: savedIdentity.id }) - - // check identity - expect( - await dbConnection.getRepository(IdentityEntity).findOne({ - where: { id: savedIdentity.id }, - }) - ).toBeNull() - - // check contact - expect( - await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: savedContact.id }, - }) - ).toBeDefined() - }) - - it('Should set creation date when saving contact', async (): Promise => { - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) - - const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: savedContact.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.createdAt).toBeDefined() - }) - - it('Should not update creation date when updating contact', async (): Promise => { - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) - - expect(savedContact).toBeDefined() - - const newContactFirstName = 'new_first_name' - await dbConnection.getRepository(ContactEntity).save({ - ...savedContact, - contactOwner: { - ...savedContact.contactOwner, - firstName: newContactFirstName, - }, - }) - - const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: savedContact.id }, - }) - - expect(fromDb).toBeDefined() - expect((fromDb?.contactOwner).firstName).toEqual(newContactFirstName) - expect(fromDb?.createdAt).toEqual(savedContact?.createdAt) - }) - - it('Should set creation date when saving identity', async (): Promise => { - const correlationId = 'example_did' - const identity: IBasicIdentity = { - alias: correlationId, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId, - }, - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - await dbConnection.getRepository(IdentityEntity).save(identityEntity) - - const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ - where: { - identifier: { - correlationId, - }, - }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.createdAt).toBeDefined() - }) - - it('Should not update creation date when saving identity', async (): Promise => { - const correlationId = 'example_did' - const identity: IBasicIdentity = { - alias: correlationId, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId, - }, - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) - const newCorrelationId = 'new_example_did' - await dbConnection - .getRepository(IdentityEntity) - .save({ ...savedIdentity, identifier: { ...savedIdentity.identifier, correlationId: newCorrelationId } }) - - const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ - where: { - identifier: { - correlationId: newCorrelationId, - }, - }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.createdAt).toEqual(savedIdentity?.createdAt) - }) - - it('Should set last updated date when saving contact', async (): Promise => { - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) - - const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: savedContact.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.lastUpdatedAt).toBeDefined() - }) - - // TODO there is still an issue when updating nested objects, the parent does not update - it('Should update last updated date when updating contact', async (): Promise => { - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) - - expect(savedContact).toBeDefined() - - // waiting here to get a different timestamp - await new Promise((resolve) => setTimeout(resolve, 2000)) - - const newContactFirstName = 'new_first_name' - await dbConnection.getRepository(ContactEntity).save({ - ...savedContact, - uri: 'new uri', // TODO remove this to trigger the bug - contactOwner: { - ...savedContact.contactOwner, - firstName: newContactFirstName, - }, - }) - - const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: savedContact.id }, - }) - - expect(fromDb).toBeDefined() - expect((fromDb?.contactOwner).firstName).toEqual(newContactFirstName) - expect(fromDb?.lastUpdatedAt).not.toEqual(savedContact?.lastUpdatedAt) - }) - - it('Should set last updated date when saving contact type', async (): Promise => { - const contactType: BasicContactType = { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - } - - const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) - const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) - - const fromDb: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).findOne({ - where: { id: savedContactType.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.lastUpdatedAt).toBeDefined() - }) - - it('Should set last creation date when saving contact type', async (): Promise => { - const contactType: BasicContactType = { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - } - - const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) - const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) - - const fromDb: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).findOne({ - where: { id: savedContactType.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.createdAt).toBeDefined() - }) - - it('Should set last updated date when saving identity', async (): Promise => { - const correlationId = 'example_did' - const identity: IBasicIdentity = { - alias: correlationId, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId, - }, - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - await dbConnection.getRepository(IdentityEntity).save(identityEntity) - - const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ - where: { - identifier: { - correlationId, - }, - }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.lastUpdatedAt).toBeDefined() - }) - - it('Should enforce unique type and tenant id combination when saving contact type', async (): Promise => { - const tenantId = 'non_unique_value' - const name = 'non_unique_value' - const contactType1: BasicContactType = { - type: ContactTypeEnum.PERSON, - tenantId, - name, - } - - const contactTypeEntity1: ContactTypeEntity = contactTypeEntityFrom(contactType1) - const savedContactType1: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity1) - - expect(savedContactType1).toBeDefined() - - const contactType2: BasicContactType = { - type: ContactTypeEnum.PERSON, - tenantId, - name, - } - - const contactTypeEntity2: ContactTypeEntity = contactTypeEntityFrom(contactType2) - await expect(dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity2)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: contact_type_entity.type, contact_type_entity.tenantId' - ) - }) - - it('Should enforce unique name when saving contact type', async (): Promise => { - const name = 'non_unique_value' - const contactType1: BasicContactType = { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name, - } - - const contactTypeEntity1: ContactTypeEntity = contactTypeEntityFrom(contactType1) - const savedContactType1: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity1) - - expect(savedContactType1).toBeDefined() - - const contactType2: BasicContactType = { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - name, - } - - const contactTypeEntity2: ContactTypeEntity = contactTypeEntityFrom(contactType2) - await expect(dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity2)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: contact_type_entity.name' - ) - }) - - it('Should enforce unique legal name when saving organization', async (): Promise => { - const legalName = 'non_unique_value' - const organization1: BasicOrganization = { - legalName, - displayName: 'example_display_name', - } - - const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) - const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { - transaction: true, - }) - - expect(savedOrganization1).toBeDefined() - - const organization2: BasicOrganization = { - legalName, - displayName: 'example_display_name', - } - - const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) - await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.legalName' - ) - }) - - it('Should enforce unique display name when saving organization', async (): Promise => { - const displayName = 'non_unique_value' - const organization1: BasicOrganization = { - legalName: 'example_legal_name1', - displayName, - } - - const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) - const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { - transaction: true, - }) - - expect(savedOrganization1).toBeDefined() - - const organization2: BasicOrganization = { - legalName: 'example_legal_name2', - displayName, - } - - const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) - await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.displayName' - ) - }) - - it('Should enforce unique legal name when saving organization', async (): Promise => { - const legalName = 'example_legal_name' - const organization1: BasicOrganization = { - legalName, - displayName: 'example_display_name', - } - - const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) - const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { - transaction: true, - }) - - expect(savedOrganization1).toBeDefined() - - const organization2: BasicOrganization = { - legalName, - displayName: 'example_display_name', - } - - const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) - await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.legalName' - ) - }) - - it('Should enforce unique coc number when saving organization per tenant id', async (): Promise => { - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.ORGANIZATION, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - legalName: 'example_legal_name', - displayName: 'example_display_name', - cocNumber: 'example_coc_number', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - await dbConnection.getRepository(ContactEntity).save(contactEntity, { - transaction: true, - }) - - const contact2: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name2', - }, - contactOwner: { - legalName: 'example_legal_name2', - displayName: 'example_display_name2', - cocNumber: 'example_coc_number', - }, - } - - const contactEntity2: ContactEntity = contactEntityFrom(contact2) - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity2, { transaction: true })).rejects.toThrowError( - 'Coc number already in use' - ) - }) - - it('Should enforce unique display name when saving person', async (): Promise => { - const displayName = 'non_unique_value' - const person1: BasicPerson = { - firstName: 'example_first_name1', - lastName: 'lastName2', - displayName, - } - - const personEntity1: PersonEntity = personEntityFrom(person1) - const savedPerson1: PersonEntity | null = await dbConnection.getRepository(PersonEntity).save(personEntity1, { - transaction: true, - }) - - expect(savedPerson1).toBeDefined() - - const person2: BasicPerson = { - firstName: 'example_first_name2', - lastName: 'lastName2', - displayName, - } - - const personEntity2: PersonEntity = personEntityFrom(person2) - await expect(dbConnection.getRepository(PersonEntity).save(personEntity2)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.displayName' - ) - }) - - it('Should save contact relationship to database', async (): Promise => { - const contact1: IBasicContact = { - uri: 'example1.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name1', - }, - contactOwner: { - firstName: 'example_first_name1', - middleName: 'example_middle_name1', - lastName: 'example_last_name1', - displayName: 'example_display_name1', - }, - } - - const contactEntity1: ContactEntity = contactEntityFrom(contact1) - const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { - transaction: true, - }) - - expect(savedContact1).toBeDefined() - - const contact2: IBasicContact = { - uri: 'example2.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - name: 'example_name2', - }, - contactOwner: { - firstName: 'example_first_name2', - middleName: 'example_middle_name2', - lastName: 'example_last_name2', - displayName: 'example_display_name2', - }, - } - - const contactEntity2: ContactEntity = contactEntityFrom(contact2) - const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { - transaction: true, - }) - - expect(savedContact2).toBeDefined() - - const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ - left: savedContact1, - right: savedContact2, - }) - - await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { - transaction: true, - }) - - // TODO check the relation field - const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: contactEntity1.id }, - }) - - expect(fromDb).toBeDefined() - }) - - it('Should set last updated date when saving contact relationship', async (): Promise => { - const contact1: IBasicContact = { - uri: 'example1.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name1', - }, - contactOwner: { - firstName: 'example_first_name1', - middleName: 'example_middle_name1', - lastName: 'example_last_name1', - displayName: 'example_display_name1', - }, - } - - const contactEntity1: ContactEntity = contactEntityFrom(contact1) - const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { - transaction: true, - }) - - const contact2: IBasicContact = { - uri: 'example2.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - name: 'example_name2', - }, - contactOwner: { - firstName: 'example_first_name2', - middleName: 'example_middle_name2', - lastName: 'example_last_name2', - displayName: 'example_display_name2', - }, - } - - const contactEntity2: ContactEntity = contactEntityFrom(contact2) - const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { - transaction: true, - }) - - const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ - left: savedContact1, - right: savedContact2, - }) - - await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { - transaction: true, - }) - - const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: contactEntity1.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.lastUpdatedAt).toBeDefined() - }) - - it('Should set creation date when saving contact relationship', async (): Promise => { - const contact1: IBasicContact = { - uri: 'example1.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name1', - }, - contactOwner: { - firstName: 'example_first_name1', - middleName: 'example_middle_name1', - lastName: 'example_last_name1', - displayName: 'example_display_name1', - }, - } - - const contactEntity1: ContactEntity = contactEntityFrom(contact1) - const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { - transaction: true, - }) - - const contact2: IBasicContact = { - uri: 'example2.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - name: 'example_name2', - }, - contactOwner: { - firstName: 'example_first_name2', - middleName: 'example_middle_name2', - lastName: 'example_last_name2', - displayName: 'example_display_name2', - }, - } - - const contactEntity2: ContactEntity = contactEntityFrom(contact2) - const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { - transaction: true, - }) - - const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ - left: savedContact1, - right: savedContact2, - }) - - await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { - transaction: true, - }) - - const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: contactEntity1.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.createdAt).toBeDefined() - }) - - it('Should save bidirectional contact relationships to database', async (): Promise => { - const contact1: IBasicContact = { - uri: 'example1.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name1', - }, - contactOwner: { - firstName: 'example_first_name1', - middleName: 'example_middle_name1', - lastName: 'example_last_name1', - displayName: 'example_display_name1', - }, - } - - const contactEntity1: ContactEntity = contactEntityFrom(contact1) - const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { - transaction: true, - }) - - expect(savedContact1).toBeDefined() - - const contact2: IBasicContact = { - uri: 'example2.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - name: 'example_name2', - }, - contactOwner: { - firstName: 'example_first_name2', - middleName: 'example_middle_name2', - lastName: 'example_last_name2', - displayName: 'example_display_name2', - }, - } - - const contactEntity2: ContactEntity = contactEntityFrom(contact2) - const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { - transaction: true, - }) - - expect(savedContact2).toBeDefined() - - const relationship1: ContactRelationshipEntity = contactRelationshipEntityFrom({ - left: savedContact1, - right: savedContact2, - }) - - const savedRelationship1: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship1, { - transaction: true, - }) - - expect(savedRelationship1).toBeDefined() - - const relationship2: ContactRelationshipEntity = contactRelationshipEntityFrom({ - left: savedContact2, - right: savedContact1, - }) - - const savedRelationship2: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship2, { - transaction: true, - }) - - expect(savedRelationship2).toBeDefined() - - const fromDb: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).findOne({ - where: { id: savedRelationship2.id }, - }) - - expect(fromDb).toBeDefined() - }) - - it('Should enforce unique owner combination for contact relationship', async (): Promise => { - const contact1: IBasicContact = { - uri: 'example1.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name1', - }, - contactOwner: { - firstName: 'example_first_name1', - middleName: 'example_middle_name1', - lastName: 'example_last_name1', - displayName: 'example_display_name1', - }, - } - - const contactEntity1: ContactEntity = contactEntityFrom(contact1) - const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { - transaction: true, - }) - - expect(savedContact1).toBeDefined() - - const contact2: IBasicContact = { - uri: 'example2.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - name: 'example_name2', - }, - contactOwner: { - firstName: 'example_first_name2', - middleName: 'example_middle_name2', - lastName: 'example_last_name2', - displayName: 'example_display_name2', - }, - } - - const contactEntity2: ContactEntity = contactEntityFrom(contact2) - const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { - transaction: true, - }) - - expect(savedContact2).toBeDefined() - - const relationship1: ContactRelationshipEntity = contactRelationshipEntityFrom({ - left: savedContact1, - right: savedContact2, - }) - - const savedRelationship1: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship1, { - transaction: true, - }) - - expect(savedRelationship1).toBeDefined() - - const relationship2: ContactRelationshipEntity = contactRelationshipEntityFrom({ - left: savedContact1, - right: savedContact2, - }) - - await expect(dbConnection.getRepository(ContactRelationshipEntity).save(relationship2)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: contact_relationship_entity.leftId, contact_relationship_entity.rightId' - ) - }) - - it('Should save contact type to database', async (): Promise => { - const contactType: BasicContactType = { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - } - - const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) - const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) - - const fromDb: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).findOne({ - where: { id: savedContactType.id }, - }) - - expect(fromDb).toBeDefined() - }) - - it('Should save person to database', async (): Promise => { - const person: BasicPerson = { - firstName: 'example_first_name', - lastName: 'lastName2', - displayName: 'displayName', - } - - const personEntity: PersonEntity = personEntityFrom(person) - const savedPerson: PersonEntity | null = await dbConnection.getRepository(PersonEntity).save(personEntity, { - transaction: true, - }) - - const fromDb: PersonEntity | null = await dbConnection.getRepository(PersonEntity).findOne({ - where: { id: savedPerson.id }, - }) - - expect(fromDb).toBeDefined() - }) - - it('Should set last updated date when saving person', async (): Promise => { - const person: BasicPerson = { - firstName: 'example_first_name', - lastName: 'lastName2', - displayName: 'displayName', - } - - const personEntity: PersonEntity = personEntityFrom(person) - const savedPerson: PersonEntity | null = await dbConnection.getRepository(PersonEntity).save(personEntity, { - transaction: true, - }) - - const fromDb: PersonEntity | null = await dbConnection.getRepository(PersonEntity).findOne({ - where: { id: savedPerson.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.lastUpdatedAt).toBeDefined() - }) - - it('Should set creation date when saving person', async (): Promise => { - const person: BasicPerson = { - firstName: 'example_first_name', - lastName: 'lastName2', - displayName: 'displayName', - } - - const personEntity: PersonEntity = personEntityFrom(person) - const savedPerson: PersonEntity | null = await dbConnection.getRepository(PersonEntity).save(personEntity, { - transaction: true, - }) - - const fromDb: PersonEntity | null = await dbConnection.getRepository(PersonEntity).findOne({ - where: { id: savedPerson.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.createdAt).toBeDefined() - }) - - it('Should save organization to database', async (): Promise => { - const organization: BasicOrganization = { - legalName: 'example_legal_name', - displayName: 'example_display_name', - } - - const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) - const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { - transaction: true, - }) - - const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ - where: { id: savedOrganization.id }, - }) - - expect(fromDb).toBeDefined() - }) - - it('Should set last updated date when saving organization', async (): Promise => { - const organization: BasicOrganization = { - legalName: 'example_legal_name', - displayName: 'example_display_name', - } - - const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) - const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { - transaction: true, - }) - - const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ - where: { id: savedOrganization.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.lastUpdatedAt).toBeDefined() - }) - - it('Should set creation date when saving organization', async (): Promise => { - const organization: BasicOrganization = { - legalName: 'example_legal_name', - displayName: 'example_display_name', - } - - const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) - const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { - transaction: true, - }) - - const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ - where: { id: savedOrganization.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.createdAt).toBeDefined() - }) - - it('Should get contact based on person information', async (): Promise => { - const firstName = 'example_first_name' - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - firstName, - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - await dbConnection.getRepository(ContactEntity).save(contactEntity, { - transaction: true, - }) - - const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { - contactOwner: { - firstName, - } as FindOptionsWhere, - }, - }) - - expect(fromDb).toBeDefined() - }) - - it('Should get contact based on organization information', async (): Promise => { - const legalName = 'example_legal_name' - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.ORGANIZATION, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - legalName, - displayName: 'example_display_name', - cocNumber: 'example_coc_number', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - await dbConnection.getRepository(ContactEntity).save(contactEntity, { - transaction: true, - }) - - const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { - contactOwner: { - legalName, - } as FindOptionsWhere, - }, - }) - - expect(fromDb).toBeDefined() - }) - - it("Should enforce unique contact id's for relationship sides", async (): Promise => { - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - const savedContact: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity, { - transaction: true, - }) - - expect(savedContact).toBeDefined() - - const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ - left: savedContact, - right: savedContact, - }) - - await expect(dbConnection.getRepository(ContactRelationshipEntity).save(relationship)).rejects.toThrowError( - 'Cannot use the same id for both sides of the relationship' - ) - }) - - it('Should delete contact relationship', async (): Promise => { - const contact1: IBasicContact = { - uri: 'example1.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name1', - }, - contactOwner: { - firstName: 'example_first_name1', - middleName: 'example_middle_name1', - lastName: 'example_last_name1', - displayName: 'example_display_name1', - }, - } - - const contactEntity1: ContactEntity = contactEntityFrom(contact1) - const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { - transaction: true, - }) - - expect(savedContact1).toBeDefined() - - const contact2: IBasicContact = { - uri: 'example2.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - name: 'example_name2', - }, - contactOwner: { - firstName: 'example_first_name2', - middleName: 'example_middle_name2', - lastName: 'example_last_name2', - displayName: 'example_display_name2', - }, - } - - const contactEntity2: ContactEntity = contactEntityFrom(contact2) - const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { - transaction: true, - }) - - expect(savedContact2).toBeDefined() - - const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ - left: savedContact1, - right: savedContact2, - }) - - const savedRelationship: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { - transaction: true, - }) - - expect(savedRelationship).toBeDefined() - - await dbConnection.getRepository(ContactRelationshipEntity).delete({ id: savedRelationship.id }) - - await expect( - await dbConnection.getRepository(ContactRelationshipEntity).findOne({ - where: { id: savedRelationship.id }, - }) - ).toBeNull() - }) - - it('Should delete contact type', async (): Promise => { - const contactType: BasicContactType = { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - } - - const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) - const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) - - expect(savedContactType).toBeDefined() - - await dbConnection.getRepository(ContactTypeEntity).delete({ id: savedContactType.id }) - - await expect( - await dbConnection.getRepository(ContactTypeEntity).findOne({ - where: { id: savedContactType.id }, - }) - ).toBeNull() - }) - - it('Should not be able to remove contact type when used by contacts', async (): Promise => { - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity, { - transaction: true, - }) - - expect(savedContact).toBeDefined() - - await expect(dbConnection.getRepository(ContactTypeEntity).delete({ id: savedContact.contactType.id })).rejects.toThrowError( - 'FOREIGN KEY constraint failed' - ) - }) - - it('Should save contact with existing contact type', async (): Promise => { - const contactType: BasicContactType = { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - } - - const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) - const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) - - const contact: IBasicContact = { - uri: 'example.com', - contactType: savedContactType, - contactOwner: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - contactEntity.contactType = savedContactType - await dbConnection.getRepository(ContactEntity).save(contactEntity, { - transaction: true, - }) - - const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: contactEntity.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.contactType).toBeDefined() - expect(fromDb?.contactType.id).toEqual(savedContactType.id) - expect(fromDb?.contactType.type).toEqual(savedContactType.type) - expect(fromDb?.contactType.tenantId).toEqual(savedContactType.tenantId) - expect(fromDb?.contactType.name).toEqual(savedContactType.name) - }) - - // TODO not update creation date when saving contact type - // TODO add test for updating nested field and checking last updated at on parent + // + // it('Should save organization contact to database', async (): Promise => { + // const contact: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.ORGANIZATION, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contactOwner: { + // legalName: 'example_legal_name', + // displayName: 'example_display_name', + // cocNumber: 'example_coc_number', + // }, + // } + // + // const contactEntity: ContactEntity = contactEntityFrom(contact) + // await dbConnection.getRepository(ContactEntity).save(contactEntity, { + // transaction: true, + // }) + // + // const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + // where: { id: contactEntity.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.identities?.length).toEqual(0) + // expect(fromDb?.uri).toEqual(contact.uri) + // expect(fromDb?.contactType).toBeDefined() + // expect(fromDb?.contactType.type).toEqual(contact.contactType.type) + // expect(fromDb?.contactType.tenantId).toEqual(contact.contactType.tenantId) + // expect(fromDb?.contactType.name).toEqual(contact.contactType.name) + // expect(fromDb?.contactOwner).toBeDefined() + // expect((fromDb?.contactOwner).legalName).toEqual((contact.contactOwner).legalName) + // expect((fromDb?.contactOwner).displayName).toEqual((contact.contactOwner).displayName) + // expect((fromDb?.contactOwner).cocNumber).toEqual((contact.contactOwner).cocNumber) + // }) + // + // it('Should result in contact relationship for the owner side only', async (): Promise => { + // const contact1: IBasicContact = { + // uri: 'example1.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name1', + // }, + // contactOwner: { + // firstName: 'example_first_name1', + // middleName: 'example_middle_name1', + // lastName: 'example_last_name1', + // displayName: 'example_display_name1', + // }, + // } + // + // const contactEntity1: ContactEntity = contactEntityFrom(contact1) + // const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + // transaction: true, + // }) + // + // const contact2: IBasicContact = { + // uri: 'example2.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + // name: 'example_name2', + // }, + // contactOwner: { + // firstName: 'example_first_name2', + // middleName: 'example_middle_name2', + // lastName: 'example_last_name2', + // displayName: 'example_display_name2', + // }, + // } + // + // const contactEntity2: ContactEntity = contactEntityFrom(contact2) + // const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + // transaction: true, + // }) + // + // const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ + // left: savedContact1, + // right: savedContact2, + // }) + // + // await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { + // transaction: true, + // }) + // + // const fromDb1: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + // where: { id: savedContact1.id }, + // }) + // + // const fromDb2: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + // where: { id: savedContact2.id }, + // }) + // + // expect(fromDb1).toBeDefined() + // expect(fromDb1?.relationships.length).toEqual(1) + // expect(fromDb2).toBeDefined() + // expect(fromDb2?.relationships.length).toEqual(0) + // }) + // + // it('should throw error when saving person contact with blank first name', async (): Promise => { + // const contact: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contactOwner: { + // firstName: '', + // middleName: 'example_middle_name1', + // lastName: 'example_last_name1', + // displayName: 'example_display_name1', + // }, + // } + // + // const contactEntity: ContactEntity = contactEntityFrom(contact) + // + // await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank first names are not allowed') + // }) + // + // it('should throw error when saving person contact with blank middle name', async (): Promise => { + // const contact: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contactOwner: { + // firstName: 'example_first_name', + // middleName: '', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const contactEntity: ContactEntity = contactEntityFrom(contact) + // + // await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank middle names are not allowed') + // }) + // + // it('should throw error when saving person contact with blank last name', async (): Promise => { + // const contact: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contactOwner: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: '', + // displayName: 'example_display_name', + // }, + // } + // + // const contactEntity: ContactEntity = contactEntityFrom(contact) + // + // await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank last names are not allowed') + // }) + // + // it('should throw error when saving person contact with blank display name', async (): Promise => { + // const contact: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contactOwner: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: '', + // }, + // } + // + // const contactEntity: ContactEntity = contactEntityFrom(contact) + // + // await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank display names are not allowed') + // }) + // + // it('should throw error when saving organization contact with blank legal name', async (): Promise => { + // const contact: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.ORGANIZATION, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contactOwner: { + // legalName: '', + // displayName: 'example_legal_name', + // cocNumber: 'example_coc_number', + // }, + // } + // + // const contactEntity: ContactEntity = contactEntityFrom(contact) + // + // await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank legal names are not allowed') + // }) + // + // it('should throw error when saving organization contact with blank display name', async (): Promise => { + // const contact: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.ORGANIZATION, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contactOwner: { + // legalName: 'example_first_name', + // displayName: '', + // cocNumber: 'example_coc_number', + // }, + // } + // + // const contactEntity: ContactEntity = contactEntityFrom(contact) + // + // await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank display names are not allowed') + // }) + // + // it('should throw error when saving organization contact with blank coc number', async (): Promise => { + // const contact: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.ORGANIZATION, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contactOwner: { + // legalName: 'example_first_name', + // displayName: 'example_display_name', + // cocNumber: '', + // }, + // } + // + // const contactEntity: ContactEntity = contactEntityFrom(contact) + // + // await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank coc numbers are not allowed') + // }) + // + // it('should throw error when saving contact with blank contact type name', async (): Promise => { + // const contact: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: '', + // }, + // contactOwner: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const contactEntity: ContactEntity = contactEntityFrom(contact) + // + // await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank names are not allowed') + // }) + // + // it('should throw error when saving contact with blank contact type description', async (): Promise => { + // const contact: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // description: '', + // }, + // contactOwner: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const contactEntity: ContactEntity = contactEntityFrom(contact) + // + // await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank descriptions are not allowed') + // }) + // + // it('should throw error when saving contact with blank contact type tenant id', async (): Promise => { + // const contact: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '', + // name: 'example_name', + // }, + // contactOwner: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const contactEntity: ContactEntity = contactEntityFrom(contact) + // + // await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError("Blank tenant id's are not allowed") + // }) + // + // it('Should enforce unique display name for a person contact', async (): Promise => { + // const contactDisplayName = 'non_unique_name' + // const contact1: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + // name: 'example_name', + // }, + // contactOwner: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: contactDisplayName, + // }, + // } + // const contact1Entity: ContactEntity = contactEntityFrom(contact1) + // await dbConnection.getRepository(ContactEntity).save(contact1Entity) + // + // const contact2: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contactOwner: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: contactDisplayName, + // }, + // } + // const contact2Entity: ContactEntity = contactEntityFrom(contact2) + // + // await expect(dbConnection.getRepository(ContactEntity).save(contact2Entity)).rejects.toThrowError( + // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: contact_type_entity.name' + // ) + // }) + // + // it('Should enforce unique display name for a organization contact', async (): Promise => { + // const contactDisplayName = 'non_unique_name' + // const contact1: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.ORGANIZATION, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + // name: 'example_name', + // }, + // contactOwner: { + // legalName: 'example_first_name', + // displayName: contactDisplayName, + // cocNumber: 'example_coc_number', + // }, + // } + // const contact1Entity: ContactEntity = contactEntityFrom(contact1) + // await dbConnection.getRepository(ContactEntity).save(contact1Entity) + // + // const contact2: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.ORGANIZATION, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contactOwner: { + // legalName: 'example_first_name', + // displayName: contactDisplayName, + // cocNumber: 'example_coc_number', + // }, + // } + // const contact2Entity: ContactEntity = contactEntityFrom(contact2) + // + // await expect(dbConnection.getRepository(ContactEntity).save(contact2Entity)).rejects.toThrowError( + // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: contact_type_entity.name' + // ) + // }) + // + // it('Should enforce unique alias for an identity', async (): Promise => { + // const alias = 'non_unique_alias' + // const identity1: IBasicIdentity = { + // alias, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId: 'unique_correlationId1', + // }, + // } + // const identity1Entity: IdentityEntity = identityEntityFrom(identity1) + // await dbConnection.getRepository(IdentityEntity).save(identity1Entity) + // + // const identity2: IBasicIdentity = { + // alias: alias, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId: 'unique_correlationId2', + // }, + // } + // const identity2Entity: IdentityEntity = identityEntityFrom(identity2) + // await expect(dbConnection.getRepository(IdentityEntity).save(identity2Entity)).rejects.toThrowError( + // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: Identity.alias' + // ) + // }) + // + // it('Should enforce unique correlationId for a identity', async (): Promise => { + // const correlationId = 'non_unique_correlationId' + // const identity1: IBasicIdentity = { + // alias: 'unique_alias1', + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId, + // }, + // } + // const identity1Entity: IdentityEntity = identityEntityFrom(identity1) + // await dbConnection.getRepository(IdentityEntity).save(identity1Entity) + // + // const identity2: IBasicIdentity = { + // alias: 'unique_alias2', + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId, + // }, + // } + // const identity2Entity: IdentityEntity = identityEntityFrom(identity2) + // await expect(dbConnection.getRepository(IdentityEntity).save(identity2Entity)).rejects.toThrowError( + // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: CorrelationIdentifier.correlation_id' + // ) + // }) + // + // it('Should save identity to database', async (): Promise => { + // const correlationId = 'example_did' + // const identity: IBasicIdentity = { + // alias: correlationId, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId, + // }, + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // + // await dbConnection.getRepository(IdentityEntity).save(identityEntity) + // + // const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ + // where: { + // identifier: { + // correlationId, + // }, + // }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.connection).toBeNull() + // expect(fromDb?.identifier).toBeDefined() + // expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) + // expect(fromDb?.identifier.type).toEqual(identity.identifier.type) + // }) + // + // it('should throw error when saving identity with blank alias', async (): Promise => { + // const identity: IBasicIdentity = { + // alias: '', + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId: 'example_did', + // }, + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // + // await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank aliases are not allowed') + // }) + // + // it('should throw error when saving identity with blank correlation id', async (): Promise => { + // const identity: IBasicIdentity = { + // alias: 'example_did', + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId: '', + // }, + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // + // await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank correlation ids are not allowed') + // }) + // + // it('should throw error when saving identity with blank metadata label', async (): Promise => { + // const correlationId = 'example_did' + // const identity: IBasicIdentity = { + // alias: correlationId, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId, + // }, + // metadata: [ + // { + // label: '', + // value: 'example_value', + // }, + // ], + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // + // await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank metadata labels are not allowed') + // }) + // + // it('should throw error when saving identity with blank metadata value', async (): Promise => { + // const correlationId = 'example_did' + // const identity: IBasicIdentity = { + // alias: correlationId, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId, + // }, + // metadata: [ + // { + // label: 'example_label', + // value: '', + // }, + // ], + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // + // await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank metadata values are not allowed') + // }) + // + // it('Should save identity with openid connection to database', async (): Promise => { + // const correlationId = 'example.com' + // const identity: IBasicIdentity = { + // alias: correlationId, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.URL, + // correlationId, + // }, + // connection: { + // type: ConnectionTypeEnum.OPENID_CONNECT, + // config: { + // clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', + // clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', + // scopes: ['auth'], + // issuer: 'https://example.com/app-test', + // redirectUrl: 'app:/callback', + // dangerouslyAllowInsecureHttpRequests: true, + // clientAuthMethod: 'post', + // }, + // }, + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // + // await dbConnection.getRepository(IdentityEntity).save(identityEntity) + // + // const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ + // where: { + // identifier: { + // correlationId, + // }, + // }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.connection).toBeDefined() + // expect(fromDb?.identifier).toBeDefined() + // expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) + // expect(fromDb?.identifier.type).toEqual(identity.identifier.type) + // expect(fromDb?.connection?.type).toEqual(identity.connection?.type) + // expect(fromDb?.connection?.config).toBeDefined() + // expect((fromDb?.connection?.config).clientId).toEqual((identity.connection?.config).clientId) + // }) + // + // it('Should save identity with didauth connection to database', async (): Promise => { + // const correlationId = 'example.com' + // const identity: IBasicIdentity = { + // alias: correlationId, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.URL, + // correlationId, + // }, + // connection: { + // type: ConnectionTypeEnum.SIOPv2, + // config: { + // identifier: { + // did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + // provider: 'test_provider', + // keys: [], + // services: [], + // }, + // redirectUrl: 'https://example.com', + // stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', + // sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + // }, + // }, + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // + // await dbConnection.getRepository(IdentityEntity).save(identityEntity) + // + // const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ + // where: { + // identifier: { + // correlationId, + // }, + // }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.connection).toBeDefined() + // expect(fromDb?.identifier).toBeDefined() + // expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) + // expect(fromDb?.identifier.type).toEqual(identity.identifier.type) + // expect(fromDb?.connection?.type).toEqual(identity.connection?.type) + // expect(fromDb?.connection?.config).toBeDefined() + // expect((fromDb?.connection?.config).identifier).toEqual((identity.connection?.config).identifier.did) + // }) + // + // it('Should save connection with openid config to database', async (): Promise => { + // const connection: IBasicConnection = { + // type: ConnectionTypeEnum.OPENID_CONNECT, + // config: { + // clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', + // clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', + // scopes: ['auth'], + // issuer: 'https://example.com/app-test', + // redirectUrl: 'app:/callback', + // dangerouslyAllowInsecureHttpRequests: true, + // clientAuthMethod: 'post', + // }, + // } + // const connectionEntity: ConnectionEntity = connectionEntityFrom(connection) + // await dbConnection.getRepository(ConnectionEntity).save(connectionEntity, { + // transaction: true, + // }) + // + // const fromDb: ConnectionEntity | null = await dbConnection.getRepository(ConnectionEntity).findOne({ + // where: { type: connection.type }, + // }) + // + // expect(fromDb).toBeDefined() + // + // const fromDbConfig: OpenIdConfigEntity | null = await dbConnection.getRepository(OpenIdConfigEntity).findOne({ + // where: { id: fromDb?.id }, + // }) + // + // expect(fromDbConfig).toBeDefined() + // expect(fromDb?.type).toEqual(connection.type) + // expect(fromDb?.config).toBeDefined() + // expect((fromDb?.config).clientId).toEqual((connection.config).clientId) + // }) + // + // it('Should save connection with didauth config to database', async (): Promise => { + // const connection: IBasicConnection = { + // type: ConnectionTypeEnum.SIOPv2, + // config: { + // identifier: { + // did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + // provider: 'test_provider', + // keys: [], + // services: [], + // }, + // redirectUrl: 'https://example.com', + // stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', + // sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + // }, + // } + // const connectionEntity: ConnectionEntity = connectionEntityFrom(connection) + // await dbConnection.getRepository(ConnectionEntity).save(connectionEntity, { + // transaction: true, + // }) + // + // const fromDb: ConnectionEntity | null = await dbConnection.getRepository(ConnectionEntity).findOne({ + // where: { type: connection.type }, + // }) + // + // expect(fromDb).toBeDefined() + // + // const fromDbConfig: DidAuthConfigEntity | null = await dbConnection.getRepository(DidAuthConfigEntity).findOne({ + // where: { id: fromDb?.id }, + // }) + // + // expect(fromDbConfig).toBeDefined() + // expect(fromDb?.type).toEqual(connection.type) + // expect(fromDb?.config).toBeDefined() + // expect((fromDb?.config).identifier).toEqual((connection.config).identifier.did) + // }) + // + // it('Should save openid config to database', async (): Promise => { + // const clientId = '138d7bf8-c930-4c6e-b928-97d3a4928b01' + // const config: BasicOpenIdConfig = { + // clientId, + // clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', + // scopes: ['auth'], + // issuer: 'https://example.com/app-test', + // redirectUrl: 'app:/callback', + // dangerouslyAllowInsecureHttpRequests: true, + // clientAuthMethod: 'post', + // } + // + // const configEntity: OpenIdConfigEntity = openIdConfigEntityFrom(config) + // await dbConnection.getRepository(OpenIdConfigEntity).save(configEntity, { + // transaction: true, + // }) + // + // const fromDb: OpenIdConfigEntity | null = await dbConnection.getRepository(OpenIdConfigEntity).findOne({ + // where: { clientId: config.clientId }, + // }) + // + // expect(fromDb).toBeDefined() + // expect((fromDb).clientId).toEqual(config.clientId) + // }) + // + // it('Should save didauth config to database', async (): Promise => { + // const sessionId = 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01' + // const config: BasicDidAuthConfig = { + // identifier: { + // did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + // provider: 'test_provider', + // keys: [], + // services: [], + // }, + // redirectUrl: 'https://example.com', + // stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', + // sessionId, + // } + // + // const configEntity: DidAuthConfigEntity = didAuthConfigEntityFrom(config) + // await dbConnection.getRepository(DidAuthConfigEntity).save(configEntity, { + // transaction: true, + // }) + // + // const fromDb: DidAuthConfigEntity | null = await dbConnection.getRepository(DidAuthConfigEntity).findOne({ + // where: { sessionId: config.sessionId }, + // }) + // + // expect(fromDb).toBeDefined() + // expect((fromDb).identifier).toEqual(config.identifier.did) + // }) + // + // it('Should delete contact and all child relations', async (): Promise => { + // const contact1: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name1', + // }, + // contactOwner: { + // firstName: 'example_first_name1', + // middleName: 'example_middle_name1', + // lastName: 'example_last_name1', + // displayName: 'example_display_name1', + // }, + // } + // + // const contactEntity1: ContactEntity = contactEntityFrom(contact1) + // const savedContact1: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity1) + // + // expect(savedContact1).toBeDefined() + // + // const contact2: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + // name: 'example_name2', + // }, + // contactOwner: { + // firstName: 'example_first_name2', + // middleName: 'example_middle_name2', + // lastName: 'example_last_name2', + // displayName: 'example_display_name2', + // }, + // } + // + // const contactEntity2: ContactEntity = contactEntityFrom(contact2) + // const savedContact2: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity2) + // + // expect(savedContact2).toBeDefined() + // + // const correlationId = 'relation_example.com' + // const identity: IBasicIdentity = { + // alias: correlationId, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.URL, + // correlationId, + // }, + // connection: { + // type: ConnectionTypeEnum.OPENID_CONNECT, + // config: { + // clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', + // clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', + // scopes: ['auth'], + // issuer: 'https://example.com/app-test', + // redirectUrl: 'app:/callback', + // dangerouslyAllowInsecureHttpRequests: true, + // clientAuthMethod: 'post', + // }, + // }, + // metadata: [ + // { + // label: 'example_label', + // value: 'example_value', + // }, + // ], + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // identityEntity.contact = savedContact1 + // + // const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) + // + // expect(savedIdentity).toBeDefined() + // + // const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ + // left: savedContact1, + // right: savedContact2, + // }) + // + // const savedRelationship: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { + // transaction: true, + // }) + // + // expect(savedRelationship).toBeDefined() + // + // expect( + // await dbConnection.getRepository(ContactEntity).findOne({ + // where: { id: savedContact1.id }, + // }) + // ).toBeDefined() + // + // await dbConnection.getRepository(ContactEntity).delete({ id: savedContact1.id }) + // + // // check contact + // await expect( + // await dbConnection.getRepository(ContactEntity).findOne({ + // where: { id: savedContact1.id }, + // }) + // ).toBeNull() + // + // // check identity + // expect( + // await dbConnection.getRepository(IdentityEntity).findOne({ + // where: { id: savedContact1.id }, + // }) + // ).toBeNull() + // + // // check identity identifier + // expect( + // await dbConnection.getRepository(CorrelationIdentifierEntity).findOne({ + // where: { id: savedIdentity.identifier.id }, + // }) + // ).toBeNull() + // + // // check identity connection + // expect( + // await dbConnection.getRepository(ConnectionEntity).findOne({ + // where: { id: savedIdentity.connection!.id }, + // }) + // ).toBeNull() + // + // // check connection config + // expect( + // await dbConnection.getRepository(OpenIdConfigEntity).findOne({ + // where: { id: savedIdentity.connection!.config.id }, + // }) + // ).toBeNull() + // + // // check identity metadata + // expect( + // await dbConnection.getRepository(IdentityMetadataItemEntity).findOne({ + // where: { id: savedIdentity.metadata![0].id }, + // }) + // ).toBeNull() + // + // // check contact owner + // expect( + // await dbConnection.getRepository(ContactOwnerEntity).findOne({ + // where: { id: savedContact1.contactOwner.id }, + // }) + // ).toBeNull() + // + // // check contact type + // expect( + // await dbConnection.getRepository(ContactTypeEntity).findOne({ + // where: { id: savedContact1.contactType.id }, + // }) + // ).toBeDefined() + // + // // check relation + // expect( + // await dbConnection.getRepository(ContactRelationshipEntity).findOne({ + // where: { id: savedRelationship.id }, + // }) + // ).toBeNull() + // }) + // + // it('Should delete identity and all child relations', async (): Promise => { + // const contact: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contactOwner: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const contactEntity: ContactEntity = contactEntityFrom(contact) + // const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) + // + // expect(savedContact).toBeDefined() + // + // const correlationId = 'relation_example.com' + // const identity: IBasicIdentity = { + // alias: correlationId, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.URL, + // correlationId, + // }, + // connection: { + // type: ConnectionTypeEnum.SIOPv2, + // config: { + // identifier: { + // did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + // provider: 'test_provider', + // keys: [], + // services: [], + // }, + // redirectUrl: 'https://example.com', + // stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', + // sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + // }, + // }, + // metadata: [ + // { + // label: 'example_label', + // value: 'example_value', + // }, + // ], + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // identityEntity.contact = savedContact + // + // const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) + // + // expect( + // await dbConnection.getRepository(ContactEntity).findOne({ + // where: { id: savedContact.id }, + // }) + // ).toBeDefined() + // + // await dbConnection.getRepository(IdentityEntity).delete({ id: savedIdentity.id }) + // + // // check identity + // expect( + // await dbConnection.getRepository(IdentityEntity).findOne({ + // where: { alias: correlationId }, + // }) + // ).toBeNull() + // + // // check identity identifier + // expect( + // await dbConnection.getRepository(CorrelationIdentifierEntity).findOne({ + // where: { id: savedIdentity.identifier.id }, + // }) + // ).toBeNull() + // + // // check identity connection + // expect( + // await dbConnection.getRepository(ConnectionEntity).findOne({ + // where: { id: savedIdentity.connection!.id }, + // }) + // ).toBeNull() + // + // // check connection config + // expect( + // await dbConnection.getRepository(OpenIdConfigEntity).findOne({ + // where: { id: savedIdentity.connection!.config.id }, + // }) + // ).toBeNull() + // + // // check identity metadata + // expect( + // await dbConnection.getRepository(IdentityMetadataItemEntity).findOne({ + // where: { id: savedIdentity.metadata![0].id }, + // }) + // ).toBeNull() + // }) + // + // it('Should not delete contact when deleting identity', async (): Promise => { + // const contact: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contactOwner: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const contactEntity: ContactEntity = contactEntityFrom(contact) + // const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) + // + // expect(savedContact).toBeDefined() + // + // const correlationId = 'relation_example.com' + // const identity: IBasicIdentity = { + // alias: correlationId, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.URL, + // correlationId, + // }, + // connection: { + // type: ConnectionTypeEnum.SIOPv2, + // config: { + // identifier: { + // did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + // provider: 'test_provider', + // keys: [], + // services: [], + // }, + // redirectUrl: 'https://example.com', + // stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', + // sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + // }, + // }, + // metadata: [ + // { + // label: 'example_label', + // value: 'example_value', + // }, + // ], + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // identityEntity.contact = savedContact + // + // const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) + // + // expect(savedIdentity).toBeDefined() + // + // await dbConnection.getRepository(IdentityEntity).delete({ id: savedIdentity.id }) + // + // // check identity + // expect( + // await dbConnection.getRepository(IdentityEntity).findOne({ + // where: { id: savedIdentity.id }, + // }) + // ).toBeNull() + // + // // check contact + // expect( + // await dbConnection.getRepository(ContactEntity).findOne({ + // where: { id: savedContact.id }, + // }) + // ).toBeDefined() + // }) + // + // it('Should set creation date when saving contact', async (): Promise => { + // const contact: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contactOwner: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const contactEntity: ContactEntity = contactEntityFrom(contact) + // const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) + // + // const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + // where: { id: savedContact.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.createdAt).toBeDefined() + // }) + // + // it('Should not update creation date when updating contact', async (): Promise => { + // const contact: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contactOwner: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const contactEntity: ContactEntity = contactEntityFrom(contact) + // const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) + // + // expect(savedContact).toBeDefined() + // + // const newContactFirstName = 'new_first_name' + // await dbConnection.getRepository(ContactEntity).save({ + // ...savedContact, + // contactOwner: { + // ...savedContact.contactOwner, + // firstName: newContactFirstName, + // }, + // }) + // + // const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + // where: { id: savedContact.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect((fromDb?.contactOwner).firstName).toEqual(newContactFirstName) + // expect(fromDb?.createdAt).toEqual(savedContact?.createdAt) + // }) + // + // it('Should set creation date when saving identity', async (): Promise => { + // const correlationId = 'example_did' + // const identity: IBasicIdentity = { + // alias: correlationId, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId, + // }, + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // await dbConnection.getRepository(IdentityEntity).save(identityEntity) + // + // const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ + // where: { + // identifier: { + // correlationId, + // }, + // }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.createdAt).toBeDefined() + // }) + // + // it('Should not update creation date when saving identity', async (): Promise => { + // const correlationId = 'example_did' + // const identity: IBasicIdentity = { + // alias: correlationId, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId, + // }, + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) + // const newCorrelationId = 'new_example_did' + // await dbConnection + // .getRepository(IdentityEntity) + // .save({ ...savedIdentity, identifier: { ...savedIdentity.identifier, correlationId: newCorrelationId } }) + // + // const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ + // where: { + // identifier: { + // correlationId: newCorrelationId, + // }, + // }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.createdAt).toEqual(savedIdentity?.createdAt) + // }) + // + // it('Should set last updated date when saving contact', async (): Promise => { + // const contact: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contactOwner: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const contactEntity: ContactEntity = contactEntityFrom(contact) + // const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) + // + // const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + // where: { id: savedContact.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.lastUpdatedAt).toBeDefined() + // }) + // + // // TODO there is still an issue when updating nested objects, the parent does not update + // it('Should update last updated date when updating contact', async (): Promise => { + // const contact: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contactOwner: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const contactEntity: ContactEntity = contactEntityFrom(contact) + // const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) + // + // expect(savedContact).toBeDefined() + // + // // waiting here to get a different timestamp + // await new Promise((resolve) => setTimeout(resolve, 2000)) + // + // const newContactFirstName = 'new_first_name' + // await dbConnection.getRepository(ContactEntity).save({ + // ...savedContact, + // uri: 'new uri', // TODO remove this to trigger the bug + // contactOwner: { + // ...savedContact.contactOwner, + // firstName: newContactFirstName, + // }, + // }) + // + // const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + // where: { id: savedContact.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect((fromDb?.contactOwner).firstName).toEqual(newContactFirstName) + // expect(fromDb?.lastUpdatedAt).not.toEqual(savedContact?.lastUpdatedAt) + // }) + // + // it('Should set last updated date when saving contact type', async (): Promise => { + // const contactType: BasicContactType = { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // } + // + // const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) + // const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) + // + // const fromDb: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).findOne({ + // where: { id: savedContactType.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.lastUpdatedAt).toBeDefined() + // }) + // + // it('Should set last creation date when saving contact type', async (): Promise => { + // const contactType: BasicContactType = { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // } + // + // const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) + // const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) + // + // const fromDb: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).findOne({ + // where: { id: savedContactType.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.createdAt).toBeDefined() + // }) + // + // it('Should set last updated date when saving identity', async (): Promise => { + // const correlationId = 'example_did' + // const identity: IBasicIdentity = { + // alias: correlationId, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId, + // }, + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // await dbConnection.getRepository(IdentityEntity).save(identityEntity) + // + // const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ + // where: { + // identifier: { + // correlationId, + // }, + // }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.lastUpdatedAt).toBeDefined() + // }) + // + // it('Should enforce unique type and tenant id combination when saving contact type', async (): Promise => { + // const tenantId = 'non_unique_value' + // const name = 'non_unique_value' + // const contactType1: BasicContactType = { + // type: ContactTypeEnum.PERSON, + // tenantId, + // name, + // } + // + // const contactTypeEntity1: ContactTypeEntity = contactTypeEntityFrom(contactType1) + // const savedContactType1: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity1) + // + // expect(savedContactType1).toBeDefined() + // + // const contactType2: BasicContactType = { + // type: ContactTypeEnum.PERSON, + // tenantId, + // name, + // } + // + // const contactTypeEntity2: ContactTypeEntity = contactTypeEntityFrom(contactType2) + // await expect(dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity2)).rejects.toThrowError( + // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: contact_type_entity.type, contact_type_entity.tenantId' + // ) + // }) + // + // it('Should enforce unique name when saving contact type', async (): Promise => { + // const name = 'non_unique_value' + // const contactType1: BasicContactType = { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name, + // } + // + // const contactTypeEntity1: ContactTypeEntity = contactTypeEntityFrom(contactType1) + // const savedContactType1: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity1) + // + // expect(savedContactType1).toBeDefined() + // + // const contactType2: BasicContactType = { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + // name, + // } + // + // const contactTypeEntity2: ContactTypeEntity = contactTypeEntityFrom(contactType2) + // await expect(dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity2)).rejects.toThrowError( + // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: contact_type_entity.name' + // ) + // }) + // + // it('Should enforce unique legal name when saving organization', async (): Promise => { + // const legalName = 'non_unique_value' + // const organization1: BasicOrganization = { + // legalName, + // displayName: 'example_display_name', + // } + // + // const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) + // const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { + // transaction: true, + // }) + // + // expect(savedOrganization1).toBeDefined() + // + // const organization2: BasicOrganization = { + // legalName, + // displayName: 'example_display_name', + // } + // + // const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) + // await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( + // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.legalName' + // ) + // }) + // + // it('Should enforce unique display name when saving organization', async (): Promise => { + // const displayName = 'non_unique_value' + // const organization1: BasicOrganization = { + // legalName: 'example_legal_name1', + // displayName, + // } + // + // const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) + // const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { + // transaction: true, + // }) + // + // expect(savedOrganization1).toBeDefined() + // + // const organization2: BasicOrganization = { + // legalName: 'example_legal_name2', + // displayName, + // } + // + // const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) + // await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( + // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.displayName' + // ) + // }) + // + // it('Should enforce unique legal name when saving organization', async (): Promise => { + // const legalName = 'example_legal_name' + // const organization1: BasicOrganization = { + // legalName, + // displayName: 'example_display_name', + // } + // + // const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) + // const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { + // transaction: true, + // }) + // + // expect(savedOrganization1).toBeDefined() + // + // const organization2: BasicOrganization = { + // legalName, + // displayName: 'example_display_name', + // } + // + // const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) + // await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( + // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.legalName' + // ) + // }) + // + // it('Should enforce unique coc number when saving organization per tenant id', async (): Promise => { + // const contact: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.ORGANIZATION, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contactOwner: { + // legalName: 'example_legal_name', + // displayName: 'example_display_name', + // cocNumber: 'example_coc_number', + // }, + // } + // + // const contactEntity: ContactEntity = contactEntityFrom(contact) + // await dbConnection.getRepository(ContactEntity).save(contactEntity, { + // transaction: true, + // }) + // + // const contact2: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name2', + // }, + // contactOwner: { + // legalName: 'example_legal_name2', + // displayName: 'example_display_name2', + // cocNumber: 'example_coc_number', + // }, + // } + // + // const contactEntity2: ContactEntity = contactEntityFrom(contact2) + // await expect(dbConnection.getRepository(ContactEntity).save(contactEntity2, { transaction: true })).rejects.toThrowError( + // 'Coc number already in use' + // ) + // }) + // + // it('Should enforce unique display name when saving person', async (): Promise => { + // const displayName = 'non_unique_value' + // const person1: BasicPerson = { + // firstName: 'example_first_name1', + // lastName: 'lastName2', + // displayName, + // } + // + // const personEntity1: PersonEntity = personEntityFrom(person1) + // const savedPerson1: PersonEntity | null = await dbConnection.getRepository(PersonEntity).save(personEntity1, { + // transaction: true, + // }) + // + // expect(savedPerson1).toBeDefined() + // + // const person2: BasicPerson = { + // firstName: 'example_first_name2', + // lastName: 'lastName2', + // displayName, + // } + // + // const personEntity2: PersonEntity = personEntityFrom(person2) + // await expect(dbConnection.getRepository(PersonEntity).save(personEntity2)).rejects.toThrowError( + // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.displayName' + // ) + // }) + // + // it('Should save contact relationship to database', async (): Promise => { + // const contact1: IBasicContact = { + // uri: 'example1.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name1', + // }, + // contactOwner: { + // firstName: 'example_first_name1', + // middleName: 'example_middle_name1', + // lastName: 'example_last_name1', + // displayName: 'example_display_name1', + // }, + // } + // + // const contactEntity1: ContactEntity = contactEntityFrom(contact1) + // const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + // transaction: true, + // }) + // + // expect(savedContact1).toBeDefined() + // + // const contact2: IBasicContact = { + // uri: 'example2.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + // name: 'example_name2', + // }, + // contactOwner: { + // firstName: 'example_first_name2', + // middleName: 'example_middle_name2', + // lastName: 'example_last_name2', + // displayName: 'example_display_name2', + // }, + // } + // + // const contactEntity2: ContactEntity = contactEntityFrom(contact2) + // const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + // transaction: true, + // }) + // + // expect(savedContact2).toBeDefined() + // + // const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ + // left: savedContact1, + // right: savedContact2, + // }) + // + // await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { + // transaction: true, + // }) + // + // // TODO check the relation field + // const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + // where: { id: contactEntity1.id }, + // }) + // + // expect(fromDb).toBeDefined() + // }) + // + // it('Should set last updated date when saving contact relationship', async (): Promise => { + // const contact1: IBasicContact = { + // uri: 'example1.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name1', + // }, + // contactOwner: { + // firstName: 'example_first_name1', + // middleName: 'example_middle_name1', + // lastName: 'example_last_name1', + // displayName: 'example_display_name1', + // }, + // } + // + // const contactEntity1: ContactEntity = contactEntityFrom(contact1) + // const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + // transaction: true, + // }) + // + // const contact2: IBasicContact = { + // uri: 'example2.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + // name: 'example_name2', + // }, + // contactOwner: { + // firstName: 'example_first_name2', + // middleName: 'example_middle_name2', + // lastName: 'example_last_name2', + // displayName: 'example_display_name2', + // }, + // } + // + // const contactEntity2: ContactEntity = contactEntityFrom(contact2) + // const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + // transaction: true, + // }) + // + // const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ + // left: savedContact1, + // right: savedContact2, + // }) + // + // await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { + // transaction: true, + // }) + // + // const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + // where: { id: contactEntity1.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.lastUpdatedAt).toBeDefined() + // }) + // + // it('Should set creation date when saving contact relationship', async (): Promise => { + // const contact1: IBasicContact = { + // uri: 'example1.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name1', + // }, + // contactOwner: { + // firstName: 'example_first_name1', + // middleName: 'example_middle_name1', + // lastName: 'example_last_name1', + // displayName: 'example_display_name1', + // }, + // } + // + // const contactEntity1: ContactEntity = contactEntityFrom(contact1) + // const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + // transaction: true, + // }) + // + // const contact2: IBasicContact = { + // uri: 'example2.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + // name: 'example_name2', + // }, + // contactOwner: { + // firstName: 'example_first_name2', + // middleName: 'example_middle_name2', + // lastName: 'example_last_name2', + // displayName: 'example_display_name2', + // }, + // } + // + // const contactEntity2: ContactEntity = contactEntityFrom(contact2) + // const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + // transaction: true, + // }) + // + // const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ + // left: savedContact1, + // right: savedContact2, + // }) + // + // await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { + // transaction: true, + // }) + // + // const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + // where: { id: contactEntity1.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.createdAt).toBeDefined() + // }) + // + // it('Should save bidirectional contact relationships to database', async (): Promise => { + // const contact1: IBasicContact = { + // uri: 'example1.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name1', + // }, + // contactOwner: { + // firstName: 'example_first_name1', + // middleName: 'example_middle_name1', + // lastName: 'example_last_name1', + // displayName: 'example_display_name1', + // }, + // } + // + // const contactEntity1: ContactEntity = contactEntityFrom(contact1) + // const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + // transaction: true, + // }) + // + // expect(savedContact1).toBeDefined() + // + // const contact2: IBasicContact = { + // uri: 'example2.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + // name: 'example_name2', + // }, + // contactOwner: { + // firstName: 'example_first_name2', + // middleName: 'example_middle_name2', + // lastName: 'example_last_name2', + // displayName: 'example_display_name2', + // }, + // } + // + // const contactEntity2: ContactEntity = contactEntityFrom(contact2) + // const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + // transaction: true, + // }) + // + // expect(savedContact2).toBeDefined() + // + // const relationship1: ContactRelationshipEntity = contactRelationshipEntityFrom({ + // left: savedContact1, + // right: savedContact2, + // }) + // + // const savedRelationship1: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship1, { + // transaction: true, + // }) + // + // expect(savedRelationship1).toBeDefined() + // + // const relationship2: ContactRelationshipEntity = contactRelationshipEntityFrom({ + // left: savedContact2, + // right: savedContact1, + // }) + // + // const savedRelationship2: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship2, { + // transaction: true, + // }) + // + // expect(savedRelationship2).toBeDefined() + // + // const fromDb: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).findOne({ + // where: { id: savedRelationship2.id }, + // }) + // + // expect(fromDb).toBeDefined() + // }) + // + // it('Should enforce unique owner combination for contact relationship', async (): Promise => { + // const contact1: IBasicContact = { + // uri: 'example1.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name1', + // }, + // contactOwner: { + // firstName: 'example_first_name1', + // middleName: 'example_middle_name1', + // lastName: 'example_last_name1', + // displayName: 'example_display_name1', + // }, + // } + // + // const contactEntity1: ContactEntity = contactEntityFrom(contact1) + // const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + // transaction: true, + // }) + // + // expect(savedContact1).toBeDefined() + // + // const contact2: IBasicContact = { + // uri: 'example2.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + // name: 'example_name2', + // }, + // contactOwner: { + // firstName: 'example_first_name2', + // middleName: 'example_middle_name2', + // lastName: 'example_last_name2', + // displayName: 'example_display_name2', + // }, + // } + // + // const contactEntity2: ContactEntity = contactEntityFrom(contact2) + // const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + // transaction: true, + // }) + // + // expect(savedContact2).toBeDefined() + // + // const relationship1: ContactRelationshipEntity = contactRelationshipEntityFrom({ + // left: savedContact1, + // right: savedContact2, + // }) + // + // const savedRelationship1: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship1, { + // transaction: true, + // }) + // + // expect(savedRelationship1).toBeDefined() + // + // const relationship2: ContactRelationshipEntity = contactRelationshipEntityFrom({ + // left: savedContact1, + // right: savedContact2, + // }) + // + // await expect(dbConnection.getRepository(ContactRelationshipEntity).save(relationship2)).rejects.toThrowError( + // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: contact_relationship_entity.leftId, contact_relationship_entity.rightId' + // ) + // }) + // + // it('Should save contact type to database', async (): Promise => { + // const contactType: BasicContactType = { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // } + // + // const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) + // const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) + // + // const fromDb: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).findOne({ + // where: { id: savedContactType.id }, + // }) + // + // expect(fromDb).toBeDefined() + // }) + // + // it('Should save person to database', async (): Promise => { + // const person: BasicPerson = { + // firstName: 'example_first_name', + // lastName: 'lastName2', + // displayName: 'displayName', + // } + // + // const personEntity: PersonEntity = personEntityFrom(person) + // const savedPerson: PersonEntity | null = await dbConnection.getRepository(PersonEntity).save(personEntity, { + // transaction: true, + // }) + // + // const fromDb: PersonEntity | null = await dbConnection.getRepository(PersonEntity).findOne({ + // where: { id: savedPerson.id }, + // }) + // + // expect(fromDb).toBeDefined() + // }) + // + // it('Should set last updated date when saving person', async (): Promise => { + // const person: BasicPerson = { + // firstName: 'example_first_name', + // lastName: 'lastName2', + // displayName: 'displayName', + // } + // + // const personEntity: PersonEntity = personEntityFrom(person) + // const savedPerson: PersonEntity | null = await dbConnection.getRepository(PersonEntity).save(personEntity, { + // transaction: true, + // }) + // + // const fromDb: PersonEntity | null = await dbConnection.getRepository(PersonEntity).findOne({ + // where: { id: savedPerson.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.lastUpdatedAt).toBeDefined() + // }) + // + // it('Should set creation date when saving person', async (): Promise => { + // const person: BasicPerson = { + // firstName: 'example_first_name', + // lastName: 'lastName2', + // displayName: 'displayName', + // } + // + // const personEntity: PersonEntity = personEntityFrom(person) + // const savedPerson: PersonEntity | null = await dbConnection.getRepository(PersonEntity).save(personEntity, { + // transaction: true, + // }) + // + // const fromDb: PersonEntity | null = await dbConnection.getRepository(PersonEntity).findOne({ + // where: { id: savedPerson.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.createdAt).toBeDefined() + // }) + // + // it('Should save organization to database', async (): Promise => { + // const organization: BasicOrganization = { + // legalName: 'example_legal_name', + // displayName: 'example_display_name', + // } + // + // const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) + // const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { + // transaction: true, + // }) + // + // const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ + // where: { id: savedOrganization.id }, + // }) + // + // expect(fromDb).toBeDefined() + // }) + // + // it('Should set last updated date when saving organization', async (): Promise => { + // const organization: BasicOrganization = { + // legalName: 'example_legal_name', + // displayName: 'example_display_name', + // } + // + // const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) + // const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { + // transaction: true, + // }) + // + // const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ + // where: { id: savedOrganization.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.lastUpdatedAt).toBeDefined() + // }) + // + // it('Should set creation date when saving organization', async (): Promise => { + // const organization: BasicOrganization = { + // legalName: 'example_legal_name', + // displayName: 'example_display_name', + // } + // + // const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) + // const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { + // transaction: true, + // }) + // + // const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ + // where: { id: savedOrganization.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.createdAt).toBeDefined() + // }) + // + // it('Should get contact based on person information', async (): Promise => { + // const firstName = 'example_first_name' + // const contact: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contactOwner: { + // firstName, + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const contactEntity: ContactEntity = contactEntityFrom(contact) + // await dbConnection.getRepository(ContactEntity).save(contactEntity, { + // transaction: true, + // }) + // + // const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + // where: { + // contactOwner: { + // firstName, + // } as FindOptionsWhere, + // }, + // }) + // + // expect(fromDb).toBeDefined() + // }) + // + // it('Should get contact based on organization information', async (): Promise => { + // const legalName = 'example_legal_name' + // const contact: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.ORGANIZATION, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contactOwner: { + // legalName, + // displayName: 'example_display_name', + // cocNumber: 'example_coc_number', + // }, + // } + // + // const contactEntity: ContactEntity = contactEntityFrom(contact) + // await dbConnection.getRepository(ContactEntity).save(contactEntity, { + // transaction: true, + // }) + // + // const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + // where: { + // contactOwner: { + // legalName, + // } as FindOptionsWhere, + // }, + // }) + // + // expect(fromDb).toBeDefined() + // }) + // + // it("Should enforce unique contact id's for relationship sides", async (): Promise => { + // const contact: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contactOwner: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const contactEntity: ContactEntity = contactEntityFrom(contact) + // const savedContact: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity, { + // transaction: true, + // }) + // + // expect(savedContact).toBeDefined() + // + // const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ + // left: savedContact, + // right: savedContact, + // }) + // + // await expect(dbConnection.getRepository(ContactRelationshipEntity).save(relationship)).rejects.toThrowError( + // 'Cannot use the same id for both sides of the relationship' + // ) + // }) + // + // it('Should delete contact relationship', async (): Promise => { + // const contact1: IBasicContact = { + // uri: 'example1.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name1', + // }, + // contactOwner: { + // firstName: 'example_first_name1', + // middleName: 'example_middle_name1', + // lastName: 'example_last_name1', + // displayName: 'example_display_name1', + // }, + // } + // + // const contactEntity1: ContactEntity = contactEntityFrom(contact1) + // const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + // transaction: true, + // }) + // + // expect(savedContact1).toBeDefined() + // + // const contact2: IBasicContact = { + // uri: 'example2.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + // name: 'example_name2', + // }, + // contactOwner: { + // firstName: 'example_first_name2', + // middleName: 'example_middle_name2', + // lastName: 'example_last_name2', + // displayName: 'example_display_name2', + // }, + // } + // + // const contactEntity2: ContactEntity = contactEntityFrom(contact2) + // const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + // transaction: true, + // }) + // + // expect(savedContact2).toBeDefined() + // + // const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ + // left: savedContact1, + // right: savedContact2, + // }) + // + // const savedRelationship: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { + // transaction: true, + // }) + // + // expect(savedRelationship).toBeDefined() + // + // await dbConnection.getRepository(ContactRelationshipEntity).delete({ id: savedRelationship.id }) + // + // await expect( + // await dbConnection.getRepository(ContactRelationshipEntity).findOne({ + // where: { id: savedRelationship.id }, + // }) + // ).toBeNull() + // }) + // + // it('Should delete contact type', async (): Promise => { + // const contactType: BasicContactType = { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // } + // + // const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) + // const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) + // + // expect(savedContactType).toBeDefined() + // + // await dbConnection.getRepository(ContactTypeEntity).delete({ id: savedContactType.id }) + // + // await expect( + // await dbConnection.getRepository(ContactTypeEntity).findOne({ + // where: { id: savedContactType.id }, + // }) + // ).toBeNull() + // }) + // + // it('Should not be able to remove contact type when used by contacts', async (): Promise => { + // const contact: IBasicContact = { + // uri: 'example.com', + // contactType: { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contactOwner: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const contactEntity: ContactEntity = contactEntityFrom(contact) + // const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity, { + // transaction: true, + // }) + // + // expect(savedContact).toBeDefined() + // + // await expect(dbConnection.getRepository(ContactTypeEntity).delete({ id: savedContact.contactType.id })).rejects.toThrowError( + // 'FOREIGN KEY constraint failed' + // ) + // }) + // + // it('Should save contact with existing contact type', async (): Promise => { + // const contactType: BasicContactType = { + // type: ContactTypeEnum.PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // } + // + // const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) + // const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) + // + // const contact: IBasicContact = { + // uri: 'example.com', + // contactType: savedContactType, + // contactOwner: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const contactEntity: ContactEntity = contactEntityFrom(contact) + // contactEntity.contactType = savedContactType + // await dbConnection.getRepository(ContactEntity).save(contactEntity, { + // transaction: true, + // }) + // + // const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + // where: { id: contactEntity.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.contactType).toBeDefined() + // expect(fromDb?.contactType.id).toEqual(savedContactType.id) + // expect(fromDb?.contactType.type).toEqual(savedContactType.type) + // expect(fromDb?.contactType.tenantId).toEqual(savedContactType.tenantId) + // expect(fromDb?.contactType.name).toEqual(savedContactType.name) + // }) + // + // // TODO not update creation date when saving contact type + // // TODO add test for updating nested field and checking last updated at on parent }) diff --git a/packages/data-store/src/migrations/generic/1-CreateContacts.ts b/packages/data-store/src/migrations/generic/1-CreateContacts.ts index 4cd98b960..a65e91148 100644 --- a/packages/data-store/src/migrations/generic/1-CreateContacts.ts +++ b/packages/data-store/src/migrations/generic/1-CreateContacts.ts @@ -1,54 +1,118 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' +import { DatabaseType, MigrationInterface, QueryRunner } from 'typeorm' import Debug from 'debug' import { CreateContacts1659463079428 } from '../postgres/1659463079428-CreateContacts' +// import { CreateContacts1690925872592 } from '../postgres/1690925872592-CreateContacts' import { CreateContacts1659463069549 } from '../sqlite/1659463069549-CreateContacts' +// import { CreateContacts1690925872693 } from '../sqlite/1690925872693-CreateContacts' -const debug = Debug('sphereon:ssi-sdk:migrations') +const debug: Debug.Debugger = Debug('sphereon:ssi-sdk:migrations') export class CreateContacts1659463079429 implements MigrationInterface { name = 'CreateContacts1659463079429' + // private readonly sqliteMigrations: MigrationInterface[] = [ + // new CreateContacts1659463069549(), + // // new CreateContacts1690925872693(), + // ]; + // + // private readonly postgresMigrations: MigrationInterface[] = [ + // new CreateContacts1659463079428(), + // new CreateContacts1690925872592() + // ]; + public async up(queryRunner: QueryRunner): Promise { debug('migration: creating contacts tables') - const dbType = queryRunner.connection.driver.options.type - if (dbType === 'postgres') { - debug('using postgres migration file') - const mig = new CreateContacts1659463079428() - const up = await mig.up(queryRunner) - debug('Migration statements executed') - return up - } else if (dbType === 'sqlite' || 'react-native') { - debug('using sqlite/react-native migration file') - const mig = new CreateContacts1659463069549() - const up = await mig.up(queryRunner) - debug('Migration statements executed') - return up - } else { - return Promise.reject( - "Migrations are currently only supported for sqlite, react-native and postgres. Please run your database without migrations and with 'migrationsRun: false' and 'synchronize: true' for now" - ) + const dbType: DatabaseType = queryRunner.connection.driver.options.type + + switch (dbType) { + case 'postgres': { + debug('using postgres migration file') + const mig: CreateContacts1659463079428 = new CreateContacts1659463079428() + // const up: void = await mig.up(queryRunner) + await mig.up(queryRunner) + // for (const mig of this.postgresMigrations) { + // await mig.up(queryRunner); + // } + debug('Migration statements executed') + // return up + return + } + case 'sqlite': + case 'react-native': { + debug('using sqlite/react-native migration file') + // for (const mig of this.sqliteMigrations) { + // await mig.up(queryRunner); + // debug('Migration statements executed'); + // } + const mig: CreateContacts1659463069549 = new CreateContacts1659463069549() + await mig.up(queryRunner) + // const mig: CreateContacts1659463069549 = new CreateContacts1659463069549() + // const up: void = await mig.up(queryRunner) + debug('Migration statements executed') + // return up + return + } + default: + return Promise.reject( + "Migrations are currently only supported for sqlite, react-native and postgres. Please run your database without migrations and with 'migrationsRun: false' and 'synchronize: true' for now" + ) } } public async down(queryRunner: QueryRunner): Promise { debug('migration: reverting contacts tables') - const dbType = queryRunner.connection.driver.options.type - if (dbType === 'postgres') { - debug('using postgres migration file') - const mig = new CreateContacts1659463079428() - const down = await mig.down(queryRunner) - debug('Migration statements executed') - return down - } else if (dbType === 'sqlite' || 'react-native') { - debug('using sqlite/react-native migration file') - const mig = new CreateContacts1659463069549() - const down = await mig.down(queryRunner) - debug('Migration statements executed') - return down - } else { - return Promise.reject( - "Migrations are currently only supported for sqlite, react-native and postgres. Please run your database without migrations and with 'migrationsRun: false' and 'synchronize: true' for now" - ) + const dbType: DatabaseType = queryRunner.connection.driver.options.type + + switch (dbType) { + case 'postgres': { + debug('using postgres migration file') + // const mig: CreateContacts1659463079428 = new CreateContacts1659463079428() + // const down: void = await mig.down(queryRunner) + const mig: CreateContacts1659463079428 = new CreateContacts1659463079428() + await mig.down(queryRunner) + // for (const mig of this.postgresMigrations.reverse()) { + // await mig.down(queryRunner); + // } + debug('Migration statements executed') + // return down + return + } + case 'sqlite': + case 'react-native': { + debug('using sqlite/react-native migration file') + // for (const mig of this.sqliteMigrations.reverse()) { + // await mig.down(queryRunner); + // } + // const mig: CreateContacts1659463069549 = new CreateContacts1659463069549() + // const down: void = await mig.down(queryRunner) + const mig: CreateContacts1659463069549 = new CreateContacts1659463069549() + await mig.down(queryRunner) + debug('Migration statements executed') + // return down + return + } + default: + return Promise.reject( + "Migrations are currently only supported for sqlite, react-native and postgres. Please run your database without migrations and with 'migrationsRun: false' and 'synchronize: true' for now" + ) } + + // if (dbType === 'postgres') { + // debug('using postgres migration file') + // const mig = new CreateContacts1659463079428() + // const down = await mig.down(queryRunner) + // debug('Migration statements executed') + // return down + // } else if (dbType === 'sqlite' || 'react-native') { + // debug('using sqlite/react-native migration file') + // const mig = new CreateContacts1659463069549() + // const down = await mig.down(queryRunner) + // debug('Migration statements executed') + // return down + // } else { + // return Promise.reject( + // "Migrations are currently only supported for sqlite, react-native and postgres. Please run your database without migrations and with 'migrationsRun: false' and 'synchronize: true' for now" + // ) + // } } } diff --git a/packages/data-store/src/migrations/generic/1-CreateIssuanceBranding.ts b/packages/data-store/src/migrations/generic/1-CreateIssuanceBranding.ts index 9453ddf1b..b730d083c 100644 --- a/packages/data-store/src/migrations/generic/1-CreateIssuanceBranding.ts +++ b/packages/data-store/src/migrations/generic/1-CreateIssuanceBranding.ts @@ -1,54 +1,62 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' +import { DatabaseType, MigrationInterface, QueryRunner } from 'typeorm' import Debug from 'debug' import { CreateIssuanceBranding1685628974232 } from '../postgres/1685628974232-CreateIssuanceBranding' import { CreateIssuanceBranding1685628973231 } from '../sqlite/1685628973231-CreateIssuanceBranding' -const debug = Debug('sphereon:ssi-sdk:migrations') +const debug: Debug.Debugger = Debug('sphereon:ssi-sdk:migrations') export class CreateIssuanceBranding1659463079429 implements MigrationInterface { name = 'CreateIssuanceBranding1659463079429' public async up(queryRunner: QueryRunner): Promise { debug('migration: creating issuance branding tables') - const dbType = queryRunner.connection.driver.options.type - if (dbType === 'postgres') { - debug('using postgres migration file') - const mig = new CreateIssuanceBranding1685628974232() - const up = await mig.up(queryRunner) - debug('Migration statements executed') - return up - } else if (dbType === 'sqlite' || 'react-native') { - debug('using sqlite/react-native migration file') - const mig = new CreateIssuanceBranding1685628973231() - const up = await mig.up(queryRunner) - debug('Migration statements executed') - return up - } else { - return Promise.reject( - "Migrations are currently only supported for sqlite, react-native and postgres. Please run your database without migrations and with 'migrationsRun: false' and 'synchronize: true' for now" - ) + const dbType: DatabaseType = queryRunner.connection.driver.options.type + switch (dbType) { + case 'postgres': { + debug('using postgres migration file') + const mig: CreateIssuanceBranding1685628974232 = new CreateIssuanceBranding1685628974232() + await mig.up(queryRunner) + debug('Migration statements executed') + return + } + case 'sqlite': + case 'react-native': { + debug('using sqlite/react-native migration file') + const mig: CreateIssuanceBranding1685628973231 = new CreateIssuanceBranding1685628973231() + await mig.up(queryRunner) + debug('Migration statements executed') + return + } + default: + return Promise.reject( + "Migrations are currently only supported for sqlite, react-native and postgres. Please run your database without migrations and with 'migrationsRun: false' and 'synchronize: true' for now" + ) } } public async down(queryRunner: QueryRunner): Promise { debug('migration: reverting issuance branding tables') - const dbType = queryRunner.connection.driver.options.type - if (dbType === 'postgres') { - debug('using postgres migration file') - const mig = new CreateIssuanceBranding1685628974232() - const down = await mig.down(queryRunner) - debug('Migration statements executed') - return down - } else if (dbType === 'sqlite' || 'react-native') { - debug('using sqlite/react-native migration file') - const mig = new CreateIssuanceBranding1685628973231() - const down = await mig.down(queryRunner) - debug('Migration statements executed') - return down - } else { - return Promise.reject( - "Migrations are currently only supported for sqlite, react-native and postgres. Please run your database without migrations and with 'migrationsRun: false' and 'synchronize: true' for now" - ) + const dbType: DatabaseType = queryRunner.connection.driver.options.type + switch (dbType) { + case 'postgres': { + debug('using postgres migration file') + const mig: CreateIssuanceBranding1685628974232 = new CreateIssuanceBranding1685628974232() + await mig.down(queryRunner) + debug('Migration statements executed') + return + } + case 'sqlite': + case 'react-native': { + debug('using sqlite/react-native migration file') + const mig: CreateIssuanceBranding1685628973231 = new CreateIssuanceBranding1685628973231() + await mig.down(queryRunner) + debug('Migration statements executed') + return + } + default: + return Promise.reject( + "Migrations are currently only supported for sqlite, react-native and postgres. Please run your database without migrations and with 'migrationsRun: false' and 'synchronize: true' for now" + ) } } } diff --git a/packages/data-store/src/migrations/generic/2-CreateContacts.ts b/packages/data-store/src/migrations/generic/2-CreateContacts.ts new file mode 100644 index 000000000..5d5fa990e --- /dev/null +++ b/packages/data-store/src/migrations/generic/2-CreateContacts.ts @@ -0,0 +1,68 @@ +import { DatabaseType, MigrationInterface, QueryRunner } from 'typeorm' +import Debug from 'debug' +import { CreateContacts1690925872693 } from '../sqlite/1690925872693-CreateContacts' +import { CreateContacts1690925872592 } from '../postgres/1690925872592-CreateContacts' + +const debug: Debug.Debugger = Debug('sphereon:ssi-sdk:migrations') + +export class CreateContacts1690925872318 implements MigrationInterface { + name = 'CreateContacts1690925872318' + + public async up(queryRunner: QueryRunner): Promise { + debug('migration: creating contacts tables') + const dbType: DatabaseType = queryRunner.connection.driver.options.type + + switch (dbType) { + case 'postgres': + { + debug('using postgres migration file') + const mig: CreateContacts1690925872592 = new CreateContacts1690925872592() + await mig.up(queryRunner) + debug('Migration statements executed') + return + } + case 'sqlite': + case 'react-native': + { + debug('using sqlite/react-native migration file') + const mig: CreateContacts1690925872693 = new CreateContacts1690925872693() + await mig.up(queryRunner) + debug('Migration statements executed') + return + } + default: + return Promise.reject( + "Migrations are currently only supported for sqlite, react-native and postgres. Please run your database without migrations and with 'migrationsRun: false' and 'synchronize: true' for now" + ) + } + } + + public async down(queryRunner: QueryRunner): Promise { + debug('migration: reverting contacts tables') + const dbType: DatabaseType = queryRunner.connection.driver.options.type + + switch (dbType) { + case 'postgres': + { + debug('using postgres migration file') + const mig: CreateContacts1690925872592 = new CreateContacts1690925872592() + await mig.down(queryRunner) + debug('Migration statements executed') + return + } + case 'sqlite': + case 'react-native': + { + debug('using sqlite/react-native migration file') + const mig: CreateContacts1690925872693 = new CreateContacts1690925872693() + await mig.down(queryRunner) + debug('Migration statements executed') + return + } + default: + return Promise.reject( + "Migrations are currently only supported for sqlite, react-native and postgres. Please run your database without migrations and with 'migrationsRun: false' and 'synchronize: true' for now" + ) + } + } +} diff --git a/packages/data-store/src/migrations/generic/index.ts b/packages/data-store/src/migrations/generic/index.ts index bcd04e323..9bada1dfe 100644 --- a/packages/data-store/src/migrations/generic/index.ts +++ b/packages/data-store/src/migrations/generic/index.ts @@ -1,6 +1,8 @@ import { CreateContacts1659463079429 } from './1-CreateContacts' +// import { CreateContacts1690925872318 } from './2-CreateContacts' import { CreateIssuanceBranding1659463079429 } from './1-CreateIssuanceBranding' + /** * The migrations array that SHOULD be used when initializing a TypeORM database connection. * @@ -8,4 +10,8 @@ import { CreateIssuanceBranding1659463079429 } from './1-CreateIssuanceBranding' * * @public */ -export const DataStoreMigrations = [CreateContacts1659463079429, CreateIssuanceBranding1659463079429] +export const DataStoreMigrations = [ + CreateContacts1659463079429, + // CreateContacts1690925872318, + CreateIssuanceBranding1659463079429 +] diff --git a/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts b/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts new file mode 100644 index 000000000..73cb16a50 --- /dev/null +++ b/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts @@ -0,0 +1,61 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class CreateContacts1690925872592 implements MigrationInterface { + name = 'CreateContacts1690925872592' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE "BaseConfigEntity" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "client_id" character varying(255), "client_secret" character varying(255), "scopes" text, "issuer" character varying(255), "redirect_url" text, "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "identifier" character varying(255), "session_id" character varying(255), "type" character varying NOT NULL, "connectionId" uuid, CONSTRAINT "REL_BaseConfig_connectionId" UNIQUE ("connectionId"), CONSTRAINT "PK_BaseConfigEntity_id" PRIMARY KEY ("id"))` + ) + await queryRunner.query(`CREATE INDEX "IDX_BaseConfigEntity_type" ON "BaseConfigEntity" ("type")`) + await queryRunner.query(`CREATE TYPE "public"."CorrelationIdentifier_type_enum" AS ENUM('did', 'url')`) + await queryRunner.query( + `CREATE TABLE "CorrelationIdentifier" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "type" "public"."CorrelationIdentifier_type_enum" NOT NULL, "correlation_id" text NOT NULL, "identityId" uuid, CONSTRAINT "UQ_Correlation_id" UNIQUE ("correlation_id"), CONSTRAINT "REL_CorrelationIdentifier_identityId" UNIQUE ("identityId"), CONSTRAINT "PK_CorrelationIdentifier_id" PRIMARY KEY ("id"))` + ) + await queryRunner.query( + `CREATE TABLE "Contact" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "name" character varying(255) NOT NULL, "alias" character varying(255) NOT NULL, "uri" character varying(255) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "UQ_Name" UNIQUE ("name"), CONSTRAINT "UQ_Alias" UNIQUE ("alias"), CONSTRAINT "PK_Contact_id" PRIMARY KEY ("id"))` + ) + await queryRunner.query( + `CREATE TABLE "IdentityMetadata" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "label" character varying(255) NOT NULL, "value" character varying(255) NOT NULL, "identityId" uuid, CONSTRAINT "PK_IdentityMetadata_id" PRIMARY KEY ("id"))` + ) + await queryRunner.query( + `CREATE TABLE "Identity" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "alias" character varying(255) NOT NULL, "roles" text, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), "contactId" uuid, CONSTRAINT "UQ_Alias" UNIQUE ("alias"), CONSTRAINT "PK_Identity_id" PRIMARY KEY ("id"))` + ) + await queryRunner.query(`CREATE TYPE "public"."Connection_type_enum" AS ENUM('OIDC', 'SIOPv2', 'SIOPv2+OpenID4VP')`) + await queryRunner.query( + `CREATE TABLE "Connection" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "type" "public"."Connection_type_enum" NOT NULL, "identityId" uuid, CONSTRAINT "REL_Connection_identityId" UNIQUE ("identityId"), CONSTRAINT "PK_Connection_id" PRIMARY KEY ("id"))` + ) + await queryRunner.query( + `ALTER TABLE "BaseConfigEntity" ADD CONSTRAINT "FK_BaseConfig_connectionId" FOREIGN KEY ("connectionId") REFERENCES "Connection"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + ) + await queryRunner.query( + `ALTER TABLE "CorrelationIdentifier" ADD CONSTRAINT "FK_CorrelationIdentifier_identityId" FOREIGN KEY ("identityId") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + ) + await queryRunner.query( + `ALTER TABLE "IdentityMetadata" ADD CONSTRAINT "FK_IdentityMetadata_identityId" FOREIGN KEY ("identityId") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + ) + await queryRunner.query( + `ALTER TABLE "Identity" ADD CONSTRAINT "FK_Identity_contactId" FOREIGN KEY ("contactId") REFERENCES "Contact"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + ) + await queryRunner.query( + `ALTER TABLE "Connection" ADD CONSTRAINT "FK_Connection_identityId" FOREIGN KEY ("identityId") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "Connection" DROP CONSTRAINT "FK_Connection_identityId"`) + await queryRunner.query(`ALTER TABLE "Identity" DROP CONSTRAINT "FK_Identity_contactId"`) + await queryRunner.query(`ALTER TABLE "IdentityMetadata" DROP CONSTRAINT "FK_IdentityMetadata_identityId"`) + await queryRunner.query(`ALTER TABLE "CorrelationIdentifier" DROP CONSTRAINT "FK_CorrelationIdentifier_identityId"`) + await queryRunner.query(`ALTER TABLE "BaseConfigEntity" DROP CONSTRAINT "FK_BaseConfig_connectionId"`) + await queryRunner.query(`DROP TABLE "Connection"`) + await queryRunner.query(`DROP TYPE "public"."Connection_type_enum"`) + await queryRunner.query(`DROP TABLE "Identity"`) + await queryRunner.query(`DROP TABLE "IdentityMetadata"`) + await queryRunner.query(`DROP TABLE "Contact"`) + await queryRunner.query(`DROP TABLE "CorrelationIdentifier"`) + await queryRunner.query(`DROP TYPE "public"."CorrelationIdentifier_type_enum"`) + await queryRunner.query(`DROP INDEX "public"."IDX_BaseConfigEntity_type"`) + await queryRunner.query(`DROP TABLE "BaseConfigEntity"`) + } +} diff --git a/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts b/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts new file mode 100644 index 000000000..7f7161859 --- /dev/null +++ b/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts @@ -0,0 +1,16 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class CreateContacts1690925872693 implements MigrationInterface { + name = 'CreateContacts1690925872693' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE "contact_type_entity" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('person','organization') ) NOT NULL, "name" varchar(255) NOT NULL, "description" varchar(255), "tenantId" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "UQ_951a7b2f1b044e348fe5b7a6172" UNIQUE ("name"))` + ) + + } + + public async down(queryRunner: QueryRunner): Promise { + + } +} From 31c67ef2cb65199ae952530e9a641c8b3b4bf23f Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Thu, 3 Aug 2023 10:51:42 +0200 Subject: [PATCH 06/35] DPP-1 WIP --- .../src/__tests__/contact.entities.test.ts | 4601 +++++++++-------- .../src/__tests__/contact.store.test.ts | 178 +- .../data-store/src/contact/ContactStore.ts | 40 +- .../src/entities/contact/BaseConfigEntity.ts | 16 +- .../src/entities/contact/ConnectionEntity.ts | 20 +- .../src/entities/contact/ContactEntity.ts | 28 +- .../entities/contact/ContactOwnerEntity.ts | 8 + .../contact/ContactRelationshipEntity.ts | 27 +- .../src/entities/contact/ContactTypeEntity.ts | 2 +- .../src/entities/contact/IdentityEntity.ts | 7 - .../entities/contact/OrganizationEntity.ts | 1 - .../BaseLocaleBrandingEntity.ts | 7 - .../CredentialBrandingEntity.ts | 7 - .../issuanceBranding/IssuerBrandingEntity.ts | 7 - .../migrations/generic/1-CreateContacts.ts | 54 - .../src/migrations/generic/index.ts | 5 +- .../internal-migrations-ormconfig.ts | 6 +- .../sqlite/1690925872693-CreateContacts.ts | 88 +- .../types/contact/IAbstractContactStore.ts | 4 +- 19 files changed, 2595 insertions(+), 2511 deletions(-) diff --git a/packages/data-store/src/__tests__/contact.entities.test.ts b/packages/data-store/src/__tests__/contact.entities.test.ts index 914db5ee7..6f4f74ca9 100644 --- a/packages/data-store/src/__tests__/contact.entities.test.ts +++ b/packages/data-store/src/__tests__/contact.entities.test.ts @@ -1,48 +1,62 @@ import { DataSource - // , FindOptionsWhere + , FindOptionsWhere } from 'typeorm' import { DataStoreContactEntities - , DataStoreMigrations + // , DataStoreMigrations } from '../index' import { IBasicContact, ContactTypeEnum, IPerson, - // IOrganization, - // IdentityRoleEnum, - // CorrelationIdentifierEnum, - // ConnectionTypeEnum, - // BasicContactType, - // BasicOrganization, - // BasicPerson, - // IBasicConnection, - // IBasicIdentity, - // BasicDidAuthConfig, - // BasicOpenIdConfig, + IOrganization, + IdentityRoleEnum, + CorrelationIdentifierEnum, + ConnectionTypeEnum, + BasicContactType, + BasicOrganization, + BasicPerson, + IBasicConnection, + IBasicIdentity, + BasicDidAuthConfig, + BasicOpenIdConfig, } from '../types' import { PersonEntity - // , personEntityFrom + , personEntityFrom } from '../entities/contact/PersonEntity' -// import { OrganizationEntity, organizationEntityFrom } from '../entities/contact/OrganizationEntity' -// import { ContactRelationshipEntity, contactRelationshipEntityFrom } from '../entities/contact/ContactRelationshipEntity' -// import { ContactTypeEntity, contactTypeEntityFrom } from '../entities/contact/ContactTypeEntity' +import { OrganizationEntity, organizationEntityFrom } from '../entities/contact/OrganizationEntity' +import { ContactRelationshipEntity, contactRelationshipEntityFrom } from '../entities/contact/ContactRelationshipEntity' +import { ContactTypeEntity, contactTypeEntityFrom } from '../entities/contact/ContactTypeEntity' import { ContactEntity, contactEntityFrom } from '../entities/contact/ContactEntity' -// import { IdentityEntity, identityEntityFrom } from '../entities/contact/IdentityEntity' -// import { OpenIdConfigEntity, openIdConfigEntityFrom } from '../entities/contact/OpenIdConfigEntity' -// import { DidAuthConfigEntity, didAuthConfigEntityFrom } from '../entities/contact/DidAuthConfigEntity' -// import { ConnectionEntity, connectionEntityFrom } from '../entities/contact/ConnectionEntity' -// import { CorrelationIdentifierEntity } from '../entities/contact/CorrelationIdentifierEntity' -// import { IdentityMetadataItemEntity } from '../entities/contact/IdentityMetadataItemEntity' -// import { ContactOwnerEntity } from '../entities/contact/ContactOwnerEntity' +import { IdentityEntity, identityEntityFrom } from '../entities/contact/IdentityEntity' +import { OpenIdConfigEntity, openIdConfigEntityFrom } from '../entities/contact/OpenIdConfigEntity' +import { DidAuthConfigEntity, didAuthConfigEntityFrom } from '../entities/contact/DidAuthConfigEntity' +import { ConnectionEntity, connectionEntityFrom } from '../entities/contact/ConnectionEntity' +import { CorrelationIdentifierEntity } from '../entities/contact/CorrelationIdentifierEntity' +import { IdentityMetadataItemEntity } from '../entities/contact/IdentityMetadataItemEntity' +import { ContactOwnerEntity } from '../entities/contact/ContactOwnerEntity' describe('Database entities tests', (): void => { let dbConnection: DataSource + beforeEach(async (): Promise => { + dbConnection = await new DataSource({ + type: 'sqlite', + database: ':memory:', + logging: 'all', + migrationsRun: false, + // migrations: DataStoreMigrations, + synchronize: true, //false + entities: DataStoreContactEntities, + }).initialize() + // await dbConnection.runMigrations() + // expect(await dbConnection.showMigrations()).toBeFalsy() + }) + // beforeEach(async (): Promise => { // dbConnection = await new DataSource({ // type: 'sqlite', - // database: ':memory:', + // database: './database.sqlite', // logging: 'all', // migrationsRun: false, // // migrations: DataStoreMigrations, @@ -53,19 +67,19 @@ describe('Database entities tests', (): void => { // // expect(await dbConnection.showMigrations()).toBeFalsy() // }) - beforeEach(async (): Promise => { - dbConnection = await new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: 'all', - migrationsRun: false, - migrations: DataStoreMigrations, - synchronize: false, //false - entities: DataStoreContactEntities, - }).initialize() - await dbConnection.runMigrations() - expect(await dbConnection.showMigrations()).toBeFalsy() - }) + // beforeEach(async (): Promise => { + // dbConnection = await new DataSource({ + // type: 'sqlite', + // database: ':memory:',//'./database.sqlite', + // logging: 'all', + // migrationsRun: false, + // migrations: DataStoreMigrations, + // synchronize: false, //false + // entities: DataStoreContactEntities, + // }).initialize() + // await dbConnection.runMigrations() + // expect(await dbConnection.showMigrations()).toBeFalsy() + // }) afterEach(async (): Promise => { await (await dbConnection).destroy() @@ -109,2249 +123,2270 @@ describe('Database entities tests', (): void => { expect((fromDb?.contactOwner).lastName).toEqual((contact.contactOwner).lastName) expect((fromDb?.contactOwner).displayName).toEqual((contact.contactOwner).displayName) }) - // - // it('Should save organization contact to database', async (): Promise => { - // const contact: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.ORGANIZATION, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contactOwner: { - // legalName: 'example_legal_name', - // displayName: 'example_display_name', - // cocNumber: 'example_coc_number', - // }, - // } - // - // const contactEntity: ContactEntity = contactEntityFrom(contact) - // await dbConnection.getRepository(ContactEntity).save(contactEntity, { - // transaction: true, - // }) - // - // const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - // where: { id: contactEntity.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.identities?.length).toEqual(0) - // expect(fromDb?.uri).toEqual(contact.uri) - // expect(fromDb?.contactType).toBeDefined() - // expect(fromDb?.contactType.type).toEqual(contact.contactType.type) - // expect(fromDb?.contactType.tenantId).toEqual(contact.contactType.tenantId) - // expect(fromDb?.contactType.name).toEqual(contact.contactType.name) - // expect(fromDb?.contactOwner).toBeDefined() - // expect((fromDb?.contactOwner).legalName).toEqual((contact.contactOwner).legalName) - // expect((fromDb?.contactOwner).displayName).toEqual((contact.contactOwner).displayName) - // expect((fromDb?.contactOwner).cocNumber).toEqual((contact.contactOwner).cocNumber) - // }) - // - // it('Should result in contact relationship for the owner side only', async (): Promise => { - // const contact1: IBasicContact = { - // uri: 'example1.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name1', - // }, - // contactOwner: { - // firstName: 'example_first_name1', - // middleName: 'example_middle_name1', - // lastName: 'example_last_name1', - // displayName: 'example_display_name1', - // }, - // } - // - // const contactEntity1: ContactEntity = contactEntityFrom(contact1) - // const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { - // transaction: true, - // }) - // - // const contact2: IBasicContact = { - // uri: 'example2.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - // name: 'example_name2', - // }, - // contactOwner: { - // firstName: 'example_first_name2', - // middleName: 'example_middle_name2', - // lastName: 'example_last_name2', - // displayName: 'example_display_name2', - // }, - // } - // - // const contactEntity2: ContactEntity = contactEntityFrom(contact2) - // const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { - // transaction: true, - // }) - // - // const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ - // left: savedContact1, - // right: savedContact2, - // }) - // - // await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { - // transaction: true, - // }) - // - // const fromDb1: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - // where: { id: savedContact1.id }, - // }) - // - // const fromDb2: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - // where: { id: savedContact2.id }, - // }) - // - // expect(fromDb1).toBeDefined() - // expect(fromDb1?.relationships.length).toEqual(1) - // expect(fromDb2).toBeDefined() - // expect(fromDb2?.relationships.length).toEqual(0) - // }) - // - // it('should throw error when saving person contact with blank first name', async (): Promise => { - // const contact: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contactOwner: { - // firstName: '', - // middleName: 'example_middle_name1', - // lastName: 'example_last_name1', - // displayName: 'example_display_name1', - // }, - // } - // - // const contactEntity: ContactEntity = contactEntityFrom(contact) - // - // await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank first names are not allowed') - // }) - // - // it('should throw error when saving person contact with blank middle name', async (): Promise => { - // const contact: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contactOwner: { - // firstName: 'example_first_name', - // middleName: '', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const contactEntity: ContactEntity = contactEntityFrom(contact) - // - // await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank middle names are not allowed') - // }) - // - // it('should throw error when saving person contact with blank last name', async (): Promise => { - // const contact: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contactOwner: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: '', - // displayName: 'example_display_name', - // }, - // } - // - // const contactEntity: ContactEntity = contactEntityFrom(contact) - // - // await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank last names are not allowed') - // }) - // - // it('should throw error when saving person contact with blank display name', async (): Promise => { - // const contact: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contactOwner: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: '', - // }, - // } - // - // const contactEntity: ContactEntity = contactEntityFrom(contact) - // - // await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank display names are not allowed') - // }) - // - // it('should throw error when saving organization contact with blank legal name', async (): Promise => { - // const contact: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.ORGANIZATION, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contactOwner: { - // legalName: '', - // displayName: 'example_legal_name', - // cocNumber: 'example_coc_number', - // }, - // } - // - // const contactEntity: ContactEntity = contactEntityFrom(contact) - // - // await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank legal names are not allowed') - // }) - // - // it('should throw error when saving organization contact with blank display name', async (): Promise => { - // const contact: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.ORGANIZATION, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contactOwner: { - // legalName: 'example_first_name', - // displayName: '', - // cocNumber: 'example_coc_number', - // }, - // } - // - // const contactEntity: ContactEntity = contactEntityFrom(contact) - // - // await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank display names are not allowed') - // }) - // - // it('should throw error when saving organization contact with blank coc number', async (): Promise => { - // const contact: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.ORGANIZATION, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contactOwner: { - // legalName: 'example_first_name', - // displayName: 'example_display_name', - // cocNumber: '', - // }, - // } - // - // const contactEntity: ContactEntity = contactEntityFrom(contact) - // - // await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank coc numbers are not allowed') - // }) - // - // it('should throw error when saving contact with blank contact type name', async (): Promise => { - // const contact: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: '', - // }, - // contactOwner: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const contactEntity: ContactEntity = contactEntityFrom(contact) - // - // await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank names are not allowed') - // }) - // - // it('should throw error when saving contact with blank contact type description', async (): Promise => { - // const contact: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // description: '', - // }, - // contactOwner: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const contactEntity: ContactEntity = contactEntityFrom(contact) - // - // await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank descriptions are not allowed') - // }) - // - // it('should throw error when saving contact with blank contact type tenant id', async (): Promise => { - // const contact: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '', - // name: 'example_name', - // }, - // contactOwner: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const contactEntity: ContactEntity = contactEntityFrom(contact) - // - // await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError("Blank tenant id's are not allowed") - // }) - // - // it('Should enforce unique display name for a person contact', async (): Promise => { - // const contactDisplayName = 'non_unique_name' - // const contact1: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - // name: 'example_name', - // }, - // contactOwner: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: contactDisplayName, - // }, - // } - // const contact1Entity: ContactEntity = contactEntityFrom(contact1) - // await dbConnection.getRepository(ContactEntity).save(contact1Entity) - // - // const contact2: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contactOwner: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: contactDisplayName, - // }, - // } - // const contact2Entity: ContactEntity = contactEntityFrom(contact2) - // - // await expect(dbConnection.getRepository(ContactEntity).save(contact2Entity)).rejects.toThrowError( - // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: contact_type_entity.name' - // ) - // }) - // - // it('Should enforce unique display name for a organization contact', async (): Promise => { - // const contactDisplayName = 'non_unique_name' - // const contact1: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.ORGANIZATION, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - // name: 'example_name', - // }, - // contactOwner: { - // legalName: 'example_first_name', - // displayName: contactDisplayName, - // cocNumber: 'example_coc_number', - // }, - // } - // const contact1Entity: ContactEntity = contactEntityFrom(contact1) - // await dbConnection.getRepository(ContactEntity).save(contact1Entity) - // - // const contact2: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.ORGANIZATION, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contactOwner: { - // legalName: 'example_first_name', - // displayName: contactDisplayName, - // cocNumber: 'example_coc_number', - // }, - // } - // const contact2Entity: ContactEntity = contactEntityFrom(contact2) - // - // await expect(dbConnection.getRepository(ContactEntity).save(contact2Entity)).rejects.toThrowError( - // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: contact_type_entity.name' - // ) - // }) - // - // it('Should enforce unique alias for an identity', async (): Promise => { - // const alias = 'non_unique_alias' - // const identity1: IBasicIdentity = { - // alias, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId: 'unique_correlationId1', - // }, - // } - // const identity1Entity: IdentityEntity = identityEntityFrom(identity1) - // await dbConnection.getRepository(IdentityEntity).save(identity1Entity) - // - // const identity2: IBasicIdentity = { - // alias: alias, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId: 'unique_correlationId2', - // }, - // } - // const identity2Entity: IdentityEntity = identityEntityFrom(identity2) - // await expect(dbConnection.getRepository(IdentityEntity).save(identity2Entity)).rejects.toThrowError( - // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: Identity.alias' - // ) - // }) - // - // it('Should enforce unique correlationId for a identity', async (): Promise => { - // const correlationId = 'non_unique_correlationId' - // const identity1: IBasicIdentity = { - // alias: 'unique_alias1', - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId, - // }, - // } - // const identity1Entity: IdentityEntity = identityEntityFrom(identity1) - // await dbConnection.getRepository(IdentityEntity).save(identity1Entity) - // - // const identity2: IBasicIdentity = { - // alias: 'unique_alias2', - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId, - // }, - // } - // const identity2Entity: IdentityEntity = identityEntityFrom(identity2) - // await expect(dbConnection.getRepository(IdentityEntity).save(identity2Entity)).rejects.toThrowError( - // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: CorrelationIdentifier.correlation_id' - // ) - // }) - // - // it('Should save identity to database', async (): Promise => { - // const correlationId = 'example_did' - // const identity: IBasicIdentity = { - // alias: correlationId, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId, - // }, - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // - // await dbConnection.getRepository(IdentityEntity).save(identityEntity) - // - // const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ - // where: { - // identifier: { - // correlationId, - // }, - // }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.connection).toBeNull() - // expect(fromDb?.identifier).toBeDefined() - // expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) - // expect(fromDb?.identifier.type).toEqual(identity.identifier.type) - // }) - // - // it('should throw error when saving identity with blank alias', async (): Promise => { - // const identity: IBasicIdentity = { - // alias: '', - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId: 'example_did', - // }, - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // - // await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank aliases are not allowed') - // }) - // - // it('should throw error when saving identity with blank correlation id', async (): Promise => { - // const identity: IBasicIdentity = { - // alias: 'example_did', - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId: '', - // }, - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // - // await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank correlation ids are not allowed') - // }) - // - // it('should throw error when saving identity with blank metadata label', async (): Promise => { - // const correlationId = 'example_did' - // const identity: IBasicIdentity = { - // alias: correlationId, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId, - // }, - // metadata: [ - // { - // label: '', - // value: 'example_value', - // }, - // ], - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // - // await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank metadata labels are not allowed') - // }) - // - // it('should throw error when saving identity with blank metadata value', async (): Promise => { - // const correlationId = 'example_did' - // const identity: IBasicIdentity = { - // alias: correlationId, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId, - // }, - // metadata: [ - // { - // label: 'example_label', - // value: '', - // }, - // ], - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // - // await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank metadata values are not allowed') - // }) - // - // it('Should save identity with openid connection to database', async (): Promise => { - // const correlationId = 'example.com' - // const identity: IBasicIdentity = { - // alias: correlationId, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.URL, - // correlationId, - // }, - // connection: { - // type: ConnectionTypeEnum.OPENID_CONNECT, - // config: { - // clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', - // clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', - // scopes: ['auth'], - // issuer: 'https://example.com/app-test', - // redirectUrl: 'app:/callback', - // dangerouslyAllowInsecureHttpRequests: true, - // clientAuthMethod: 'post', - // }, - // }, - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // - // await dbConnection.getRepository(IdentityEntity).save(identityEntity) - // - // const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ - // where: { - // identifier: { - // correlationId, - // }, - // }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.connection).toBeDefined() - // expect(fromDb?.identifier).toBeDefined() - // expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) - // expect(fromDb?.identifier.type).toEqual(identity.identifier.type) - // expect(fromDb?.connection?.type).toEqual(identity.connection?.type) - // expect(fromDb?.connection?.config).toBeDefined() - // expect((fromDb?.connection?.config).clientId).toEqual((identity.connection?.config).clientId) - // }) - // - // it('Should save identity with didauth connection to database', async (): Promise => { - // const correlationId = 'example.com' - // const identity: IBasicIdentity = { - // alias: correlationId, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.URL, - // correlationId, - // }, - // connection: { - // type: ConnectionTypeEnum.SIOPv2, - // config: { - // identifier: { - // did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - // provider: 'test_provider', - // keys: [], - // services: [], - // }, - // redirectUrl: 'https://example.com', - // stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', - // sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - // }, - // }, - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // - // await dbConnection.getRepository(IdentityEntity).save(identityEntity) - // - // const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ - // where: { - // identifier: { - // correlationId, - // }, - // }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.connection).toBeDefined() - // expect(fromDb?.identifier).toBeDefined() - // expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) - // expect(fromDb?.identifier.type).toEqual(identity.identifier.type) - // expect(fromDb?.connection?.type).toEqual(identity.connection?.type) - // expect(fromDb?.connection?.config).toBeDefined() - // expect((fromDb?.connection?.config).identifier).toEqual((identity.connection?.config).identifier.did) - // }) - // - // it('Should save connection with openid config to database', async (): Promise => { - // const connection: IBasicConnection = { - // type: ConnectionTypeEnum.OPENID_CONNECT, - // config: { - // clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', - // clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', - // scopes: ['auth'], - // issuer: 'https://example.com/app-test', - // redirectUrl: 'app:/callback', - // dangerouslyAllowInsecureHttpRequests: true, - // clientAuthMethod: 'post', - // }, - // } - // const connectionEntity: ConnectionEntity = connectionEntityFrom(connection) - // await dbConnection.getRepository(ConnectionEntity).save(connectionEntity, { - // transaction: true, - // }) - // - // const fromDb: ConnectionEntity | null = await dbConnection.getRepository(ConnectionEntity).findOne({ - // where: { type: connection.type }, - // }) - // - // expect(fromDb).toBeDefined() - // - // const fromDbConfig: OpenIdConfigEntity | null = await dbConnection.getRepository(OpenIdConfigEntity).findOne({ - // where: { id: fromDb?.id }, - // }) - // - // expect(fromDbConfig).toBeDefined() - // expect(fromDb?.type).toEqual(connection.type) - // expect(fromDb?.config).toBeDefined() - // expect((fromDb?.config).clientId).toEqual((connection.config).clientId) - // }) - // - // it('Should save connection with didauth config to database', async (): Promise => { - // const connection: IBasicConnection = { - // type: ConnectionTypeEnum.SIOPv2, - // config: { - // identifier: { - // did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - // provider: 'test_provider', - // keys: [], - // services: [], - // }, - // redirectUrl: 'https://example.com', - // stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', - // sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - // }, - // } - // const connectionEntity: ConnectionEntity = connectionEntityFrom(connection) - // await dbConnection.getRepository(ConnectionEntity).save(connectionEntity, { - // transaction: true, - // }) - // - // const fromDb: ConnectionEntity | null = await dbConnection.getRepository(ConnectionEntity).findOne({ - // where: { type: connection.type }, - // }) - // - // expect(fromDb).toBeDefined() - // - // const fromDbConfig: DidAuthConfigEntity | null = await dbConnection.getRepository(DidAuthConfigEntity).findOne({ - // where: { id: fromDb?.id }, - // }) - // - // expect(fromDbConfig).toBeDefined() - // expect(fromDb?.type).toEqual(connection.type) - // expect(fromDb?.config).toBeDefined() - // expect((fromDb?.config).identifier).toEqual((connection.config).identifier.did) - // }) - // - // it('Should save openid config to database', async (): Promise => { - // const clientId = '138d7bf8-c930-4c6e-b928-97d3a4928b01' - // const config: BasicOpenIdConfig = { - // clientId, - // clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', - // scopes: ['auth'], - // issuer: 'https://example.com/app-test', - // redirectUrl: 'app:/callback', - // dangerouslyAllowInsecureHttpRequests: true, - // clientAuthMethod: 'post', - // } - // - // const configEntity: OpenIdConfigEntity = openIdConfigEntityFrom(config) - // await dbConnection.getRepository(OpenIdConfigEntity).save(configEntity, { - // transaction: true, - // }) - // - // const fromDb: OpenIdConfigEntity | null = await dbConnection.getRepository(OpenIdConfigEntity).findOne({ - // where: { clientId: config.clientId }, - // }) - // - // expect(fromDb).toBeDefined() - // expect((fromDb).clientId).toEqual(config.clientId) - // }) - // - // it('Should save didauth config to database', async (): Promise => { - // const sessionId = 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01' - // const config: BasicDidAuthConfig = { - // identifier: { - // did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - // provider: 'test_provider', - // keys: [], - // services: [], - // }, - // redirectUrl: 'https://example.com', - // stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', - // sessionId, - // } - // - // const configEntity: DidAuthConfigEntity = didAuthConfigEntityFrom(config) - // await dbConnection.getRepository(DidAuthConfigEntity).save(configEntity, { - // transaction: true, - // }) - // - // const fromDb: DidAuthConfigEntity | null = await dbConnection.getRepository(DidAuthConfigEntity).findOne({ - // where: { sessionId: config.sessionId }, - // }) - // - // expect(fromDb).toBeDefined() - // expect((fromDb).identifier).toEqual(config.identifier.did) - // }) - // - // it('Should delete contact and all child relations', async (): Promise => { - // const contact1: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name1', - // }, - // contactOwner: { - // firstName: 'example_first_name1', - // middleName: 'example_middle_name1', - // lastName: 'example_last_name1', - // displayName: 'example_display_name1', - // }, - // } - // - // const contactEntity1: ContactEntity = contactEntityFrom(contact1) - // const savedContact1: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity1) - // - // expect(savedContact1).toBeDefined() - // - // const contact2: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - // name: 'example_name2', - // }, - // contactOwner: { - // firstName: 'example_first_name2', - // middleName: 'example_middle_name2', - // lastName: 'example_last_name2', - // displayName: 'example_display_name2', - // }, - // } - // - // const contactEntity2: ContactEntity = contactEntityFrom(contact2) - // const savedContact2: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity2) - // - // expect(savedContact2).toBeDefined() - // - // const correlationId = 'relation_example.com' - // const identity: IBasicIdentity = { - // alias: correlationId, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.URL, - // correlationId, - // }, - // connection: { - // type: ConnectionTypeEnum.OPENID_CONNECT, - // config: { - // clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', - // clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', - // scopes: ['auth'], - // issuer: 'https://example.com/app-test', - // redirectUrl: 'app:/callback', - // dangerouslyAllowInsecureHttpRequests: true, - // clientAuthMethod: 'post', - // }, - // }, - // metadata: [ - // { - // label: 'example_label', - // value: 'example_value', - // }, - // ], - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // identityEntity.contact = savedContact1 - // - // const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) - // - // expect(savedIdentity).toBeDefined() - // - // const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ - // left: savedContact1, - // right: savedContact2, - // }) - // - // const savedRelationship: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { - // transaction: true, - // }) - // - // expect(savedRelationship).toBeDefined() - // - // expect( - // await dbConnection.getRepository(ContactEntity).findOne({ - // where: { id: savedContact1.id }, - // }) - // ).toBeDefined() - // - // await dbConnection.getRepository(ContactEntity).delete({ id: savedContact1.id }) - // - // // check contact - // await expect( - // await dbConnection.getRepository(ContactEntity).findOne({ - // where: { id: savedContact1.id }, - // }) - // ).toBeNull() - // - // // check identity - // expect( - // await dbConnection.getRepository(IdentityEntity).findOne({ - // where: { id: savedContact1.id }, - // }) - // ).toBeNull() - // - // // check identity identifier - // expect( - // await dbConnection.getRepository(CorrelationIdentifierEntity).findOne({ - // where: { id: savedIdentity.identifier.id }, - // }) - // ).toBeNull() - // - // // check identity connection - // expect( - // await dbConnection.getRepository(ConnectionEntity).findOne({ - // where: { id: savedIdentity.connection!.id }, - // }) - // ).toBeNull() - // - // // check connection config - // expect( - // await dbConnection.getRepository(OpenIdConfigEntity).findOne({ - // where: { id: savedIdentity.connection!.config.id }, - // }) - // ).toBeNull() - // - // // check identity metadata - // expect( - // await dbConnection.getRepository(IdentityMetadataItemEntity).findOne({ - // where: { id: savedIdentity.metadata![0].id }, - // }) - // ).toBeNull() - // - // // check contact owner - // expect( - // await dbConnection.getRepository(ContactOwnerEntity).findOne({ - // where: { id: savedContact1.contactOwner.id }, - // }) - // ).toBeNull() - // - // // check contact type - // expect( - // await dbConnection.getRepository(ContactTypeEntity).findOne({ - // where: { id: savedContact1.contactType.id }, - // }) - // ).toBeDefined() - // - // // check relation - // expect( - // await dbConnection.getRepository(ContactRelationshipEntity).findOne({ - // where: { id: savedRelationship.id }, - // }) - // ).toBeNull() - // }) - // - // it('Should delete identity and all child relations', async (): Promise => { - // const contact: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contactOwner: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const contactEntity: ContactEntity = contactEntityFrom(contact) - // const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) - // - // expect(savedContact).toBeDefined() - // - // const correlationId = 'relation_example.com' - // const identity: IBasicIdentity = { - // alias: correlationId, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.URL, - // correlationId, - // }, - // connection: { - // type: ConnectionTypeEnum.SIOPv2, - // config: { - // identifier: { - // did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - // provider: 'test_provider', - // keys: [], - // services: [], - // }, - // redirectUrl: 'https://example.com', - // stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', - // sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - // }, - // }, - // metadata: [ - // { - // label: 'example_label', - // value: 'example_value', - // }, - // ], - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // identityEntity.contact = savedContact - // - // const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) - // - // expect( - // await dbConnection.getRepository(ContactEntity).findOne({ - // where: { id: savedContact.id }, - // }) - // ).toBeDefined() - // - // await dbConnection.getRepository(IdentityEntity).delete({ id: savedIdentity.id }) - // - // // check identity - // expect( - // await dbConnection.getRepository(IdentityEntity).findOne({ - // where: { alias: correlationId }, - // }) - // ).toBeNull() - // - // // check identity identifier - // expect( - // await dbConnection.getRepository(CorrelationIdentifierEntity).findOne({ - // where: { id: savedIdentity.identifier.id }, - // }) - // ).toBeNull() - // - // // check identity connection - // expect( - // await dbConnection.getRepository(ConnectionEntity).findOne({ - // where: { id: savedIdentity.connection!.id }, - // }) - // ).toBeNull() - // - // // check connection config - // expect( - // await dbConnection.getRepository(OpenIdConfigEntity).findOne({ - // where: { id: savedIdentity.connection!.config.id }, - // }) - // ).toBeNull() - // - // // check identity metadata - // expect( - // await dbConnection.getRepository(IdentityMetadataItemEntity).findOne({ - // where: { id: savedIdentity.metadata![0].id }, - // }) - // ).toBeNull() - // }) - // - // it('Should not delete contact when deleting identity', async (): Promise => { - // const contact: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contactOwner: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const contactEntity: ContactEntity = contactEntityFrom(contact) - // const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) - // - // expect(savedContact).toBeDefined() - // - // const correlationId = 'relation_example.com' - // const identity: IBasicIdentity = { - // alias: correlationId, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.URL, - // correlationId, - // }, - // connection: { - // type: ConnectionTypeEnum.SIOPv2, - // config: { - // identifier: { - // did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - // provider: 'test_provider', - // keys: [], - // services: [], - // }, - // redirectUrl: 'https://example.com', - // stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', - // sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - // }, - // }, - // metadata: [ - // { - // label: 'example_label', - // value: 'example_value', - // }, - // ], - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // identityEntity.contact = savedContact - // - // const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) - // - // expect(savedIdentity).toBeDefined() - // - // await dbConnection.getRepository(IdentityEntity).delete({ id: savedIdentity.id }) - // - // // check identity - // expect( - // await dbConnection.getRepository(IdentityEntity).findOne({ - // where: { id: savedIdentity.id }, - // }) - // ).toBeNull() - // - // // check contact - // expect( - // await dbConnection.getRepository(ContactEntity).findOne({ - // where: { id: savedContact.id }, - // }) - // ).toBeDefined() - // }) - // - // it('Should set creation date when saving contact', async (): Promise => { - // const contact: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contactOwner: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const contactEntity: ContactEntity = contactEntityFrom(contact) - // const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) - // - // const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - // where: { id: savedContact.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.createdAt).toBeDefined() - // }) - // - // it('Should not update creation date when updating contact', async (): Promise => { - // const contact: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contactOwner: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const contactEntity: ContactEntity = contactEntityFrom(contact) - // const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) - // - // expect(savedContact).toBeDefined() - // - // const newContactFirstName = 'new_first_name' - // await dbConnection.getRepository(ContactEntity).save({ - // ...savedContact, - // contactOwner: { - // ...savedContact.contactOwner, - // firstName: newContactFirstName, - // }, - // }) - // - // const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - // where: { id: savedContact.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect((fromDb?.contactOwner).firstName).toEqual(newContactFirstName) - // expect(fromDb?.createdAt).toEqual(savedContact?.createdAt) - // }) - // - // it('Should set creation date when saving identity', async (): Promise => { - // const correlationId = 'example_did' - // const identity: IBasicIdentity = { - // alias: correlationId, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId, - // }, - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // await dbConnection.getRepository(IdentityEntity).save(identityEntity) - // - // const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ - // where: { - // identifier: { - // correlationId, - // }, - // }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.createdAt).toBeDefined() - // }) - // - // it('Should not update creation date when saving identity', async (): Promise => { - // const correlationId = 'example_did' - // const identity: IBasicIdentity = { - // alias: correlationId, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId, - // }, - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) - // const newCorrelationId = 'new_example_did' - // await dbConnection - // .getRepository(IdentityEntity) - // .save({ ...savedIdentity, identifier: { ...savedIdentity.identifier, correlationId: newCorrelationId } }) - // - // const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ - // where: { - // identifier: { - // correlationId: newCorrelationId, - // }, - // }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.createdAt).toEqual(savedIdentity?.createdAt) - // }) - // - // it('Should set last updated date when saving contact', async (): Promise => { - // const contact: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contactOwner: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const contactEntity: ContactEntity = contactEntityFrom(contact) - // const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) - // - // const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - // where: { id: savedContact.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.lastUpdatedAt).toBeDefined() - // }) - // - // // TODO there is still an issue when updating nested objects, the parent does not update - // it('Should update last updated date when updating contact', async (): Promise => { - // const contact: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contactOwner: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const contactEntity: ContactEntity = contactEntityFrom(contact) - // const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) - // - // expect(savedContact).toBeDefined() - // - // // waiting here to get a different timestamp - // await new Promise((resolve) => setTimeout(resolve, 2000)) - // - // const newContactFirstName = 'new_first_name' - // await dbConnection.getRepository(ContactEntity).save({ - // ...savedContact, - // uri: 'new uri', // TODO remove this to trigger the bug - // contactOwner: { - // ...savedContact.contactOwner, - // firstName: newContactFirstName, - // }, - // }) - // - // const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - // where: { id: savedContact.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect((fromDb?.contactOwner).firstName).toEqual(newContactFirstName) - // expect(fromDb?.lastUpdatedAt).not.toEqual(savedContact?.lastUpdatedAt) - // }) - // - // it('Should set last updated date when saving contact type', async (): Promise => { - // const contactType: BasicContactType = { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // } - // - // const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) - // const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) - // - // const fromDb: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).findOne({ - // where: { id: savedContactType.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.lastUpdatedAt).toBeDefined() - // }) - // - // it('Should set last creation date when saving contact type', async (): Promise => { - // const contactType: BasicContactType = { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // } - // - // const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) - // const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) - // - // const fromDb: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).findOne({ - // where: { id: savedContactType.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.createdAt).toBeDefined() - // }) - // - // it('Should set last updated date when saving identity', async (): Promise => { - // const correlationId = 'example_did' - // const identity: IBasicIdentity = { - // alias: correlationId, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId, - // }, - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // await dbConnection.getRepository(IdentityEntity).save(identityEntity) - // - // const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ - // where: { - // identifier: { - // correlationId, - // }, - // }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.lastUpdatedAt).toBeDefined() - // }) - // - // it('Should enforce unique type and tenant id combination when saving contact type', async (): Promise => { - // const tenantId = 'non_unique_value' - // const name = 'non_unique_value' - // const contactType1: BasicContactType = { - // type: ContactTypeEnum.PERSON, - // tenantId, - // name, - // } - // - // const contactTypeEntity1: ContactTypeEntity = contactTypeEntityFrom(contactType1) - // const savedContactType1: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity1) - // - // expect(savedContactType1).toBeDefined() - // - // const contactType2: BasicContactType = { - // type: ContactTypeEnum.PERSON, - // tenantId, - // name, - // } - // - // const contactTypeEntity2: ContactTypeEntity = contactTypeEntityFrom(contactType2) - // await expect(dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity2)).rejects.toThrowError( - // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: contact_type_entity.type, contact_type_entity.tenantId' - // ) - // }) - // - // it('Should enforce unique name when saving contact type', async (): Promise => { - // const name = 'non_unique_value' - // const contactType1: BasicContactType = { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name, - // } - // - // const contactTypeEntity1: ContactTypeEntity = contactTypeEntityFrom(contactType1) - // const savedContactType1: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity1) - // - // expect(savedContactType1).toBeDefined() - // - // const contactType2: BasicContactType = { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - // name, - // } - // - // const contactTypeEntity2: ContactTypeEntity = contactTypeEntityFrom(contactType2) - // await expect(dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity2)).rejects.toThrowError( - // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: contact_type_entity.name' - // ) - // }) - // - // it('Should enforce unique legal name when saving organization', async (): Promise => { - // const legalName = 'non_unique_value' - // const organization1: BasicOrganization = { - // legalName, - // displayName: 'example_display_name', - // } - // - // const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) - // const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { - // transaction: true, - // }) - // - // expect(savedOrganization1).toBeDefined() - // - // const organization2: BasicOrganization = { - // legalName, - // displayName: 'example_display_name', - // } - // - // const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) - // await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( - // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.legalName' - // ) - // }) - // - // it('Should enforce unique display name when saving organization', async (): Promise => { - // const displayName = 'non_unique_value' - // const organization1: BasicOrganization = { - // legalName: 'example_legal_name1', - // displayName, - // } - // - // const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) - // const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { - // transaction: true, - // }) - // - // expect(savedOrganization1).toBeDefined() - // - // const organization2: BasicOrganization = { - // legalName: 'example_legal_name2', - // displayName, - // } - // - // const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) - // await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( - // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.displayName' - // ) - // }) - // - // it('Should enforce unique legal name when saving organization', async (): Promise => { - // const legalName = 'example_legal_name' - // const organization1: BasicOrganization = { - // legalName, - // displayName: 'example_display_name', - // } - // - // const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) - // const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { - // transaction: true, - // }) - // - // expect(savedOrganization1).toBeDefined() - // - // const organization2: BasicOrganization = { - // legalName, - // displayName: 'example_display_name', - // } - // - // const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) - // await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( - // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.legalName' - // ) - // }) - // - // it('Should enforce unique coc number when saving organization per tenant id', async (): Promise => { - // const contact: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.ORGANIZATION, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contactOwner: { - // legalName: 'example_legal_name', - // displayName: 'example_display_name', - // cocNumber: 'example_coc_number', - // }, - // } - // - // const contactEntity: ContactEntity = contactEntityFrom(contact) - // await dbConnection.getRepository(ContactEntity).save(contactEntity, { - // transaction: true, - // }) - // - // const contact2: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name2', - // }, - // contactOwner: { - // legalName: 'example_legal_name2', - // displayName: 'example_display_name2', - // cocNumber: 'example_coc_number', - // }, - // } - // - // const contactEntity2: ContactEntity = contactEntityFrom(contact2) - // await expect(dbConnection.getRepository(ContactEntity).save(contactEntity2, { transaction: true })).rejects.toThrowError( - // 'Coc number already in use' - // ) - // }) - // - // it('Should enforce unique display name when saving person', async (): Promise => { - // const displayName = 'non_unique_value' - // const person1: BasicPerson = { - // firstName: 'example_first_name1', - // lastName: 'lastName2', - // displayName, - // } - // - // const personEntity1: PersonEntity = personEntityFrom(person1) - // const savedPerson1: PersonEntity | null = await dbConnection.getRepository(PersonEntity).save(personEntity1, { - // transaction: true, - // }) - // - // expect(savedPerson1).toBeDefined() - // - // const person2: BasicPerson = { - // firstName: 'example_first_name2', - // lastName: 'lastName2', - // displayName, - // } - // - // const personEntity2: PersonEntity = personEntityFrom(person2) - // await expect(dbConnection.getRepository(PersonEntity).save(personEntity2)).rejects.toThrowError( - // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.displayName' - // ) - // }) - // - // it('Should save contact relationship to database', async (): Promise => { - // const contact1: IBasicContact = { - // uri: 'example1.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name1', - // }, - // contactOwner: { - // firstName: 'example_first_name1', - // middleName: 'example_middle_name1', - // lastName: 'example_last_name1', - // displayName: 'example_display_name1', - // }, - // } - // - // const contactEntity1: ContactEntity = contactEntityFrom(contact1) - // const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { - // transaction: true, - // }) - // - // expect(savedContact1).toBeDefined() - // - // const contact2: IBasicContact = { - // uri: 'example2.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - // name: 'example_name2', - // }, - // contactOwner: { - // firstName: 'example_first_name2', - // middleName: 'example_middle_name2', - // lastName: 'example_last_name2', - // displayName: 'example_display_name2', - // }, - // } - // - // const contactEntity2: ContactEntity = contactEntityFrom(contact2) - // const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { - // transaction: true, - // }) - // - // expect(savedContact2).toBeDefined() - // - // const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ - // left: savedContact1, - // right: savedContact2, - // }) - // - // await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { - // transaction: true, - // }) - // - // // TODO check the relation field - // const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - // where: { id: contactEntity1.id }, - // }) - // - // expect(fromDb).toBeDefined() - // }) - // - // it('Should set last updated date when saving contact relationship', async (): Promise => { - // const contact1: IBasicContact = { - // uri: 'example1.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name1', - // }, - // contactOwner: { - // firstName: 'example_first_name1', - // middleName: 'example_middle_name1', - // lastName: 'example_last_name1', - // displayName: 'example_display_name1', - // }, - // } - // - // const contactEntity1: ContactEntity = contactEntityFrom(contact1) - // const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { - // transaction: true, - // }) - // - // const contact2: IBasicContact = { - // uri: 'example2.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - // name: 'example_name2', - // }, - // contactOwner: { - // firstName: 'example_first_name2', - // middleName: 'example_middle_name2', - // lastName: 'example_last_name2', - // displayName: 'example_display_name2', - // }, - // } - // - // const contactEntity2: ContactEntity = contactEntityFrom(contact2) - // const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { - // transaction: true, - // }) - // - // const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ - // left: savedContact1, - // right: savedContact2, - // }) - // - // await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { - // transaction: true, - // }) - // - // const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - // where: { id: contactEntity1.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.lastUpdatedAt).toBeDefined() - // }) - // - // it('Should set creation date when saving contact relationship', async (): Promise => { - // const contact1: IBasicContact = { - // uri: 'example1.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name1', - // }, - // contactOwner: { - // firstName: 'example_first_name1', - // middleName: 'example_middle_name1', - // lastName: 'example_last_name1', - // displayName: 'example_display_name1', - // }, - // } - // - // const contactEntity1: ContactEntity = contactEntityFrom(contact1) - // const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { - // transaction: true, - // }) - // - // const contact2: IBasicContact = { - // uri: 'example2.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - // name: 'example_name2', - // }, - // contactOwner: { - // firstName: 'example_first_name2', - // middleName: 'example_middle_name2', - // lastName: 'example_last_name2', - // displayName: 'example_display_name2', - // }, - // } - // - // const contactEntity2: ContactEntity = contactEntityFrom(contact2) - // const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { - // transaction: true, - // }) - // - // const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ - // left: savedContact1, - // right: savedContact2, - // }) - // - // await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { - // transaction: true, - // }) - // - // const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - // where: { id: contactEntity1.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.createdAt).toBeDefined() - // }) - // - // it('Should save bidirectional contact relationships to database', async (): Promise => { - // const contact1: IBasicContact = { - // uri: 'example1.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name1', - // }, - // contactOwner: { - // firstName: 'example_first_name1', - // middleName: 'example_middle_name1', - // lastName: 'example_last_name1', - // displayName: 'example_display_name1', - // }, - // } - // - // const contactEntity1: ContactEntity = contactEntityFrom(contact1) - // const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { - // transaction: true, - // }) - // - // expect(savedContact1).toBeDefined() - // - // const contact2: IBasicContact = { - // uri: 'example2.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - // name: 'example_name2', - // }, - // contactOwner: { - // firstName: 'example_first_name2', - // middleName: 'example_middle_name2', - // lastName: 'example_last_name2', - // displayName: 'example_display_name2', - // }, - // } - // - // const contactEntity2: ContactEntity = contactEntityFrom(contact2) - // const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { - // transaction: true, - // }) - // - // expect(savedContact2).toBeDefined() - // - // const relationship1: ContactRelationshipEntity = contactRelationshipEntityFrom({ - // left: savedContact1, - // right: savedContact2, - // }) - // - // const savedRelationship1: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship1, { - // transaction: true, - // }) - // - // expect(savedRelationship1).toBeDefined() - // - // const relationship2: ContactRelationshipEntity = contactRelationshipEntityFrom({ - // left: savedContact2, - // right: savedContact1, - // }) - // - // const savedRelationship2: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship2, { - // transaction: true, - // }) - // - // expect(savedRelationship2).toBeDefined() - // - // const fromDb: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).findOne({ - // where: { id: savedRelationship2.id }, - // }) - // - // expect(fromDb).toBeDefined() - // }) - // - // it('Should enforce unique owner combination for contact relationship', async (): Promise => { - // const contact1: IBasicContact = { - // uri: 'example1.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name1', - // }, - // contactOwner: { - // firstName: 'example_first_name1', - // middleName: 'example_middle_name1', - // lastName: 'example_last_name1', - // displayName: 'example_display_name1', - // }, - // } - // - // const contactEntity1: ContactEntity = contactEntityFrom(contact1) - // const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { - // transaction: true, - // }) - // - // expect(savedContact1).toBeDefined() - // - // const contact2: IBasicContact = { - // uri: 'example2.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - // name: 'example_name2', - // }, - // contactOwner: { - // firstName: 'example_first_name2', - // middleName: 'example_middle_name2', - // lastName: 'example_last_name2', - // displayName: 'example_display_name2', - // }, - // } - // - // const contactEntity2: ContactEntity = contactEntityFrom(contact2) - // const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { - // transaction: true, - // }) - // - // expect(savedContact2).toBeDefined() - // - // const relationship1: ContactRelationshipEntity = contactRelationshipEntityFrom({ - // left: savedContact1, - // right: savedContact2, - // }) - // - // const savedRelationship1: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship1, { - // transaction: true, - // }) - // - // expect(savedRelationship1).toBeDefined() - // - // const relationship2: ContactRelationshipEntity = contactRelationshipEntityFrom({ - // left: savedContact1, - // right: savedContact2, - // }) - // - // await expect(dbConnection.getRepository(ContactRelationshipEntity).save(relationship2)).rejects.toThrowError( - // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: contact_relationship_entity.leftId, contact_relationship_entity.rightId' - // ) - // }) - // - // it('Should save contact type to database', async (): Promise => { - // const contactType: BasicContactType = { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // } - // - // const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) - // const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) - // - // const fromDb: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).findOne({ - // where: { id: savedContactType.id }, - // }) - // - // expect(fromDb).toBeDefined() - // }) - // - // it('Should save person to database', async (): Promise => { - // const person: BasicPerson = { - // firstName: 'example_first_name', - // lastName: 'lastName2', - // displayName: 'displayName', - // } - // - // const personEntity: PersonEntity = personEntityFrom(person) - // const savedPerson: PersonEntity | null = await dbConnection.getRepository(PersonEntity).save(personEntity, { - // transaction: true, - // }) - // - // const fromDb: PersonEntity | null = await dbConnection.getRepository(PersonEntity).findOne({ - // where: { id: savedPerson.id }, - // }) - // - // expect(fromDb).toBeDefined() - // }) - // - // it('Should set last updated date when saving person', async (): Promise => { - // const person: BasicPerson = { - // firstName: 'example_first_name', - // lastName: 'lastName2', - // displayName: 'displayName', - // } - // - // const personEntity: PersonEntity = personEntityFrom(person) - // const savedPerson: PersonEntity | null = await dbConnection.getRepository(PersonEntity).save(personEntity, { - // transaction: true, - // }) - // - // const fromDb: PersonEntity | null = await dbConnection.getRepository(PersonEntity).findOne({ - // where: { id: savedPerson.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.lastUpdatedAt).toBeDefined() - // }) - // - // it('Should set creation date when saving person', async (): Promise => { - // const person: BasicPerson = { - // firstName: 'example_first_name', - // lastName: 'lastName2', - // displayName: 'displayName', - // } - // - // const personEntity: PersonEntity = personEntityFrom(person) - // const savedPerson: PersonEntity | null = await dbConnection.getRepository(PersonEntity).save(personEntity, { - // transaction: true, - // }) - // - // const fromDb: PersonEntity | null = await dbConnection.getRepository(PersonEntity).findOne({ - // where: { id: savedPerson.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.createdAt).toBeDefined() - // }) - // - // it('Should save organization to database', async (): Promise => { - // const organization: BasicOrganization = { - // legalName: 'example_legal_name', - // displayName: 'example_display_name', - // } - // - // const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) - // const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { - // transaction: true, - // }) - // - // const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ - // where: { id: savedOrganization.id }, - // }) - // - // expect(fromDb).toBeDefined() - // }) - // - // it('Should set last updated date when saving organization', async (): Promise => { - // const organization: BasicOrganization = { - // legalName: 'example_legal_name', - // displayName: 'example_display_name', - // } - // - // const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) - // const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { - // transaction: true, - // }) - // - // const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ - // where: { id: savedOrganization.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.lastUpdatedAt).toBeDefined() - // }) - // - // it('Should set creation date when saving organization', async (): Promise => { - // const organization: BasicOrganization = { - // legalName: 'example_legal_name', - // displayName: 'example_display_name', - // } - // - // const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) - // const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { - // transaction: true, - // }) - // - // const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ - // where: { id: savedOrganization.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.createdAt).toBeDefined() - // }) - // - // it('Should get contact based on person information', async (): Promise => { - // const firstName = 'example_first_name' - // const contact: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contactOwner: { - // firstName, - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const contactEntity: ContactEntity = contactEntityFrom(contact) - // await dbConnection.getRepository(ContactEntity).save(contactEntity, { - // transaction: true, - // }) - // - // const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - // where: { - // contactOwner: { - // firstName, - // } as FindOptionsWhere, - // }, - // }) - // - // expect(fromDb).toBeDefined() - // }) - // - // it('Should get contact based on organization information', async (): Promise => { - // const legalName = 'example_legal_name' - // const contact: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.ORGANIZATION, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contactOwner: { - // legalName, - // displayName: 'example_display_name', - // cocNumber: 'example_coc_number', - // }, - // } - // - // const contactEntity: ContactEntity = contactEntityFrom(contact) - // await dbConnection.getRepository(ContactEntity).save(contactEntity, { - // transaction: true, - // }) - // - // const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - // where: { - // contactOwner: { - // legalName, - // } as FindOptionsWhere, - // }, - // }) - // - // expect(fromDb).toBeDefined() - // }) - // - // it("Should enforce unique contact id's for relationship sides", async (): Promise => { - // const contact: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contactOwner: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const contactEntity: ContactEntity = contactEntityFrom(contact) - // const savedContact: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity, { - // transaction: true, - // }) - // - // expect(savedContact).toBeDefined() - // - // const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ - // left: savedContact, - // right: savedContact, - // }) - // - // await expect(dbConnection.getRepository(ContactRelationshipEntity).save(relationship)).rejects.toThrowError( - // 'Cannot use the same id for both sides of the relationship' - // ) - // }) - // - // it('Should delete contact relationship', async (): Promise => { - // const contact1: IBasicContact = { - // uri: 'example1.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name1', - // }, - // contactOwner: { - // firstName: 'example_first_name1', - // middleName: 'example_middle_name1', - // lastName: 'example_last_name1', - // displayName: 'example_display_name1', - // }, - // } - // - // const contactEntity1: ContactEntity = contactEntityFrom(contact1) - // const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { - // transaction: true, - // }) - // - // expect(savedContact1).toBeDefined() - // - // const contact2: IBasicContact = { - // uri: 'example2.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - // name: 'example_name2', - // }, - // contactOwner: { - // firstName: 'example_first_name2', - // middleName: 'example_middle_name2', - // lastName: 'example_last_name2', - // displayName: 'example_display_name2', - // }, - // } - // - // const contactEntity2: ContactEntity = contactEntityFrom(contact2) - // const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { - // transaction: true, - // }) - // - // expect(savedContact2).toBeDefined() - // - // const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ - // left: savedContact1, - // right: savedContact2, - // }) - // - // const savedRelationship: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { - // transaction: true, - // }) - // - // expect(savedRelationship).toBeDefined() - // - // await dbConnection.getRepository(ContactRelationshipEntity).delete({ id: savedRelationship.id }) - // - // await expect( - // await dbConnection.getRepository(ContactRelationshipEntity).findOne({ - // where: { id: savedRelationship.id }, - // }) - // ).toBeNull() - // }) - // - // it('Should delete contact type', async (): Promise => { - // const contactType: BasicContactType = { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // } - // - // const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) - // const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) - // - // expect(savedContactType).toBeDefined() - // - // await dbConnection.getRepository(ContactTypeEntity).delete({ id: savedContactType.id }) - // - // await expect( - // await dbConnection.getRepository(ContactTypeEntity).findOne({ - // where: { id: savedContactType.id }, - // }) - // ).toBeNull() - // }) - // - // it('Should not be able to remove contact type when used by contacts', async (): Promise => { - // const contact: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contactOwner: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const contactEntity: ContactEntity = contactEntityFrom(contact) - // const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity, { - // transaction: true, - // }) - // - // expect(savedContact).toBeDefined() - // - // await expect(dbConnection.getRepository(ContactTypeEntity).delete({ id: savedContact.contactType.id })).rejects.toThrowError( - // 'FOREIGN KEY constraint failed' - // ) - // }) - // - // it('Should save contact with existing contact type', async (): Promise => { - // const contactType: BasicContactType = { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // } - // - // const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) - // const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) - // - // const contact: IBasicContact = { - // uri: 'example.com', - // contactType: savedContactType, - // contactOwner: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const contactEntity: ContactEntity = contactEntityFrom(contact) - // contactEntity.contactType = savedContactType - // await dbConnection.getRepository(ContactEntity).save(contactEntity, { - // transaction: true, - // }) - // - // const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - // where: { id: contactEntity.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.contactType).toBeDefined() - // expect(fromDb?.contactType.id).toEqual(savedContactType.id) - // expect(fromDb?.contactType.type).toEqual(savedContactType.type) - // expect(fromDb?.contactType.tenantId).toEqual(savedContactType.tenantId) - // expect(fromDb?.contactType.name).toEqual(savedContactType.name) - // }) - // - // // TODO not update creation date when saving contact type - // // TODO add test for updating nested field and checking last updated at on parent + + it('Should save organization contact to database', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.ORGANIZATION, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + legalName: 'example_legal_name', + displayName: 'example_display_name', + cocNumber: 'example_coc_number', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + await dbConnection.getRepository(ContactEntity).save(contactEntity, { + transaction: true, + }) + + const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: contactEntity.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.identities?.length).toEqual(0) + expect(fromDb?.uri).toEqual(contact.uri) + expect(fromDb?.contactType).toBeDefined() + expect(fromDb?.contactType.type).toEqual(contact.contactType.type) + expect(fromDb?.contactType.tenantId).toEqual(contact.contactType.tenantId) + expect(fromDb?.contactType.name).toEqual(contact.contactType.name) + expect(fromDb?.contactOwner).toBeDefined() + expect((fromDb?.contactOwner).legalName).toEqual((contact.contactOwner).legalName) + expect((fromDb?.contactOwner).displayName).toEqual((contact.contactOwner).displayName) + expect((fromDb?.contactOwner).cocNumber).toEqual((contact.contactOwner).cocNumber) + }) + + it('Should result in contact relationship for the owner side only', async (): Promise => { + const contact1: IBasicContact = { + uri: 'example1.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const contactEntity1: ContactEntity = contactEntityFrom(contact1) + const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + transaction: true, + }) + + const contact2: IBasicContact = { + uri: 'example2.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + + const contactEntity2: ContactEntity = contactEntityFrom(contact2) + const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + transaction: true, + }) + + const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ + leftId: savedContact1.id, + rightId: savedContact2.id, + }) + + await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { + transaction: true, + }) + + const fromDb1: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: savedContact1.id }, + }) + + const fromDb2: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: savedContact2.id }, + }) + + expect(fromDb1).toBeDefined() + expect(fromDb1?.relationships.length).toEqual(1) + expect(fromDb2).toBeDefined() + expect(fromDb2?.relationships.length).toEqual(0) + }) + + it('should throw error when saving person contact with blank first name', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: '', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank first names are not allowed') + }) + + it('should throw error when saving person contact with blank middle name', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: '', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank middle names are not allowed') + }) + + it('should throw error when saving person contact with blank last name', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: '', + displayName: 'example_display_name', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank last names are not allowed') + }) + + it('should throw error when saving person contact with blank display name', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: '', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank display names are not allowed') + }) + + it('should throw error when saving organization contact with blank legal name', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.ORGANIZATION, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + legalName: '', + displayName: 'example_legal_name', + cocNumber: 'example_coc_number', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank legal names are not allowed') + }) + + it('should throw error when saving organization contact with blank display name', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.ORGANIZATION, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + legalName: 'example_first_name', + displayName: '', + cocNumber: 'example_coc_number', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank display names are not allowed') + }) + + it('should throw error when saving organization contact with blank coc number', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.ORGANIZATION, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + legalName: 'example_first_name', + displayName: 'example_display_name', + cocNumber: '', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank coc numbers are not allowed') + }) + + it('should throw error when saving contact with blank contact type name', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: '', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank names are not allowed') + }) + + it('should throw error when saving contact with blank contact type description', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + description: '', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank descriptions are not allowed') + }) + + it('should throw error when saving contact with blank contact type tenant id', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError("Blank tenant id's are not allowed") + }) + + it('Should enforce unique display name for a person contact', async (): Promise => { + const contactDisplayName = 'non_unique_name' + const contact1: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: contactDisplayName, + }, + } + const contact1Entity: ContactEntity = contactEntityFrom(contact1) + await dbConnection.getRepository(ContactEntity).save(contact1Entity) + + const contact2: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: contactDisplayName, + }, + } + const contact2Entity: ContactEntity = contactEntityFrom(contact2) + + await expect(dbConnection.getRepository(ContactEntity).save(contact2Entity)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactType.name' + ) + }) + + it('Should enforce unique display name for a organization contact', async (): Promise => { + const contactDisplayName = 'non_unique_name' + const contact1: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.ORGANIZATION, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name', + }, + contactOwner: { + legalName: 'example_first_name', + displayName: contactDisplayName, + cocNumber: 'example_coc_number', + }, + } + const contact1Entity: ContactEntity = contactEntityFrom(contact1) + await dbConnection.getRepository(ContactEntity).save(contact1Entity) + + const contact2: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.ORGANIZATION, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + legalName: 'example_first_name', + displayName: contactDisplayName, + cocNumber: 'example_coc_number', + }, + } + const contact2Entity: ContactEntity = contactEntityFrom(contact2) + + await expect(dbConnection.getRepository(ContactEntity).save(contact2Entity)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactType.name' + ) + }) + + it('Should enforce unique alias for an identity', async (): Promise => { + const alias = 'non_unique_alias' + const identity1: IBasicIdentity = { + alias, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId: 'unique_correlationId1', + }, + } + const identity1Entity: IdentityEntity = identityEntityFrom(identity1) + await dbConnection.getRepository(IdentityEntity).save(identity1Entity) + + const identity2: IBasicIdentity = { + alias: alias, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId: 'unique_correlationId2', + }, + } + const identity2Entity: IdentityEntity = identityEntityFrom(identity2) + await expect(dbConnection.getRepository(IdentityEntity).save(identity2Entity)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: Identity.alias' + ) + }) + + it('Should enforce unique correlationId for a identity', async (): Promise => { + const correlationId = 'non_unique_correlationId' + const identity1: IBasicIdentity = { + alias: 'unique_alias1', + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId, + }, + } + const identity1Entity: IdentityEntity = identityEntityFrom(identity1) + await dbConnection.getRepository(IdentityEntity).save(identity1Entity) + + const identity2: IBasicIdentity = { + alias: 'unique_alias2', + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId, + }, + } + const identity2Entity: IdentityEntity = identityEntityFrom(identity2) + await expect(dbConnection.getRepository(IdentityEntity).save(identity2Entity)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: CorrelationIdentifier.correlation_id' + ) + }) + + it('Should save identity to database', async (): Promise => { + const correlationId = 'example_did' + const identity: IBasicIdentity = { + alias: correlationId, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId, + }, + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + + await dbConnection.getRepository(IdentityEntity).save(identityEntity) + + const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ + where: { + identifier: { + correlationId, + }, + }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.connection).toBeNull() + expect(fromDb?.identifier).toBeDefined() + expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) + expect(fromDb?.identifier.type).toEqual(identity.identifier.type) + }) + + it('should throw error when saving identity with blank alias', async (): Promise => { + const identity: IBasicIdentity = { + alias: '', + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId: 'example_did', + }, + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + + await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank aliases are not allowed') + }) + + it('should throw error when saving identity with blank correlation id', async (): Promise => { + const identity: IBasicIdentity = { + alias: 'example_did', + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId: '', + }, + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + + await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank correlation ids are not allowed') + }) + + it('should throw error when saving identity with blank metadata label', async (): Promise => { + const correlationId = 'example_did' + const identity: IBasicIdentity = { + alias: correlationId, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId, + }, + metadata: [ + { + label: '', + value: 'example_value', + }, + ], + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + + await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank metadata labels are not allowed') + }) + + it('should throw error when saving identity with blank metadata value', async (): Promise => { + const correlationId = 'example_did' + const identity: IBasicIdentity = { + alias: correlationId, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId, + }, + metadata: [ + { + label: 'example_label', + value: '', + }, + ], + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + + await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank metadata values are not allowed') + }) + + it('Should save identity with openid connection to database', async (): Promise => { + const correlationId = 'example.com' + const identity: IBasicIdentity = { + alias: correlationId, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.URL, + correlationId, + }, + connection: { + type: ConnectionTypeEnum.OPENID_CONNECT, + config: { + clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', + clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', + scopes: ['auth'], + issuer: 'https://example.com/app-test', + redirectUrl: 'app:/callback', + dangerouslyAllowInsecureHttpRequests: true, + clientAuthMethod: 'post', + }, + }, + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + + await dbConnection.getRepository(IdentityEntity).save(identityEntity) + + const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ + where: { + identifier: { + correlationId, + }, + }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.connection).toBeDefined() + expect(fromDb?.identifier).toBeDefined() + expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) + expect(fromDb?.identifier.type).toEqual(identity.identifier.type) + expect(fromDb?.connection?.type).toEqual(identity.connection?.type) + expect(fromDb?.connection?.config).toBeDefined() + expect((fromDb?.connection?.config).clientId).toEqual((identity.connection?.config).clientId) + }) + + it('Should save identity with didauth connection to database', async (): Promise => { + const correlationId = 'example.com' + const identity: IBasicIdentity = { + alias: correlationId, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.URL, + correlationId, + }, + connection: { + type: ConnectionTypeEnum.SIOPv2, + config: { + identifier: { + did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + provider: 'test_provider', + keys: [], + services: [], + }, + redirectUrl: 'https://example.com', + stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', + sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + }, + }, + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + + await dbConnection.getRepository(IdentityEntity).save(identityEntity) + + const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ + where: { + identifier: { + correlationId, + }, + }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.connection).toBeDefined() + expect(fromDb?.identifier).toBeDefined() + expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) + expect(fromDb?.identifier.type).toEqual(identity.identifier.type) + expect(fromDb?.connection?.type).toEqual(identity.connection?.type) + expect(fromDb?.connection?.config).toBeDefined() + expect((fromDb?.connection?.config).identifier).toEqual((identity.connection?.config).identifier.did) + }) + + it('Should save connection with openid config to database', async (): Promise => { + const connection: IBasicConnection = { + type: ConnectionTypeEnum.OPENID_CONNECT, + config: { + clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', + clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', + scopes: ['auth'], + issuer: 'https://example.com/app-test', + redirectUrl: 'app:/callback', + dangerouslyAllowInsecureHttpRequests: true, + clientAuthMethod: 'post', + }, + } + const connectionEntity: ConnectionEntity = connectionEntityFrom(connection) + await dbConnection.getRepository(ConnectionEntity).save(connectionEntity, { + transaction: true, + }) + + const fromDb: ConnectionEntity | null = await dbConnection.getRepository(ConnectionEntity).findOne({ + where: { type: connection.type }, + }) + + expect(fromDb).toBeDefined() + + const fromDbConfig: OpenIdConfigEntity | null = await dbConnection.getRepository(OpenIdConfigEntity).findOne({ + where: { id: fromDb?.id }, + }) + + expect(fromDbConfig).toBeDefined() + expect(fromDb?.type).toEqual(connection.type) + expect(fromDb?.config).toBeDefined() + expect((fromDb?.config).clientId).toEqual((connection.config).clientId) + }) + + it('Should save connection with didauth config to database', async (): Promise => { + const connection: IBasicConnection = { + type: ConnectionTypeEnum.SIOPv2, + config: { + identifier: { + did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + provider: 'test_provider', + keys: [], + services: [], + }, + redirectUrl: 'https://example.com', + stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', + sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + }, + } + const connectionEntity: ConnectionEntity = connectionEntityFrom(connection) + await dbConnection.getRepository(ConnectionEntity).save(connectionEntity, { + transaction: true, + }) + + const fromDb: ConnectionEntity | null = await dbConnection.getRepository(ConnectionEntity).findOne({ + where: { type: connection.type }, + }) + + expect(fromDb).toBeDefined() + + const fromDbConfig: DidAuthConfigEntity | null = await dbConnection.getRepository(DidAuthConfigEntity).findOne({ + where: { id: fromDb?.id }, + }) + + expect(fromDbConfig).toBeDefined() + expect(fromDb?.type).toEqual(connection.type) + expect(fromDb?.config).toBeDefined() + expect((fromDb?.config).identifier).toEqual((connection.config).identifier.did) + }) + + it('Should save openid config to database', async (): Promise => { + const clientId = '138d7bf8-c930-4c6e-b928-97d3a4928b01' + const config: BasicOpenIdConfig = { + clientId, + clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', + scopes: ['auth'], + issuer: 'https://example.com/app-test', + redirectUrl: 'app:/callback', + dangerouslyAllowInsecureHttpRequests: true, + clientAuthMethod: 'post', + } + + const configEntity: OpenIdConfigEntity = openIdConfigEntityFrom(config) + await dbConnection.getRepository(OpenIdConfigEntity).save(configEntity, { + transaction: true, + }) + + const fromDb: OpenIdConfigEntity | null = await dbConnection.getRepository(OpenIdConfigEntity).findOne({ + where: { clientId: config.clientId }, + }) + + expect(fromDb).toBeDefined() + expect((fromDb).clientId).toEqual(config.clientId) + }) + + it('Should save didauth config to database', async (): Promise => { + const sessionId = 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01' + const config: BasicDidAuthConfig = { + identifier: { + did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + provider: 'test_provider', + keys: [], + services: [], + }, + redirectUrl: 'https://example.com', + stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', + sessionId, + } + + const configEntity: DidAuthConfigEntity = didAuthConfigEntityFrom(config) + await dbConnection.getRepository(DidAuthConfigEntity).save(configEntity, { + transaction: true, + }) + + const fromDb: DidAuthConfigEntity | null = await dbConnection.getRepository(DidAuthConfigEntity).findOne({ + where: { sessionId: config.sessionId }, + }) + + expect(fromDb).toBeDefined() + expect((fromDb).identifier).toEqual(config.identifier.did) + }) + + it('Should delete contact and all child relations', async (): Promise => { + const contact1: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const contactEntity1: ContactEntity = contactEntityFrom(contact1) + const savedContact1: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity1) + + expect(savedContact1).toBeDefined() + + const contact2: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + + const contactEntity2: ContactEntity = contactEntityFrom(contact2) + const savedContact2: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity2) + + expect(savedContact2).toBeDefined() + + const correlationId = 'relation_example.com' + const identity: IBasicIdentity = { + alias: correlationId, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.URL, + correlationId, + }, + connection: { + type: ConnectionTypeEnum.OPENID_CONNECT, + config: { + clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', + clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', + scopes: ['auth'], + issuer: 'https://example.com/app-test', + redirectUrl: 'app:/callback', + dangerouslyAllowInsecureHttpRequests: true, + clientAuthMethod: 'post', + }, + }, + metadata: [ + { + label: 'example_label', + value: 'example_value', + }, + ], + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + identityEntity.contact = savedContact1 + + const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) + + expect(savedIdentity).toBeDefined() + + const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ + leftId: savedContact1.id, + rightId: savedContact2.id, + }) + + const savedRelationship: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { + transaction: true, + }) + + expect(savedRelationship).toBeDefined() + + expect( + await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: savedContact1.id }, + }) + ).toBeDefined() + + await dbConnection.getRepository(ContactEntity).delete({ id: savedContact1.id }) + + // check contact + await expect( + await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: savedContact1.id }, + }) + ).toBeNull() + + // check identity + expect( + await dbConnection.getRepository(IdentityEntity).findOne({ + where: { id: savedContact1.id }, + }) + ).toBeNull() + + // check identity identifier + expect( + await dbConnection.getRepository(CorrelationIdentifierEntity).findOne({ + where: { id: savedIdentity.identifier.id }, + }) + ).toBeNull() + + // check identity connection + expect( + await dbConnection.getRepository(ConnectionEntity).findOne({ + where: { id: savedIdentity.connection!.id }, + }) + ).toBeNull() + + // check connection config + expect( + await dbConnection.getRepository(OpenIdConfigEntity).findOne({ + where: { id: savedIdentity.connection!.config.id }, + }) + ).toBeNull() + + // check identity metadata + expect( + await dbConnection.getRepository(IdentityMetadataItemEntity).findOne({ + where: { id: savedIdentity.metadata![0].id }, + }) + ).toBeNull() + + // check contact owner + expect( + await dbConnection.getRepository(ContactOwnerEntity).findOne({ + where: { id: savedContact1.contactOwner.id }, + }) + ).toBeNull() + + // check contact type + expect( + await dbConnection.getRepository(ContactTypeEntity).findOne({ + where: { id: savedContact1.contactType.id }, + }) + ).toBeDefined() + + // check relation + expect( + await dbConnection.getRepository(ContactRelationshipEntity).findOne({ + where: { id: savedRelationship.id }, + }) + ).toBeNull() + }) + + it('Should delete identity and all child relations', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) + + expect(savedContact).toBeDefined() + + const correlationId = 'relation_example.com' + const identity: IBasicIdentity = { + alias: correlationId, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.URL, + correlationId, + }, + connection: { + type: ConnectionTypeEnum.SIOPv2, + config: { + identifier: { + did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + provider: 'test_provider', + keys: [], + services: [], + }, + redirectUrl: 'https://example.com', + stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', + sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + }, + }, + metadata: [ + { + label: 'example_label', + value: 'example_value', + }, + ], + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + identityEntity.contact = savedContact + + const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) + + expect( + await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: savedContact.id }, + }) + ).toBeDefined() + + await dbConnection.getRepository(IdentityEntity).delete({ id: savedIdentity.id }) + + // check identity + expect( + await dbConnection.getRepository(IdentityEntity).findOne({ + where: { alias: correlationId }, + }) + ).toBeNull() + + // check identity identifier + expect( + await dbConnection.getRepository(CorrelationIdentifierEntity).findOne({ + where: { id: savedIdentity.identifier.id }, + }) + ).toBeNull() + + // check identity connection + expect( + await dbConnection.getRepository(ConnectionEntity).findOne({ + where: { id: savedIdentity.connection!.id }, + }) + ).toBeNull() + + // check connection config + expect( + await dbConnection.getRepository(OpenIdConfigEntity).findOne({ + where: { id: savedIdentity.connection!.config.id }, + }) + ).toBeNull() + + // check identity metadata + expect( + await dbConnection.getRepository(IdentityMetadataItemEntity).findOne({ + where: { id: savedIdentity.metadata![0].id }, + }) + ).toBeNull() + }) + + it('Should not delete contact when deleting identity', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) + + expect(savedContact).toBeDefined() + + const correlationId = 'relation_example.com' + const identity: IBasicIdentity = { + alias: correlationId, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.URL, + correlationId, + }, + connection: { + type: ConnectionTypeEnum.SIOPv2, + config: { + identifier: { + did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + provider: 'test_provider', + keys: [], + services: [], + }, + redirectUrl: 'https://example.com', + stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', + sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + }, + }, + metadata: [ + { + label: 'example_label', + value: 'example_value', + }, + ], + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + identityEntity.contact = savedContact + + const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) + + expect(savedIdentity).toBeDefined() + + await dbConnection.getRepository(IdentityEntity).delete({ id: savedIdentity.id }) + + // check identity + expect( + await dbConnection.getRepository(IdentityEntity).findOne({ + where: { id: savedIdentity.id }, + }) + ).toBeNull() + + // check contact + expect( + await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: savedContact.id }, + }) + ).toBeDefined() + }) + + it('Should set creation date when saving contact', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) + + const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: savedContact.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.createdAt).toBeDefined() + }) + + it('Should not update creation date when updating contact', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) + + expect(savedContact).toBeDefined() + + const newContactFirstName = 'new_first_name' + await dbConnection.getRepository(ContactEntity).save({ + ...savedContact, + contactOwner: { + ...savedContact.contactOwner, + firstName: newContactFirstName, + }, + }) + + const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: savedContact.id }, + }) + + expect(fromDb).toBeDefined() + expect((fromDb?.contactOwner).firstName).toEqual(newContactFirstName) + expect(fromDb?.createdAt).toEqual(savedContact?.createdAt) + }) + + it('Should set creation date when saving identity', async (): Promise => { + const correlationId = 'example_did' + const identity: IBasicIdentity = { + alias: correlationId, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId, + }, + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + await dbConnection.getRepository(IdentityEntity).save(identityEntity) + + const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ + where: { + identifier: { + correlationId, + }, + }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.createdAt).toBeDefined() + }) + + it('Should not update creation date when saving identity', async (): Promise => { + const correlationId = 'example_did' + const identity: IBasicIdentity = { + alias: correlationId, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId, + }, + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) + const newCorrelationId = 'new_example_did' + await dbConnection + .getRepository(IdentityEntity) + .save({ ...savedIdentity, identifier: { ...savedIdentity.identifier, correlationId: newCorrelationId } }) + + const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ + where: { + identifier: { + correlationId: newCorrelationId, + }, + }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.createdAt).toEqual(savedIdentity?.createdAt) + }) + + it('Should set last updated date when saving contact', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) + + const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: savedContact.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.lastUpdatedAt).toBeDefined() + }) + + it('Should update last updated date when updating contact', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) + expect(savedContact).toBeDefined() + + // waiting here to get a different timestamp + await new Promise((resolve) => setTimeout(resolve, 2000)) + + const newContactFirstName = 'new_first_name' + await dbConnection.getRepository(ContactEntity).save({ + ...savedContact, + // FIXME there is still an issue when updating nested objects, the parent does not update + // https://github.com/typeorm/typeorm/issues/5378 + uri: 'new uri', // TODO remove this to trigger the bug + contactOwner: { + ...savedContact.contactOwner, + firstName: newContactFirstName, + }, + }) + + const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: savedContact.id }, + }) + + expect(fromDb).toBeDefined() + expect((fromDb?.contactOwner).firstName).toEqual(newContactFirstName) + expect(fromDb?.lastUpdatedAt).not.toEqual(savedContact?.lastUpdatedAt) + }) + + it('Should set last updated date when saving contact type', async (): Promise => { + const contactType: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + } + + const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) + const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) + + const fromDb: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).findOne({ + where: { id: savedContactType.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.lastUpdatedAt).toBeDefined() + }) + + it('Should set last creation date when saving contact type', async (): Promise => { + const contactType: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + } + + const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) + const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) + + const fromDb: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).findOne({ + where: { id: savedContactType.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.createdAt).toBeDefined() + }) + + it('Should set last updated date when saving identity', async (): Promise => { + const correlationId = 'example_did' + const identity: IBasicIdentity = { + alias: correlationId, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId, + }, + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + await dbConnection.getRepository(IdentityEntity).save(identityEntity) + + const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ + where: { + identifier: { + correlationId, + }, + }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.lastUpdatedAt).toBeDefined() + }) + + it('Should enforce unique type and tenant id combination when saving contact type', async (): Promise => { + const tenantId = 'non_unique_value' + const name = 'non_unique_value' + const contactType1: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId, + name, + } + + const contactTypeEntity1: ContactTypeEntity = contactTypeEntityFrom(contactType1) + const savedContactType1: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity1) + + expect(savedContactType1).toBeDefined() + + const contactType2: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId, + name, + } + + const contactTypeEntity2: ContactTypeEntity = contactTypeEntityFrom(contactType2) + await expect(dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity2)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactType.type, ContactType.tenantId' + ) + }) + + it('Should enforce unique name when saving contact type', async (): Promise => { + const name = 'non_unique_value' + const contactType1: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name, + } + + const contactTypeEntity1: ContactTypeEntity = contactTypeEntityFrom(contactType1) + const savedContactType1: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity1) + + expect(savedContactType1).toBeDefined() + + const contactType2: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name, + } + + const contactTypeEntity2: ContactTypeEntity = contactTypeEntityFrom(contactType2) + await expect(dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity2)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactType.name' + ) + }) + + it('Should enforce unique legal name when saving organization', async (): Promise => { + const legalName = 'non_unique_value' + const organization1: BasicOrganization = { + legalName, + displayName: 'example_display_name', + } + + const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) + const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { + transaction: true, + }) + + expect(savedOrganization1).toBeDefined() + + const organization2: BasicOrganization = { + legalName, + displayName: 'example_display_name', + } + + const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) + await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.legalName' + ) + }) + + it('Should enforce unique display name when saving organization', async (): Promise => { + const displayName = 'non_unique_value' + const organization1: BasicOrganization = { + legalName: 'example_legal_name1', + displayName, + } + + const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) + const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { + transaction: true, + }) + + expect(savedOrganization1).toBeDefined() + + const organization2: BasicOrganization = { + legalName: 'example_legal_name2', + displayName, + } + + const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) + await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.displayName' + ) + }) + + it('Should enforce unique legal name when saving organization', async (): Promise => { + const legalName = 'example_legal_name' + const organization1: BasicOrganization = { + legalName, + displayName: 'example_display_name', + } + + const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) + const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { + transaction: true, + }) + + expect(savedOrganization1).toBeDefined() + + const organization2: BasicOrganization = { + legalName, + displayName: 'example_display_name', + } + + const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) + await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.legalName' + ) + }) + + it('Should enforce unique coc number when saving organization per tenant id', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.ORGANIZATION, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + legalName: 'example_legal_name', + displayName: 'example_display_name', + cocNumber: 'example_coc_number', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + await dbConnection.getRepository(ContactEntity).save(contactEntity, { + transaction: true, + }) + + const contact2: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name2', + }, + contactOwner: { + legalName: 'example_legal_name2', + displayName: 'example_display_name2', + cocNumber: 'example_coc_number', + }, + } + + const contactEntity2: ContactEntity = contactEntityFrom(contact2) + await expect(dbConnection.getRepository(ContactEntity).save(contactEntity2, { transaction: true })).rejects.toThrowError( + 'Coc number already in use' + ) + }) + + it('Should enforce unique display name when saving person', async (): Promise => { + const displayName = 'non_unique_value' + const person1: BasicPerson = { + firstName: 'example_first_name1', + lastName: 'lastName2', + displayName, + } + + const personEntity1: PersonEntity = personEntityFrom(person1) + const savedPerson1: PersonEntity | null = await dbConnection.getRepository(PersonEntity).save(personEntity1, { + transaction: true, + }) + + expect(savedPerson1).toBeDefined() + + const person2: BasicPerson = { + firstName: 'example_first_name2', + lastName: 'lastName2', + displayName, + } + + const personEntity2: PersonEntity = personEntityFrom(person2) + await expect(dbConnection.getRepository(PersonEntity).save(personEntity2)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.displayName' + ) + }) + + it('Should save contact relationship to database', async (): Promise => { + const contact1: IBasicContact = { + uri: 'example1.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const contactEntity1: ContactEntity = contactEntityFrom(contact1) + const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + transaction: true, + }) + + expect(savedContact1).toBeDefined() + + const contact2: IBasicContact = { + uri: 'example2.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + + const contactEntity2: ContactEntity = contactEntityFrom(contact2) + const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + transaction: true, + }) + + expect(savedContact2).toBeDefined() + + const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ + leftId: savedContact1.id, + rightId: savedContact2.id, + }) + + await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { + transaction: true, + }) + + // TODO check the relation field + const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: contactEntity1.id }, + }) + + expect(fromDb).toBeDefined() + }) + + it('Should set last updated date when saving contact relationship', async (): Promise => { + const contact1: IBasicContact = { + uri: 'example1.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const contactEntity1: ContactEntity = contactEntityFrom(contact1) + const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + transaction: true, + }) + + const contact2: IBasicContact = { + uri: 'example2.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + + const contactEntity2: ContactEntity = contactEntityFrom(contact2) + const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + transaction: true, + }) + + const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ + leftId: savedContact1.id, + rightId: savedContact2.id, + }) + + await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { + transaction: true, + }) + + const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: contactEntity1.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.lastUpdatedAt).toBeDefined() + }) + + it('Should set creation date when saving contact relationship', async (): Promise => { + const contact1: IBasicContact = { + uri: 'example1.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const contactEntity1: ContactEntity = contactEntityFrom(contact1) + const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + transaction: true, + }) + + const contact2: IBasicContact = { + uri: 'example2.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + + const contactEntity2: ContactEntity = contactEntityFrom(contact2) + const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + transaction: true, + }) + + const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ + leftId: savedContact1.id, + rightId: savedContact2.id, + }) + + await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { + transaction: true, + }) + + const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: contactEntity1.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.createdAt).toBeDefined() + }) + + it('Should save bidirectional contact relationships to database', async (): Promise => { + const contact1: IBasicContact = { + uri: 'example1.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const contactEntity1: ContactEntity = contactEntityFrom(contact1) + const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + transaction: true, + }) + + expect(savedContact1).toBeDefined() + + const contact2: IBasicContact = { + uri: 'example2.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + + const contactEntity2: ContactEntity = contactEntityFrom(contact2) + const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + transaction: true, + }) + + expect(savedContact2).toBeDefined() + + const relationship1: ContactRelationshipEntity = contactRelationshipEntityFrom({ + leftId: savedContact1.id, + rightId: savedContact2.id, + }) + + const savedRelationship1: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship1, { + transaction: true, + }) + + expect(savedRelationship1).toBeDefined() + + const relationship2: ContactRelationshipEntity = contactRelationshipEntityFrom({ + leftId: savedContact2.id, + rightId: savedContact1.id, + }) + + const savedRelationship2: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship2, { + transaction: true, + }) + + expect(savedRelationship2).toBeDefined() + + const fromDb: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).findOne({ + where: { id: savedRelationship2.id }, + }) + + expect(fromDb).toBeDefined() + }) + + it('Should enforce unique owner combination for contact relationship', async (): Promise => { + const contact1: IBasicContact = { + uri: 'example1.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const contactEntity1: ContactEntity = contactEntityFrom(contact1) + const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + transaction: true, + }) + + expect(savedContact1).toBeDefined() + + const contact2: IBasicContact = { + uri: 'example2.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + + const contactEntity2: ContactEntity = contactEntityFrom(contact2) + const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + transaction: true, + }) + + expect(savedContact2).toBeDefined() + + const relationship1: ContactRelationshipEntity = contactRelationshipEntityFrom({ + leftId: savedContact1.id, + rightId: savedContact2.id, + }) + + const savedRelationship1: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship1, { + transaction: true, + }) + + expect(savedRelationship1).toBeDefined() + + const relationship2: ContactRelationshipEntity = contactRelationshipEntityFrom({ + leftId: savedContact1.id, + rightId: savedContact2.id, + }) + + await expect(dbConnection.getRepository(ContactRelationshipEntity).save(relationship2)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactRelationship.leftId, ContactRelationship.rightId' + ) + }) + + it('Should save contact type to database', async (): Promise => { + const contactType: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + } + + const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) + const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) + + const fromDb: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).findOne({ + where: { id: savedContactType.id }, + }) + + expect(fromDb).toBeDefined() + }) + + it('Should save person to database', async (): Promise => { + const person: BasicPerson = { + firstName: 'example_first_name', + lastName: 'lastName2', + displayName: 'displayName', + } + + const personEntity: PersonEntity = personEntityFrom(person) + const savedPerson: PersonEntity | null = await dbConnection.getRepository(PersonEntity).save(personEntity, { + transaction: true, + }) + + const fromDb: PersonEntity | null = await dbConnection.getRepository(PersonEntity).findOne({ + where: { id: savedPerson.id }, + }) + + expect(fromDb).toBeDefined() + }) + + it('Should set last updated date when saving person', async (): Promise => { + const person: BasicPerson = { + firstName: 'example_first_name', + lastName: 'lastName2', + displayName: 'displayName', + } + + const personEntity: PersonEntity = personEntityFrom(person) + const savedPerson: PersonEntity | null = await dbConnection.getRepository(PersonEntity).save(personEntity, { + transaction: true, + }) + + const fromDb: PersonEntity | null = await dbConnection.getRepository(PersonEntity).findOne({ + where: { id: savedPerson.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.lastUpdatedAt).toBeDefined() + }) + + it('Should set creation date when saving person', async (): Promise => { + const person: BasicPerson = { + firstName: 'example_first_name', + lastName: 'lastName2', + displayName: 'displayName', + } + + const personEntity: PersonEntity = personEntityFrom(person) + const savedPerson: PersonEntity | null = await dbConnection.getRepository(PersonEntity).save(personEntity, { + transaction: true, + }) + + const fromDb: PersonEntity | null = await dbConnection.getRepository(PersonEntity).findOne({ + where: { id: savedPerson.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.createdAt).toBeDefined() + }) + + it('Should save organization to database', async (): Promise => { + const organization: BasicOrganization = { + legalName: 'example_legal_name', + displayName: 'example_display_name', + } + + const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) + const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { + transaction: true, + }) + + const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ + where: { id: savedOrganization.id }, + }) + + expect(fromDb).toBeDefined() + }) + + it('Should set last updated date when saving organization', async (): Promise => { + const organization: BasicOrganization = { + legalName: 'example_legal_name', + displayName: 'example_display_name', + } + + const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) + const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { + transaction: true, + }) + + const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ + where: { id: savedOrganization.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.lastUpdatedAt).toBeDefined() + }) + + it('Should set creation date when saving organization', async (): Promise => { + const organization: BasicOrganization = { + legalName: 'example_legal_name', + displayName: 'example_display_name', + } + + const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) + const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { + transaction: true, + }) + + const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ + where: { id: savedOrganization.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.createdAt).toBeDefined() + }) + + it('Should get contact based on person information', async (): Promise => { + const firstName = 'example_first_name' + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName, + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + await dbConnection.getRepository(ContactEntity).save(contactEntity, { + transaction: true, + }) + + const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { + contactOwner: { + firstName, + } as FindOptionsWhere, + }, + }) + + expect(fromDb).toBeDefined() + }) + + it('Should get contact based on organization information', async (): Promise => { + const legalName = 'example_legal_name' + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.ORGANIZATION, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + legalName, + displayName: 'example_display_name', + cocNumber: 'example_coc_number', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + await dbConnection.getRepository(ContactEntity).save(contactEntity, { + transaction: true, + }) + + const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { + contactOwner: { + legalName, + } as FindOptionsWhere, + }, + }) + + expect(fromDb).toBeDefined() + }) + + it("Should enforce unique contact id's for relationship sides", async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + const savedContact: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity, { + transaction: true, + }) + + expect(savedContact).toBeDefined() + + const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ + leftId: savedContact.id, + rightId: savedContact.id, + }) + + await expect(dbConnection.getRepository(ContactRelationshipEntity).save(relationship)).rejects.toThrowError( + 'Cannot use the same id for both sides of the relationship' + ) + }) + + it('Should delete contact relationship', async (): Promise => { + const contact1: IBasicContact = { + uri: 'example1.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const contactEntity1: ContactEntity = contactEntityFrom(contact1) + const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + transaction: true, + }) + + expect(savedContact1).toBeDefined() + + const contact2: IBasicContact = { + uri: 'example2.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + + const contactEntity2: ContactEntity = contactEntityFrom(contact2) + const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + transaction: true, + }) + + expect(savedContact2).toBeDefined() + + const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ + leftId: savedContact1.id, + rightId: savedContact2.id, + }) + + const savedRelationship: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { + transaction: true, + }) + + expect(savedRelationship).toBeDefined() + + await dbConnection.getRepository(ContactRelationshipEntity).delete({ id: savedRelationship.id }) + + await expect( + await dbConnection.getRepository(ContactRelationshipEntity).findOne({ + where: { id: savedRelationship.id }, + }) + ).toBeNull() + }) + + it('Should delete contact type', async (): Promise => { + const contactType: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + } + + const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) + const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) + + expect(savedContactType).toBeDefined() + + await dbConnection.getRepository(ContactTypeEntity).delete({ id: savedContactType.id }) + + await expect( + await dbConnection.getRepository(ContactTypeEntity).findOne({ + where: { id: savedContactType.id }, + }) + ).toBeNull() + }) + + it('Should not be able to remove contact type when used by contacts', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity, { + transaction: true, + }) + + expect(savedContact).toBeDefined() + + await expect(dbConnection.getRepository(ContactTypeEntity).delete({ id: savedContact.contactType.id })).rejects.toThrowError( + 'FOREIGN KEY constraint failed' + ) + }) + + it('Should save contact with existing contact type', async (): Promise => { + const contactType: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + } + + const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) + const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) + + const contact: IBasicContact = { + uri: 'example.com', + contactType: savedContactType, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const contactEntity: ContactEntity = contactEntityFrom(contact) + contactEntity.contactType = savedContactType + await dbConnection.getRepository(ContactEntity).save(contactEntity, { + transaction: true, + }) + + const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + where: { id: contactEntity.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.contactType).toBeDefined() + expect(fromDb?.contactType.id).toEqual(savedContactType.id) + expect(fromDb?.contactType.type).toEqual(savedContactType.type) + expect(fromDb?.contactType.tenantId).toEqual(savedContactType.tenantId) + expect(fromDb?.contactType.name).toEqual(savedContactType.name) + }) + + it('Should not update creation date when saving contact type', async (): Promise => { + const contactType: BasicContactType = { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + } + + const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) + const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) + await dbConnection + .getRepository(ContactTypeEntity) + .save({ ...savedContactType, type: ContactTypeEnum.ORGANIZATION }) + + const fromDb: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).findOne({ + where: { + type: ContactTypeEnum.ORGANIZATION, + }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.createdAt).toEqual(savedContactType?.createdAt) + }) + }) diff --git a/packages/data-store/src/__tests__/contact.store.test.ts b/packages/data-store/src/__tests__/contact.store.test.ts index caa92bd62..950a38785 100644 --- a/packages/data-store/src/__tests__/contact.store.test.ts +++ b/packages/data-store/src/__tests__/contact.store.test.ts @@ -432,51 +432,44 @@ describe('Contact store tests', (): void => { expect(result.identities.length).toEqual(2) }) - // TODO fix test, its not throwing an error - // it('should throw error when adding contact with invalid identity', async (): Promise => { - // const contact: IBasicContact = { - // uri: 'example.com', - // contactType: { - // type: ContactTypeEnum.PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'something', - // }, - // contactOwner: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // identities: [ - // { - // alias: 'test_alias1', - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId: 'example_did1', - // }, - // }, - // { - // alias: 'test_alias2', - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId: 'example_did2', - // }, - // }, - // ], - // } - // - // const result: IContact = await contactStore.addContact(contact) - // - // expect(result.name).toEqual(contact.name) - // expect(result.alias).toEqual(contact.alias) - // expect(result.uri).toEqual(contact.uri) - // expect(result.identities.length).toEqual(2) - // }) + it('should throw error when adding contact with invalid identity', async (): Promise => { + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'something', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + identities: [ + { + alias: 'test_alias1', + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.URL, + correlationId: 'example_did1', + }, + }, + { + alias: 'test_alias2', + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId: 'example_did2', + }, + }, + ], + } + + await expect(contactStore.addContact(contact)).rejects.toThrow(`Identity with correlation type url should contain a connection`) + }) - // TODO test org and person - it('should throw error when adding contact with duplicate display name', async (): Promise => { + it('should throw error when adding person contact with duplicate display name', async (): Promise => { const displayName = 'non_unique_value' const contact1: IBasicContact = { uri: 'example.com', @@ -510,29 +503,41 @@ describe('Contact store tests', (): void => { }, } - await expect(contactStore.addContact(contact2)).rejects.toThrow(`Duplicate names or display are not allowed. Display name: ${displayName}`) + await expect(contactStore.addContact(contact2)).rejects.toThrow(`Duplicate display names are not allowed. Display name: ${displayName}`) }) - // TODO // TODO test name - // it('should throw error when adding contact with duplicate name', async (): Promise => { - // const alias = 'test_alias' - // const contact1: IBasicContact = { - // name: 'test_name', - // alias, - // uri: 'example.com', - // } - // const savedContact1: IContact = await contactStore.addContact(contact1) - // expect(savedContact1).toBeDefined() - // - // const name = 'test_name2' - // const contact2: IBasicContact = { - // name, - // alias, - // uri: 'example.com', - // } - // - // await expect(contactStore.addContact(contact2)).rejects.toThrow(`Duplicate names or aliases are not allowed. Name: ${name}, Alias: ${alias}`) - // }) + it('should throw error when adding organization contact with duplicate display name', async (): Promise => { + const displayName = 'non_unique_value' + const contact1: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.ORGANIZATION, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contactOwner: { + legalName: 'example_legal_name1', + displayName, + }, + } + const savedContact1: IContact = await contactStore.addContact(contact1) + expect(savedContact1).toBeDefined() + + const contact2: IBasicContact = { + uri: 'example.com', + contactType: { + type: ContactTypeEnum.ORGANIZATION, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contactOwner: { + legalName: 'example_legal_name2', + displayName, + }, + } + + await expect(contactStore.addContact(contact2)).rejects.toThrow(`Duplicate display names are not allowed. Display name: ${displayName}`) + }) it('should update contact by id', async (): Promise => { const contact: IBasicContact = { @@ -623,8 +628,6 @@ describe('Contact store tests', (): void => { await expect(contactStore.updateContact({ contact: updatedContact })).rejects.toThrow(`No contact found for id: ${contactId}`) }) - // TODO test to update wrong contact type person to org - it('should get identity by id', async (): Promise => { const contact: IBasicContact = { uri: 'example.com', @@ -1813,6 +1816,43 @@ describe('Contact store tests', (): void => { expect(result?.contactType.tenantId).toEqual(savedContactType.tenantId) expect(result?.contactType.name).toEqual(savedContactType.name) }) -}) -// maybe add some categories for the tests to find them + it('should throw error when adding person contact with wrong contact type', async (): Promise => { + const contactType = ContactTypeEnum.ORGANIZATION + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: contactType, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + await expect(contactStore.addContact(contact)).rejects.toThrow(`Contact type ${contactType}, does not match for provided contact owner`) + }) + + it('should throw error when adding organization contact with wrong contact type', async (): Promise => { + const contactType = ContactTypeEnum.PERSON + const contact: IBasicContact = { + uri: 'example.com', + contactType: { + type: contactType, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contactOwner: { + legalName: 'example_legal_name', + displayName: 'example_display_name', + }, + } + + await expect(contactStore.addContact(contact)).rejects.toThrow(`Contact type ${contactType}, does not match for provided contact owner`) + }) + +}) diff --git a/packages/data-store/src/contact/ContactStore.ts b/packages/data-store/src/contact/ContactStore.ts index 4b59f785e..edfc39014 100644 --- a/packages/data-store/src/contact/ContactStore.ts +++ b/packages/data-store/src/contact/ContactStore.ts @@ -29,6 +29,8 @@ import { IRemoveContactTypeArgs, IGetRelationshipsArgs, IUpdateRelationshipArgs, + ContactTypeEnum, + BasicContactOwner } from '../types' import { ContactEntity, contactEntityFrom, contactFrom } from '../entities/contact/ContactEntity' import { IdentityEntity, identityEntityFrom, identityFrom } from '../entities/contact/IdentityEntity' @@ -41,6 +43,7 @@ import { PersonEntity } from '../entities/contact/PersonEntity' import { OrganizationEntity } from '../entities/contact/OrganizationEntity' import { ContactRelationshipEntity, contactRelationshipEntityFrom, contactRelationshipFrom } from '../entities/contact/ContactRelationshipEntity' import { ContactTypeEntity, contactTypeEntityFrom, contactTypeFrom } from '../entities/contact/ContactTypeEntity' +import { isOrganization, isPerson } from '../entities/contact/ContactOwnerEntity' const debug: Debug.Debugger = Debug('sphereon:ssi-sdk:contact-store') @@ -80,10 +83,14 @@ export class ContactStore extends AbstractContactStore { } addContact = async (args: IAddContactArgs): Promise => { - const { identities, contactOwner } = args + const { identities, contactOwner, contactType } = args const contactRepository: Repository = (await this.dbConnection).getRepository(ContactEntity) + if (!this.hasCorrectContactType(contactType.type, contactOwner)) { + return Promise.reject(Error(`Contact type ${contactType.type}, does not match for provided contact owner`)) + } + const result: ContactEntity | null = await contactRepository.findOne({ where: [ { @@ -95,8 +102,7 @@ export class ContactStore extends AbstractContactStore { }) if (result) { - // TODO correct msg? - return Promise.reject(Error(`Duplicate names or display are not allowed. Display name: ${contactOwner.displayName}`)) + return Promise.reject(Error(`Duplicate display names are not allowed. Display name: ${contactOwner.displayName}`)) } for (const identity of identities ?? []) { @@ -105,7 +111,7 @@ export class ContactStore extends AbstractContactStore { return Promise.reject(Error(`Identity with correlation type ${CorrelationIdentifierEnum.URL} should contain a connection`)) } - if (!this.hasCorrectConfig(identity.connection.type, identity.connection.config)) { + if (!this.hasCorrectConnectionConfig(identity.connection.type, identity.connection.config)) { return Promise.reject(Error(`Connection type ${identity.connection.type}, does not match for provided config`)) } } @@ -129,9 +135,9 @@ export class ContactStore extends AbstractContactStore { } const updatedContact = { - // TODO fix type ...contact, identities: result.identities, + contactType: result.contactType, relationships: result.relationships, } @@ -201,7 +207,7 @@ export class ContactStore extends AbstractContactStore { return Promise.reject(Error(`Identity with correlation type ${CorrelationIdentifierEnum.URL} should contain a connection`)) } - if (!this.hasCorrectConfig(identity.connection.type, identity.connection.config)) { + if (!this.hasCorrectConnectionConfig(identity.connection.type, identity.connection.config)) { return Promise.reject(Error(`Connection type ${identity.connection.type}, does not match for provided config`)) } } @@ -231,7 +237,7 @@ export class ContactStore extends AbstractContactStore { return Promise.reject(Error(`Identity with correlation type ${CorrelationIdentifierEnum.URL} should contain a connection`)) } - if (!this.hasCorrectConfig(identity.connection.type, identity.connection.config)) { + if (!this.hasCorrectConnectionConfig(identity.connection.type, identity.connection.config)) { return Promise.reject(Error(`Connection type ${identity.connection.type}, does not match for provided config`)) } } @@ -275,8 +281,8 @@ export class ContactStore extends AbstractContactStore { } const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ - left: leftContact, - right: rightContact, + leftId: leftContact.id, + rightId: rightContact.id, }) const createdResult: ContactRelationshipEntity = await (await this.dbConnection).getRepository(ContactRelationshipEntity).save(relationship) @@ -360,8 +366,6 @@ export class ContactStore extends AbstractContactStore { } addContactType = async (args: IAddContactTypeArgs): Promise => { - // TODO do we need checks? - const contactEntity: ContactTypeEntity = contactTypeEntityFrom(args) debug('Adding contact type', args) const createdResult: ContactTypeEntity = await (await this.dbConnection).getRepository(ContactTypeEntity).save(contactEntity) @@ -439,7 +443,7 @@ export class ContactStore extends AbstractContactStore { await contactTypeRepository.delete(contactTypeId) } - private hasCorrectConfig(type: ConnectionTypeEnum, config: BasicConnectionConfig): boolean { + private hasCorrectConnectionConfig(type: ConnectionTypeEnum, config: BasicConnectionConfig): boolean { switch (type) { case ConnectionTypeEnum.OPENID_CONNECT: return isOpenIdConfig(config) @@ -450,6 +454,17 @@ export class ContactStore extends AbstractContactStore { } } + private hasCorrectContactType(type: ContactTypeEnum, owner: BasicContactOwner): boolean { + switch (type) { + case ContactTypeEnum.PERSON: + return isPerson(owner) + case ContactTypeEnum.ORGANIZATION: + return isOrganization(owner) + default: + throw new Error('Contact type not supported') + } + } + private async deleteIdentities(identities: Array): Promise { debug('Removing identities', identities) @@ -489,4 +504,5 @@ export class ContactStore extends AbstractContactStore { .catch((error) => Promise.reject(Error(`Unable to remove metadataItem.id with id ${identity.id}. ${error}`))) }) } + } diff --git a/packages/data-store/src/entities/contact/BaseConfigEntity.ts b/packages/data-store/src/entities/contact/BaseConfigEntity.ts index b3d7ffd10..0999eebe9 100644 --- a/packages/data-store/src/entities/contact/BaseConfigEntity.ts +++ b/packages/data-store/src/entities/contact/BaseConfigEntity.ts @@ -1,5 +1,10 @@ import { BaseEntity, Entity, PrimaryGeneratedColumn, TableInheritance } from 'typeorm' -import { BasicConnectionConfig, ConnectionConfig, IDidAuthConfig, IOpenIdConfig } from '../../types' +import { + BasicConnectionConfig, + ConnectionConfig, + IDidAuthConfig, + IOpenIdConfig +} from '../../types' import { OpenIdConfigEntity } from './OpenIdConfigEntity' import { DidAuthConfigEntity } from './DidAuthConfigEntity' @@ -11,12 +16,9 @@ export abstract class BaseConfigEntity extends BaseEntity { } export const configFrom = (config: BaseConfigEntity): ConnectionConfig => { - // @ts-ignore if (isOpenIdConfig(config)) { return openIdConfigFrom(config) - // @ts-ignore } else if (isDidAuthConfig(config)) { - // @ts-ignore return didAuthConfigFrom(config) } @@ -29,7 +31,7 @@ export const openIdConfigFrom = (config: OpenIdConfigEntity): IOpenIdConfig => { clientId: config.clientId, clientSecret: config.clientSecret, scopes: config.scopes, - issuer: config.issuer!, // FIXME + issuer: config.issuer, redirectUrl: config.redirectUrl, dangerouslyAllowInsecureHttpRequests: config.dangerouslyAllowInsecureHttpRequests, clientAuthMethod: config.clientAuthMethod, @@ -46,8 +48,8 @@ export const didAuthConfigFrom = (config: DidAuthConfigEntity): IDidAuthConfig = } } -export const isOpenIdConfig = (config: BasicConnectionConfig): config is IOpenIdConfig => +export const isOpenIdConfig = (config: BasicConnectionConfig | BaseConfigEntity): config is IOpenIdConfig | OpenIdConfigEntity => 'clientSecret' in config && 'issuer' in config && 'redirectUrl' in config -export const isDidAuthConfig = (config: BasicConnectionConfig): config is IDidAuthConfig => +export const isDidAuthConfig = (config: BasicConnectionConfig | BaseConfigEntity): config is IDidAuthConfig | DidAuthConfigEntity => 'identifier' in config && 'redirectUrl' in config && 'sessionId' in config diff --git a/packages/data-store/src/entities/contact/ConnectionEntity.ts b/packages/data-store/src/entities/contact/ConnectionEntity.ts index 33dc5644b..ef568e5a8 100644 --- a/packages/data-store/src/entities/contact/ConnectionEntity.ts +++ b/packages/data-store/src/entities/contact/ConnectionEntity.ts @@ -1,9 +1,20 @@ import { Entity, Column, PrimaryGeneratedColumn, OneToOne, JoinColumn, BaseEntity } from 'typeorm' -import { BaseConfigEntity, configFrom, isDidAuthConfig, isOpenIdConfig } from './BaseConfigEntity' -import { BasicConnectionConfig, BasicDidAuthConfig, BasicOpenIdConfig, ConnectionTypeEnum, IBasicConnection, IConnection } from '../../types' +import { + BaseConfigEntity, + configFrom, isDidAuthConfig, isOpenIdConfig +} from './BaseConfigEntity' +import { + BasicConnectionConfig, + BasicDidAuthConfig, BasicOpenIdConfig, + ConnectionTypeEnum, IBasicConnection, IConnection +} from '../../types' import { IdentityEntity } from './IdentityEntity' -import { OpenIdConfigEntity, openIdConfigEntityFrom } from './OpenIdConfigEntity' -import { DidAuthConfigEntity, didAuthConfigEntityFrom } from './DidAuthConfigEntity' +import { + OpenIdConfigEntity, openIdConfigEntityFrom +} from './OpenIdConfigEntity' +import { + DidAuthConfigEntity, didAuthConfigEntityFrom +} from './DidAuthConfigEntity' @Entity('Connection') export class ConnectionEntity extends BaseEntity { @@ -44,7 +55,6 @@ export const connectionFrom = (connection: ConnectionEntity): IConnection => { } } -// TODO move to base config? const configEntityFrom = (config: BasicConnectionConfig): BaseConfigEntity => { if (isOpenIdConfig(config)) { return openIdConfigEntityFrom(config) diff --git a/packages/data-store/src/entities/contact/ContactEntity.ts b/packages/data-store/src/entities/contact/ContactEntity.ts index 7b005775f..9d55fe8fb 100644 --- a/packages/data-store/src/entities/contact/ContactEntity.ts +++ b/packages/data-store/src/entities/contact/ContactEntity.ts @@ -21,12 +21,16 @@ import { IBasicContact, IBasicIdentity, IContact, - ValidationConstraint, + ValidationConstraint } from '../../types' import { IdentityEntity, identityEntityFrom, identityFrom } from './IdentityEntity' import { validate, ValidationError } from 'class-validator' import { ContactTypeEntity, contactTypeEntityFrom, contactTypeFrom } from './ContactTypeEntity' -import { ContactOwnerEntity } from './ContactOwnerEntity' +import { + ContactOwnerEntity, + isOrganization, + isPerson +} from './ContactOwnerEntity' import { PersonEntity, personEntityFrom, personFrom } from './PersonEntity' import { OrganizationEntity, organizationEntityFrom, organizationFrom } from './OrganizationEntity' import { ContactRelationshipEntity, contactRelationshipFrom } from './ContactRelationshipEntity' @@ -50,12 +54,10 @@ export class ContactEntity extends BaseEntity { identities!: Array @ManyToOne(() => ContactTypeEntity, (contactType: ContactTypeEntity) => contactType.contacts, { - // cascade: ['insert', 'update'], cascade: true, - // onDelete: 'CASCADE', nullable: false, eager: true, - }) // TODO check these options + }) @JoinColumn({ name: 'contactTypeId' }) contactType!: ContactTypeEntity @@ -82,13 +84,6 @@ export class ContactEntity extends BaseEntity { @UpdateDateColumn({ name: 'last_updated_at', nullable: false }) lastUpdatedAt!: Date - // By default, @UpdateDateColumn in TypeORM updates the timestamp only when the entity's top-level properties change. - @BeforeInsert() - @BeforeUpdate() - updateLastUpdatedDate(): void { - this.lastUpdatedAt = new Date() - } - @BeforeInsert() @BeforeUpdate() async checkUniqueCocNumberAndTenantId(): Promise { @@ -150,7 +145,6 @@ export const contactFrom = (contact: ContactEntity): IContact => { } } -// TODO move export const contactOwnerEntityFrom = (owner: BasicContactOwner): ContactOwnerEntity => { if (isPerson(owner)) { return personEntityFrom(owner) @@ -163,18 +157,10 @@ export const contactOwnerEntityFrom = (owner: BasicContactOwner): ContactOwnerEn export const contactOwnerFrom = (owner: ContactOwnerEntity): ContactOwner => { if (isPerson(owner)) { - // @ts-ignore return personFrom(owner) } else if (isOrganization(owner)) { - // @ts-ignore return organizationFrom(owner) } throw new Error('Owner type not supported') } - -// TODO move? -const isPerson = (owner: BasicContactOwner | ContactOwnerEntity): owner is BasicPerson => - 'firstName' in owner && 'middleName' in owner && 'lastName' in owner - -const isOrganization = (owner: BasicContactOwner | ContactOwnerEntity): owner is BasicOrganization => 'legalName' in owner && 'cocNumber' in owner diff --git a/packages/data-store/src/entities/contact/ContactOwnerEntity.ts b/packages/data-store/src/entities/contact/ContactOwnerEntity.ts index 00a4bc476..18bb16a74 100644 --- a/packages/data-store/src/entities/contact/ContactOwnerEntity.ts +++ b/packages/data-store/src/entities/contact/ContactOwnerEntity.ts @@ -1,5 +1,8 @@ import { BaseEntity, CreateDateColumn, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn, TableInheritance, UpdateDateColumn } from 'typeorm' import { ContactEntity } from './ContactEntity' +import { BasicContactOwner, BasicOrganization, BasicPerson } from '../../types' +import { PersonEntity } from './PersonEntity' +import { OrganizationEntity } from './OrganizationEntity' @Entity('ContactOwner') @TableInheritance({ column: { type: 'varchar', name: 'type' } }) @@ -19,3 +22,8 @@ export abstract class ContactOwnerEntity extends BaseEntity { @JoinColumn({ name: 'contactId' }) contact!: ContactEntity } + +export const isPerson = (owner: BasicContactOwner | ContactOwnerEntity): owner is BasicPerson | PersonEntity => + 'firstName' in owner && 'middleName' in owner && 'lastName' in owner + +export const isOrganization = (owner: BasicContactOwner | ContactOwnerEntity): owner is BasicOrganization | OrganizationEntity => 'legalName' in owner diff --git a/packages/data-store/src/entities/contact/ContactRelationshipEntity.ts b/packages/data-store/src/entities/contact/ContactRelationshipEntity.ts index 8dc8d65b5..2177dccdd 100644 --- a/packages/data-store/src/entities/contact/ContactRelationshipEntity.ts +++ b/packages/data-store/src/entities/contact/ContactRelationshipEntity.ts @@ -1,6 +1,5 @@ import { Entity, - // JoinColumn, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn, @@ -11,11 +10,10 @@ import { BeforeUpdate, } from 'typeorm' import { ContactEntity } from './ContactEntity' -import { IContactRelationship } from '../../types' +import { BasicContactRelationship, IContactRelationship } from '../../types' -@Entity() -// @Index(['leftContactId', 'rightContactId'], { unique: true }) // TODO name\ -@Index(['left', 'right'], { unique: true }) // TODO name +@Entity('ContactRelationship') +@Index('IDX_ContactRelationshipEntity_left_right', ['left', 'right'], { unique: true }) export class ContactRelationshipEntity { @PrimaryGeneratedColumn('uuid') id!: string @@ -24,7 +22,6 @@ export class ContactRelationshipEntity { nullable: false, onDelete: 'CASCADE', }) - // @JoinColumn({ name: 'left_contact_id' }) left!: ContactEntity @Column({ name: 'leftId', nullable: false }) @@ -34,7 +31,6 @@ export class ContactRelationshipEntity { nullable: false, onDelete: 'CASCADE', }) - // @JoinColumn({ name: 'right_contact_id' }) right!: ContactEntity @Column({ name: 'rightId', nullable: false }) @@ -49,29 +45,26 @@ export class ContactRelationshipEntity { @BeforeInsert() @BeforeUpdate() async checkRelationshipSides(): Promise { - if (this.left.id === this.right.id) { + if ((this.left?.id ?? this.leftId) === (this.right?.id ?? this.rightId)) { return Promise.reject(Error('Cannot use the same id for both sides of the relationship')) } } } -// TODO interface -export const contactRelationshipEntityFrom = (relationship: { left: ContactEntity; right: ContactEntity }): ContactRelationshipEntity => { - // TODO convert IContact to ContactEntity here - +export const contactRelationshipEntityFrom = (relationship: BasicContactRelationship): ContactRelationshipEntity => { const contactRelationshipEntity: ContactRelationshipEntity = new ContactRelationshipEntity() - contactRelationshipEntity.left = relationship.left - contactRelationshipEntity.right = relationship.right + contactRelationshipEntity.leftId = relationship.leftId + contactRelationshipEntity.rightId = relationship.rightId + return contactRelationshipEntity } export const contactRelationshipFrom = (relationship: ContactRelationshipEntity): IContactRelationship => { return { id: relationship.id, - leftId: relationship.leftId, //relationship.left.id, - rightId: relationship.rightId, //relationship.right.id, + leftId: relationship.leftId, + rightId: relationship.rightId, createdAt: relationship.createdAt, lastUpdatedAt: relationship.lastUpdatedAt, } - // TODO convert IContact to ContactEntity here } diff --git a/packages/data-store/src/entities/contact/ContactTypeEntity.ts b/packages/data-store/src/entities/contact/ContactTypeEntity.ts index 13ca80956..70f241725 100644 --- a/packages/data-store/src/entities/contact/ContactTypeEntity.ts +++ b/packages/data-store/src/entities/contact/ContactTypeEntity.ts @@ -5,7 +5,7 @@ import { IsNotEmpty, Validate, validate, ValidationError } from 'class-validator import { IsNonEmptyStringConstraint } from '../validators' import { getConstraint } from '../../utils/ValidatorUtils' -@Entity() +@Entity('ContactType') @Index(['type', 'tenantId'], { unique: true }) // TODO name example: 'IDX_CredentialLocaleBrandingEntity_credentialBranding_locale', export class ContactTypeEntity { @PrimaryGeneratedColumn('uuid') diff --git a/packages/data-store/src/entities/contact/IdentityEntity.ts b/packages/data-store/src/entities/contact/IdentityEntity.ts index 57ffef968..43765906f 100644 --- a/packages/data-store/src/entities/contact/IdentityEntity.ts +++ b/packages/data-store/src/entities/contact/IdentityEntity.ts @@ -75,13 +75,6 @@ export class IdentityEntity extends BaseEntity { @Column({ name: 'contactId', nullable: true }) contactId!: string - // By default, @UpdateDateColumn in TypeORM updates the timestamp only when the entity's top-level properties change. - @BeforeInsert() - @BeforeUpdate() - updateLastUpdatedDate(): void { - this.lastUpdatedAt = new Date() - } - @BeforeInsert() @BeforeUpdate() async validate(): Promise { diff --git a/packages/data-store/src/entities/contact/OrganizationEntity.ts b/packages/data-store/src/entities/contact/OrganizationEntity.ts index aabd5f03b..e0e856a0d 100644 --- a/packages/data-store/src/entities/contact/OrganizationEntity.ts +++ b/packages/data-store/src/entities/contact/OrganizationEntity.ts @@ -16,7 +16,6 @@ export class OrganizationEntity extends ContactOwnerEntity { @IsNotEmpty({ message: 'Blank display names are not allowed' }) displayName!: string - // TODO uniek per tenant @Column({ name: 'cocNumber', length: 255, nullable: true, unique: false }) @Validate(IsNonEmptyStringConstraint, { message: 'Blank coc numbers are not allowed' }) cocNumber?: string diff --git a/packages/data-store/src/entities/issuanceBranding/BaseLocaleBrandingEntity.ts b/packages/data-store/src/entities/issuanceBranding/BaseLocaleBrandingEntity.ts index 6435f9e83..f60a96101 100644 --- a/packages/data-store/src/entities/issuanceBranding/BaseLocaleBrandingEntity.ts +++ b/packages/data-store/src/entities/issuanceBranding/BaseLocaleBrandingEntity.ts @@ -67,13 +67,6 @@ export class BaseLocaleBrandingEntity extends BaseEntity { @UpdateDateColumn({ name: 'last_updated_at', nullable: false }) lastUpdatedAt!: Date - // By default, @UpdateDateColumn in TypeORM updates the timestamp only when the entity's top-level properties change. - @BeforeInsert() - @BeforeUpdate() - updateUpdatedDate(): void { - this.lastUpdatedAt = new Date() - } - @BeforeInsert() @BeforeUpdate() async validate(): Promise { diff --git a/packages/data-store/src/entities/issuanceBranding/CredentialBrandingEntity.ts b/packages/data-store/src/entities/issuanceBranding/CredentialBrandingEntity.ts index b1161044a..178d01521 100644 --- a/packages/data-store/src/entities/issuanceBranding/CredentialBrandingEntity.ts +++ b/packages/data-store/src/entities/issuanceBranding/CredentialBrandingEntity.ts @@ -48,13 +48,6 @@ export class CredentialBrandingEntity extends BaseEntity { @UpdateDateColumn({ name: 'last_updated_at', nullable: false }) lastUpdatedAt!: Date - // By default, @UpdateDateColumn in TypeORM updates the timestamp only when the entity's top-level properties change. - @BeforeInsert() - @BeforeUpdate() - updateUpdatedDate(): void { - this.lastUpdatedAt = new Date() - } - @BeforeInsert() @BeforeUpdate() async validate(): Promise { diff --git a/packages/data-store/src/entities/issuanceBranding/IssuerBrandingEntity.ts b/packages/data-store/src/entities/issuanceBranding/IssuerBrandingEntity.ts index 404e94d2d..e3e83ba44 100644 --- a/packages/data-store/src/entities/issuanceBranding/IssuerBrandingEntity.ts +++ b/packages/data-store/src/entities/issuanceBranding/IssuerBrandingEntity.ts @@ -43,13 +43,6 @@ export class IssuerBrandingEntity extends BaseEntity { @UpdateDateColumn({ name: 'last_updated_at', nullable: false }) lastUpdatedAt!: Date - // By default, @UpdateDateColumn in TypeORM updates the timestamp only when the entity's top-level properties change. - @BeforeInsert() - @BeforeUpdate() - updateUpdatedDate(): void { - this.lastUpdatedAt = new Date() - } - @BeforeInsert() @BeforeUpdate() async validate(): Promise { diff --git a/packages/data-store/src/migrations/generic/1-CreateContacts.ts b/packages/data-store/src/migrations/generic/1-CreateContacts.ts index a65e91148..0191e1808 100644 --- a/packages/data-store/src/migrations/generic/1-CreateContacts.ts +++ b/packages/data-store/src/migrations/generic/1-CreateContacts.ts @@ -1,25 +1,13 @@ import { DatabaseType, MigrationInterface, QueryRunner } from 'typeorm' import Debug from 'debug' import { CreateContacts1659463079428 } from '../postgres/1659463079428-CreateContacts' -// import { CreateContacts1690925872592 } from '../postgres/1690925872592-CreateContacts' import { CreateContacts1659463069549 } from '../sqlite/1659463069549-CreateContacts' -// import { CreateContacts1690925872693 } from '../sqlite/1690925872693-CreateContacts' const debug: Debug.Debugger = Debug('sphereon:ssi-sdk:migrations') export class CreateContacts1659463079429 implements MigrationInterface { name = 'CreateContacts1659463079429' - // private readonly sqliteMigrations: MigrationInterface[] = [ - // new CreateContacts1659463069549(), - // // new CreateContacts1690925872693(), - // ]; - // - // private readonly postgresMigrations: MigrationInterface[] = [ - // new CreateContacts1659463079428(), - // new CreateContacts1690925872592() - // ]; - public async up(queryRunner: QueryRunner): Promise { debug('migration: creating contacts tables') const dbType: DatabaseType = queryRunner.connection.driver.options.type @@ -28,28 +16,16 @@ export class CreateContacts1659463079429 implements MigrationInterface { case 'postgres': { debug('using postgres migration file') const mig: CreateContacts1659463079428 = new CreateContacts1659463079428() - // const up: void = await mig.up(queryRunner) await mig.up(queryRunner) - // for (const mig of this.postgresMigrations) { - // await mig.up(queryRunner); - // } debug('Migration statements executed') - // return up return } case 'sqlite': case 'react-native': { debug('using sqlite/react-native migration file') - // for (const mig of this.sqliteMigrations) { - // await mig.up(queryRunner); - // debug('Migration statements executed'); - // } const mig: CreateContacts1659463069549 = new CreateContacts1659463069549() await mig.up(queryRunner) - // const mig: CreateContacts1659463069549 = new CreateContacts1659463069549() - // const up: void = await mig.up(queryRunner) debug('Migration statements executed') - // return up return } default: @@ -66,29 +42,17 @@ export class CreateContacts1659463079429 implements MigrationInterface { switch (dbType) { case 'postgres': { debug('using postgres migration file') - // const mig: CreateContacts1659463079428 = new CreateContacts1659463079428() - // const down: void = await mig.down(queryRunner) const mig: CreateContacts1659463079428 = new CreateContacts1659463079428() await mig.down(queryRunner) - // for (const mig of this.postgresMigrations.reverse()) { - // await mig.down(queryRunner); - // } debug('Migration statements executed') - // return down return } case 'sqlite': case 'react-native': { debug('using sqlite/react-native migration file') - // for (const mig of this.sqliteMigrations.reverse()) { - // await mig.down(queryRunner); - // } - // const mig: CreateContacts1659463069549 = new CreateContacts1659463069549() - // const down: void = await mig.down(queryRunner) const mig: CreateContacts1659463069549 = new CreateContacts1659463069549() await mig.down(queryRunner) debug('Migration statements executed') - // return down return } default: @@ -96,23 +60,5 @@ export class CreateContacts1659463079429 implements MigrationInterface { "Migrations are currently only supported for sqlite, react-native and postgres. Please run your database without migrations and with 'migrationsRun: false' and 'synchronize: true' for now" ) } - - // if (dbType === 'postgres') { - // debug('using postgres migration file') - // const mig = new CreateContacts1659463079428() - // const down = await mig.down(queryRunner) - // debug('Migration statements executed') - // return down - // } else if (dbType === 'sqlite' || 'react-native') { - // debug('using sqlite/react-native migration file') - // const mig = new CreateContacts1659463069549() - // const down = await mig.down(queryRunner) - // debug('Migration statements executed') - // return down - // } else { - // return Promise.reject( - // "Migrations are currently only supported for sqlite, react-native and postgres. Please run your database without migrations and with 'migrationsRun: false' and 'synchronize: true' for now" - // ) - // } } } diff --git a/packages/data-store/src/migrations/generic/index.ts b/packages/data-store/src/migrations/generic/index.ts index 9bada1dfe..36fbd54f8 100644 --- a/packages/data-store/src/migrations/generic/index.ts +++ b/packages/data-store/src/migrations/generic/index.ts @@ -1,8 +1,7 @@ import { CreateContacts1659463079429 } from './1-CreateContacts' -// import { CreateContacts1690925872318 } from './2-CreateContacts' +import { CreateContacts1690925872318 } from './2-CreateContacts' import { CreateIssuanceBranding1659463079429 } from './1-CreateIssuanceBranding' - /** * The migrations array that SHOULD be used when initializing a TypeORM database connection. * @@ -12,6 +11,6 @@ import { CreateIssuanceBranding1659463079429 } from './1-CreateIssuanceBranding' */ export const DataStoreMigrations = [ CreateContacts1659463079429, - // CreateContacts1690925872318, + CreateContacts1690925872318, CreateIssuanceBranding1659463079429 ] diff --git a/packages/data-store/src/migrations/internal-migrations-ormconfig.ts b/packages/data-store/src/migrations/internal-migrations-ormconfig.ts index 69f15b773..27de527de 100644 --- a/packages/data-store/src/migrations/internal-migrations-ormconfig.ts +++ b/packages/data-store/src/migrations/internal-migrations-ormconfig.ts @@ -1,4 +1,4 @@ -import { ConnectionOptions } from 'typeorm' +import { DataSourceOptions } from 'typeorm' import { DataStoreContactEntities, DataStoreMigrations } from '../index' /** @@ -7,7 +7,6 @@ import { DataStoreContactEntities, DataStoreMigrations } from '../index' export default [ { type: 'sqlite', - name: 'migration-sqlite', database: 'migration.sqlite', migrationsRun: false, synchronize: false, @@ -17,7 +16,6 @@ export default [ }, { type: 'postgres', - name: 'migration-postgres', database: 'migration-postgres', migrationsRun: false, synchronize: false, @@ -25,4 +23,4 @@ export default [ entities: [...DataStoreContactEntities], migrations: [...DataStoreMigrations], }, -] as ConnectionOptions[] +] as DataSourceOptions[] diff --git a/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts b/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts index 7f7161859..1d7e362ab 100644 --- a/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts +++ b/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts @@ -4,10 +4,90 @@ export class CreateContacts1690925872693 implements MigrationInterface { name = 'CreateContacts1690925872693' public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `CREATE TABLE "contact_type_entity" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('person','organization') ) NOT NULL, "name" varchar(255) NOT NULL, "description" varchar(255), "tenantId" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "UQ_951a7b2f1b044e348fe5b7a6172" UNIQUE ("name"))` - ) - + await queryRunner.query(`DROP INDEX "IDX_BaseConfigEntity_type"`) + await queryRunner.query(`CREATE TABLE "temporary_BaseConfigEntity" ("id" varchar PRIMARY KEY NOT NULL, "client_id" varchar(255), "client_secret" varchar(255), "scopes" text, "issuer" varchar(255), "redirect_url" text, "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "identifier" varchar(255), "session_id" varchar(255), "type" varchar NOT NULL, "connectionId" varchar, CONSTRAINT "REL_BaseConfig_connectionId" UNIQUE ("connectionId"))`) + await queryRunner.query(`INSERT INTO "temporary_BaseConfigEntity"("id", "client_id", "client_secret", "scopes", "issuer", "redirect_url", "dangerously_allow_insecure_http_requests", "client_auth_method", "identifier", "session_id", "type", "connectionId") SELECT "id", "client_id", "client_secret", "scopes", "issuer", "redirect_url", "dangerously_allow_insecure_http_requests", "client_auth_method", "identifier", "session_id", "type", "connectionId" FROM "BaseConfigEntity"`) + await queryRunner.query(`DROP TABLE "BaseConfigEntity"`) + await queryRunner.query(`ALTER TABLE "temporary_BaseConfigEntity" RENAME TO "BaseConfigEntity"`) + await queryRunner.query(`CREATE INDEX "IDX_BaseConfigEntity_type" ON "BaseConfigEntity" ("type")`) + await queryRunner.query(`CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identityId" varchar, CONSTRAINT "REL_CorrelationIdentifier_identityId" UNIQUE ("identityId"), CONSTRAINT "UQ_Correlation_id" UNIQUE ("correlation_id"))`) + await queryRunner.query(`INSERT INTO "temporary_CorrelationIdentifier"("id", "type", "correlation_id", "identityId") SELECT "id", "type", "correlation_id", "identityId" FROM "CorrelationIdentifier"`) + await queryRunner.query(`DROP TABLE "CorrelationIdentifier"`) + await queryRunner.query(`ALTER TABLE "temporary_CorrelationIdentifier" RENAME TO "CorrelationIdentifier"`) + await queryRunner.query(`CREATE TABLE "temporary_IdentityMetadata" ("id" varchar PRIMARY KEY NOT NULL, "label" varchar(255) NOT NULL, "value" varchar(255) NOT NULL, "identityId" varchar)`) + await queryRunner.query(`INSERT INTO "temporary_IdentityMetadata"("id", "label", "value", "identityId") SELECT "id", "label", "value", "identityId" FROM "IdentityMetadata"`) + await queryRunner.query(`DROP TABLE "IdentityMetadata"`) + await queryRunner.query(`ALTER TABLE "temporary_IdentityMetadata" RENAME TO "IdentityMetadata"`) + await queryRunner.query(`CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Alias" UNIQUE ("alias"))`) + await queryRunner.query(`INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"`) + await queryRunner.query(`DROP TABLE "Identity"`) + await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) + await queryRunner.query(`CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identityId" varchar, CONSTRAINT "REL_Connection_identityId" UNIQUE ("identityId"))`) + await queryRunner.query(`INSERT INTO "temporary_Connection"("id", "type", "identityId") SELECT "id", "type", "identityId" FROM "Connection"`) + await queryRunner.query(`DROP TABLE "Connection"`) + await queryRunner.query(`ALTER TABLE "temporary_Connection" RENAME TO "Connection"`) + await queryRunner.query(`DROP INDEX "IDX_BaseConfigEntity_type"`) + await queryRunner.query(`CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Alias" UNIQUE ("alias"))`) + await queryRunner.query(`INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"`) + await queryRunner.query(`DROP TABLE "Identity"`) + await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) + await queryRunner.query(`CREATE TABLE "ContactType" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('person','organization') ) NOT NULL, "name" varchar(255) NOT NULL, "description" varchar(255), "tenantId" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "UQ_2229e0d8c1e6817efcc982a6dde" UNIQUE ("name"))`) + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_1a1fa2aa0a56649427e427a41f" ON "ContactType" ("type", "tenantId")`) + await queryRunner.query(`CREATE TABLE "ContactOwner" ("id" varchar PRIMARY KEY NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "firstName" varchar(255), "middleName" varchar(255), "lastName" varchar(255), "displayName" varchar(255), "legalName" varchar(255), "cocNumber" varchar(255), "type" varchar NOT NULL, "contactId" varchar, CONSTRAINT "UQ_9177af8a51a2a0598d3a8c68e1e" UNIQUE ("displayName"), CONSTRAINT "UQ_91bf22d2597ff429ece6ae807aa" UNIQUE ("legalName"), CONSTRAINT "UQ_9177af8a51a2a0598d3a8c68e1e" UNIQUE ("displayName"), CONSTRAINT "REL_26ce21b29da1426fa1198b947e" UNIQUE ("contactId"))`) + await queryRunner.query(`CREATE INDEX "IDX_e50c368daf85e7ae54585b0f7b" ON "ContactOwner" ("type")`) + await queryRunner.query(`CREATE TABLE "ContactRelationship" ("id" varchar PRIMARY KEY NOT NULL, "leftId" varchar NOT NULL, "rightId" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')))`) + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_ContactRelationshipEntity_left_right" ON "ContactRelationship" ("leftId", "rightId")`) + await queryRunner.query(`CREATE TABLE "temporary_Contact" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')))`) + await queryRunner.query(`INSERT INTO "temporary_Contact"("id", "uri", "created_at", "last_updated_at") SELECT "id", "uri", "created_at", "last_updated_at" FROM "Contact"`) + await queryRunner.query(`DROP TABLE "Contact"`) + await queryRunner.query(`ALTER TABLE "temporary_Contact" RENAME TO "Contact"`) + await queryRunner.query(`CREATE TABLE "temporary_Contact" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactTypeId" varchar NOT NULL)`) + await queryRunner.query(`INSERT INTO "temporary_Contact"("id", "uri", "created_at", "last_updated_at") SELECT "id", "uri", "created_at", "last_updated_at" FROM "Contact"`) + await queryRunner.query(`DROP TABLE "Contact"`) + await queryRunner.query(`ALTER TABLE "temporary_Contact" RENAME TO "Contact"`) + await queryRunner.query(`CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Alias" UNIQUE ("alias"))`) + await queryRunner.query(`INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"`) + await queryRunner.query(`DROP TABLE "Identity"`) + await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) + await queryRunner.query(`CREATE INDEX "IDX_228953a09ee91bbac6e28b7345" ON "BaseConfigEntity" ("type")`) + await queryRunner.query(`DROP INDEX "IDX_228953a09ee91bbac6e28b7345"`) + await queryRunner.query(`CREATE TABLE "temporary_BaseConfigEntity" ("id" varchar PRIMARY KEY NOT NULL, "client_id" varchar(255), "client_secret" varchar(255), "scopes" text, "issuer" varchar(255), "redirect_url" text, "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "identifier" varchar(255), "session_id" varchar(255), "type" varchar NOT NULL, "connectionId" varchar, CONSTRAINT "REL_BaseConfig_connectionId" UNIQUE ("connectionId"), CONSTRAINT "FK_0ab3b33e0a87e1706025e63d8a9" FOREIGN KEY ("connectionId") REFERENCES "Connection" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) + await queryRunner.query(`INSERT INTO "temporary_BaseConfigEntity"("id", "client_id", "client_secret", "scopes", "issuer", "redirect_url", "dangerously_allow_insecure_http_requests", "client_auth_method", "identifier", "session_id", "type", "connectionId") SELECT "id", "client_id", "client_secret", "scopes", "issuer", "redirect_url", "dangerously_allow_insecure_http_requests", "client_auth_method", "identifier", "session_id", "type", "connectionId" FROM "BaseConfigEntity"`) + await queryRunner.query(`DROP TABLE "BaseConfigEntity"`) + await queryRunner.query(`ALTER TABLE "temporary_BaseConfigEntity" RENAME TO "BaseConfigEntity"`) + await queryRunner.query(`CREATE INDEX "IDX_228953a09ee91bbac6e28b7345" ON "BaseConfigEntity" ("type")`) + await queryRunner.query(`CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identityId" varchar, CONSTRAINT "REL_CorrelationIdentifier_identityId" UNIQUE ("identityId"), CONSTRAINT "UQ_Correlation_id" UNIQUE ("correlation_id"), CONSTRAINT "FK_28945c1d57c5feee1d5d1f54510" FOREIGN KEY ("identityId") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) + await queryRunner.query(`INSERT INTO "temporary_CorrelationIdentifier"("id", "type", "correlation_id", "identityId") SELECT "id", "type", "correlation_id", "identityId" FROM "CorrelationIdentifier"`) + await queryRunner.query(`DROP TABLE "CorrelationIdentifier"`) + await queryRunner.query(`ALTER TABLE "temporary_CorrelationIdentifier" RENAME TO "CorrelationIdentifier"`) + await queryRunner.query(`CREATE TABLE "temporary_IdentityMetadata" ("id" varchar PRIMARY KEY NOT NULL, "label" varchar(255) NOT NULL, "value" varchar(255) NOT NULL, "identityId" varchar, CONSTRAINT "FK_e22568cc3d201c0131b87186117" FOREIGN KEY ("identityId") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) + await queryRunner.query(`INSERT INTO "temporary_IdentityMetadata"("id", "label", "value", "identityId") SELECT "id", "label", "value", "identityId" FROM "IdentityMetadata"`) + await queryRunner.query(`DROP TABLE "IdentityMetadata"`) + await queryRunner.query(`ALTER TABLE "temporary_IdentityMetadata" RENAME TO "IdentityMetadata"`) + await queryRunner.query(`DROP INDEX "IDX_e50c368daf85e7ae54585b0f7b"`) + await queryRunner.query(`CREATE TABLE "temporary_ContactOwner" ("id" varchar PRIMARY KEY NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "firstName" varchar(255), "middleName" varchar(255), "lastName" varchar(255), "displayName" varchar(255), "legalName" varchar(255), "cocNumber" varchar(255), "type" varchar NOT NULL, "contactId" varchar, CONSTRAINT "UQ_9177af8a51a2a0598d3a8c68e1e" UNIQUE ("displayName"), CONSTRAINT "UQ_91bf22d2597ff429ece6ae807aa" UNIQUE ("legalName"), CONSTRAINT "UQ_9177af8a51a2a0598d3a8c68e1e" UNIQUE ("displayName"), CONSTRAINT "REL_26ce21b29da1426fa1198b947e" UNIQUE ("contactId"), CONSTRAINT "FK_26ce21b29da1426fa1198b947e1" FOREIGN KEY ("contactId") REFERENCES "Contact" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) + await queryRunner.query(`INSERT INTO "temporary_ContactOwner"("id", "created_at", "last_updated_at", "firstName", "middleName", "lastName", "displayName", "legalName", "cocNumber", "type", "contactId") SELECT "id", "created_at", "last_updated_at", "firstName", "middleName", "lastName", "displayName", "legalName", "cocNumber", "type", "contactId" FROM "ContactOwner"`) + await queryRunner.query(`DROP TABLE "ContactOwner"`) + await queryRunner.query(`ALTER TABLE "temporary_ContactOwner" RENAME TO "ContactOwner"`) + await queryRunner.query(`CREATE INDEX "IDX_e50c368daf85e7ae54585b0f7b" ON "ContactOwner" ("type")`) + await queryRunner.query(`DROP INDEX "IDX_ContactRelationshipEntity_left_right"`) + await queryRunner.query(`CREATE TABLE "temporary_ContactRelationship" ("id" varchar PRIMARY KEY NOT NULL, "leftId" varchar NOT NULL, "rightId" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "FK_24a7bc0595cc5da51c91e1bee62" FOREIGN KEY ("leftId") REFERENCES "Contact" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "FK_e673c9f78f3c7670a75c0ea7710" FOREIGN KEY ("rightId") REFERENCES "Contact" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) + await queryRunner.query(`INSERT INTO "temporary_ContactRelationship"("id", "leftId", "rightId", "created_at", "last_updated_at") SELECT "id", "leftId", "rightId", "created_at", "last_updated_at" FROM "ContactRelationship"`) + await queryRunner.query(`DROP TABLE "ContactRelationship"`) + await queryRunner.query(`ALTER TABLE "temporary_ContactRelationship" RENAME TO "ContactRelationship"`) + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_ContactRelationshipEntity_left_right" ON "ContactRelationship" ("leftId", "rightId")`) + await queryRunner.query(`CREATE TABLE "temporary_Contact" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactTypeId" varchar NOT NULL, CONSTRAINT "FK_a992c5cdc48d0bc105d0338f982" FOREIGN KEY ("contactTypeId") REFERENCES "ContactType" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`) + await queryRunner.query(`INSERT INTO "temporary_Contact"("id", "uri", "created_at", "last_updated_at", "contactTypeId") SELECT "id", "uri", "created_at", "last_updated_at", "contactTypeId" FROM "Contact"`) + await queryRunner.query(`DROP TABLE "Contact"`) + await queryRunner.query(`ALTER TABLE "temporary_Contact" RENAME TO "Contact"`) + await queryRunner.query(`CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Alias" UNIQUE ("alias"), CONSTRAINT "FK_70ac2a54e2041b7914613204e3d" FOREIGN KEY ("contactId") REFERENCES "Contact" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) + await queryRunner.query(`INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"`) + await queryRunner.query(`DROP TABLE "Identity"`) + await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) + await queryRunner.query(`CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identityId" varchar, CONSTRAINT "REL_Connection_identityId" UNIQUE ("identityId"), CONSTRAINT "FK_fff3668c112a6863bb8c37519a0" FOREIGN KEY ("identityId") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) + await queryRunner.query(`INSERT INTO "temporary_Connection"("id", "type", "identityId") SELECT "id", "type", "identityId" FROM "Connection"`) + await queryRunner.query(`DROP TABLE "Connection"`) + await queryRunner.query(`ALTER TABLE "temporary_Connection" RENAME TO "Connection"`) } public async down(queryRunner: QueryRunner): Promise { diff --git a/packages/data-store/src/types/contact/IAbstractContactStore.ts b/packages/data-store/src/types/contact/IAbstractContactStore.ts index 8385213ac..8dcfd9a1a 100644 --- a/packages/data-store/src/types/contact/IAbstractContactStore.ts +++ b/packages/data-store/src/types/contact/IAbstractContactStore.ts @@ -28,13 +28,13 @@ export interface IGetContactsArgs { export interface IAddContactArgs { uri?: string - contactType: BasicContactType // TODO we can have a situation where we want to add a contact to an existing type, so use BasicContactType | IContactType? also make a test for these 2 situations in the store + contactType: BasicContactType contactOwner: BasicContactOwner identities?: Array } export interface IUpdateContactArgs { - contact: Omit + contact: Omit } export interface IRemoveContactArgs { From 7c2d544a784e8297b83a49eb01fc0d14a4334d1a Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Thu, 3 Aug 2023 10:54:03 +0200 Subject: [PATCH 07/35] DPP-1 WIP --- packages/contact-manager/src/types/IContactManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contact-manager/src/types/IContactManager.ts b/packages/contact-manager/src/types/IContactManager.ts index 6895d077d..6a18e0a0e 100644 --- a/packages/contact-manager/src/types/IContactManager.ts +++ b/packages/contact-manager/src/types/IContactManager.ts @@ -47,7 +47,7 @@ export interface IGetContactsArgs { export interface IAddContactArgs { uri?: string - contactType: BasicContactType // TODO we can have a situation where we want to add a contact to an existing type, so use BasicContactType | IContactType? also make a test for these 2 situations in the store + contactType: BasicContactType contactOwner: BasicContactOwner identities?: Array } From f82ebb2cbed9a070fdf37b5d87c3ab8823c040c1 Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Thu, 3 Aug 2023 10:58:44 +0200 Subject: [PATCH 08/35] DPP-1 added index name --- packages/data-store/src/entities/contact/ContactTypeEntity.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/data-store/src/entities/contact/ContactTypeEntity.ts b/packages/data-store/src/entities/contact/ContactTypeEntity.ts index 70f241725..42462a5d3 100644 --- a/packages/data-store/src/entities/contact/ContactTypeEntity.ts +++ b/packages/data-store/src/entities/contact/ContactTypeEntity.ts @@ -6,7 +6,7 @@ import { IsNonEmptyStringConstraint } from '../validators' import { getConstraint } from '../../utils/ValidatorUtils' @Entity('ContactType') -@Index(['type', 'tenantId'], { unique: true }) // TODO name example: 'IDX_CredentialLocaleBrandingEntity_credentialBranding_locale', +@Index('IDX_ContactTypeEntity_type_tenantId', ['type', 'tenantId'], { unique: true }) // TODO use name for migrations export class ContactTypeEntity { @PrimaryGeneratedColumn('uuid') id!: string From ff03e381f3c89791536500f255b764e89eef280d Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Wed, 30 Aug 2023 13:53:36 +0200 Subject: [PATCH 09/35] DPP-1 refactor work --- .../shared/contactManagerAgentLogic.ts | 278 ++-- packages/contact-manager/package.json | 4 +- .../src/agent/ContactManager.ts | 131 +- .../src/types/IContactManager.ts | 129 +- packages/data-store/package.json | 2 +- .../src/__tests__/contact.entities.test.ts | 1314 +++++++---------- .../src/__tests__/contact.store.test.ts | 1174 +++++++-------- .../src/contact/AbstractContactStore.ts | 88 +- .../data-store/src/contact/ContactStore.ts | 409 +++-- .../src/entities/contact/BaseConfigEntity.ts | 57 +- .../src/entities/contact/BaseContactEntity.ts | 21 + .../src/entities/contact/ConnectionEntity.ts | 47 +- .../src/entities/contact/ContactEntity.ts | 166 --- .../entities/contact/ContactOwnerEntity.ts | 29 - .../contact/ContactRelationshipEntity.ts | 70 - .../contact/CorrelationIdentifierEntity.ts | 20 +- .../entities/contact/DidAuthConfigEntity.ts | 20 +- .../contact/ElectronicAddressEntity.ts | 53 + .../src/entities/contact/IdentityEntity.ts | 46 +- .../contact/IdentityMetadataItemEntity.ts | 18 +- .../entities/contact/NaturalPersonEntity.ts | 38 + .../entities/contact/OpenIdConfigEntity.ts | 24 +- .../entities/contact/OrganizationEntity.ts | 45 +- .../src/entities/contact/PartyEntity.ts | 111 ++ .../contact/PartyRelationshipEntity.ts | 54 + ...ontactTypeEntity.ts => PartyTypeEntity.ts} | 45 +- .../src/entities/contact/PersonEntity.ts | 60 - packages/data-store/src/index.ts | 63 +- .../migrations/generic/2-CreateContacts.ts | 12 +- .../src/migrations/generic/index.ts | 6 +- .../sqlite/1690925872693-CreateContacts.ts | 144 +- .../types/contact/IAbstractContactStore.ts | 105 +- .../data-store/src/types/contact/contact.ts | 203 +-- .../src/utils/contact/MappingUtils.ts | 344 +++++ pnpm-lock.yaml | 38 +- 35 files changed, 2661 insertions(+), 2707 deletions(-) create mode 100644 packages/data-store/src/entities/contact/BaseContactEntity.ts delete mode 100644 packages/data-store/src/entities/contact/ContactEntity.ts delete mode 100644 packages/data-store/src/entities/contact/ContactOwnerEntity.ts delete mode 100644 packages/data-store/src/entities/contact/ContactRelationshipEntity.ts create mode 100644 packages/data-store/src/entities/contact/ElectronicAddressEntity.ts create mode 100644 packages/data-store/src/entities/contact/NaturalPersonEntity.ts create mode 100644 packages/data-store/src/entities/contact/PartyEntity.ts create mode 100644 packages/data-store/src/entities/contact/PartyRelationshipEntity.ts rename packages/data-store/src/entities/contact/{ContactTypeEntity.ts => PartyTypeEntity.ts} (50%) delete mode 100644 packages/data-store/src/entities/contact/PersonEntity.ts create mode 100644 packages/data-store/src/utils/contact/MappingUtils.ts diff --git a/packages/contact-manager/__tests__/shared/contactManagerAgentLogic.ts b/packages/contact-manager/__tests__/shared/contactManagerAgentLogic.ts index 68ea306a5..e6a6b3c7e 100644 --- a/packages/contact-manager/__tests__/shared/contactManagerAgentLogic.ts +++ b/packages/contact-manager/__tests__/shared/contactManagerAgentLogic.ts @@ -1,17 +1,15 @@ import { TAgent } from '@veramo/core' -import { IContactManager } from '../../src' +import { AddContactArgs, IContactManager } from '../../src' import { - BasicPerson, - ContactTypeEnum, + PartyTypeEnum, CorrelationIdentifierEnum, - IBasicContact, - IBasicIdentity, - IContact, + NonPersistedIdentity, + Party, IdentityRoleEnum, - IIdentity, - IPerson, - IGetContactsArgs, - IContactRelationship, + Identity, + NaturalPerson, + GetPartiesArgs, + PartyRelationship, } from '../../../data-store/src' type ConfiguredAgent = TAgent @@ -19,29 +17,33 @@ type ConfiguredAgent = TAgent export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Promise; tearDown: () => Promise }): void => { describe('Contact Manager Agent Plugin', (): void => { let agent: ConfiguredAgent - let defaultContact: IContact - let defaultIdentity: IIdentity + let defaultContact: Party + let defaultIdentity: Identity beforeAll(async (): Promise => { await testContext.setup() agent = testContext.getAgent() - const contact: IBasicContact = { + const contact: AddContactArgs = { //NonPersistedParty + firstName: 'default_first_name', + middleName: 'default_middle_name', + lastName: 'default_last_name', + displayName: 'default_display_name', contactType: { - type: ContactTypeEnum.PERSON, + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { - firstName: 'default_first_name', - middleName: 'default_middle_name', - lastName: 'default_last_name', - displayName: 'default_display_name', - }, + // contact: { + // firstName: 'default_first_name', + // middleName: 'default_middle_name', + // lastName: 'default_last_name', + // displayName: 'default_display_name', + // }, uri: 'example.com', } const correlationId = 'default_example_did' - const identity: IBasicIdentity = { + const identity: NonPersistedIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -56,7 +58,7 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro afterAll(testContext.tearDown) it('should get contact by id', async (): Promise => { - const result: IContact = await agent.cmGetContact({ contactId: defaultContact.id }) + const result: Party = await agent.cmGetContact({ contactId: defaultContact.id }) expect(result.id).toEqual(defaultContact.id) }) @@ -64,155 +66,146 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro it('should throw error when getting contact with unknown id', async (): Promise => { const contactId = 'unknownContactId' - await expect(agent.cmGetContact({ contactId })).rejects.toThrow(`No contact found for id: ${contactId}`) + await expect(agent.cmGetContact({ contactId })).rejects.toThrow(`No party found for id: ${contactId}`) }) it('should get all contacts', async (): Promise => { - const result: Array = await agent.cmGetContacts() + const result: Array = await agent.cmGetContacts() expect(result.length).toBeGreaterThan(0) }) it('should get contacts by filter', async (): Promise => { - const args: IGetContactsArgs = { + const args: GetPartiesArgs = { filter: [ { - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, }, }, { - contactOwner: { + contact: { displayName: 'default_display_name', }, }, { uri: 'example.com' }, ], } - const result: Array = await agent.cmGetContacts(args) + const result: Array = await agent.cmGetContacts(args) expect(result.length).toBe(1) }) it('should get contacts by name', async (): Promise => { - const args: IGetContactsArgs = { + const args: GetPartiesArgs = { filter: [ - { contactOwner: { firstName: 'default_first_name' } }, - { contactOwner: { middleName: 'default_middle_name' } }, - { contactOwner: { lastName: 'default_last_name' } }, + { contact: { firstName: 'default_first_name' } }, + { contact: { middleName: 'default_middle_name' } }, + { contact: { lastName: 'default_last_name' } }, ], } - const result: Array = await agent.cmGetContacts(args) + const result: Array = await agent.cmGetContacts(args) expect(result.length).toBe(1) }) it('should get contacts by display name', async (): Promise => { - const args: IGetContactsArgs = { - filter: [{ contactOwner: { displayName: 'default_display_name' } }], + const args: GetPartiesArgs = { + filter: [{ contact: { displayName: 'default_display_name' } }], } - const result: Array = await agent.cmGetContacts(args) + const result: Array = await agent.cmGetContacts(args) expect(result.length).toBe(1) }) it('should get contacts by uri', async (): Promise => { - const args: IGetContactsArgs = { + const args: GetPartiesArgs = { filter: [{ uri: 'example.com' }], } - const result: Array = await agent.cmGetContacts(args) + const result: Array = await agent.cmGetContacts(args) expect(result.length).toBe(1) }) it('should return no contacts if filter does not match', async (): Promise => { - const args: IGetContactsArgs = { - filter: [{ contactOwner: { displayName: 'no_match_contact_display_name' } }, { uri: 'no_match_example.com' }], + const args: GetPartiesArgs = { + filter: [{ contact: { displayName: 'no_match_contact_display_name' } }, { uri: 'no_match_example.com' }], } - const result: Array = await agent.cmGetContacts(args) + const result: Array = await agent.cmGetContacts(args) expect(result.length).toBe(0) }) it('should add contact', async (): Promise => { - const contact: IBasicContact = { + const contact: AddContactArgs = { //NonPersistedParty + firstName: 'new_first_name', + middleName: 'new_middle_name', + lastName: 'new_last_name', + displayName: 'new_display_name', contactType: { - type: ContactTypeEnum.PERSON, + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'new_name', description: 'new_description', }, - contactOwner: { - firstName: 'new_first_name', - middleName: 'new_middle_name', - lastName: 'new_last_name', - displayName: 'new_display_name', - }, + // contact: { + // firstName: 'new_first_name', + // middleName: 'new_middle_name', + // lastName: 'new_last_name', + // displayName: 'new_display_name', + // }, uri: 'example.com', + // TODO create better tests for electronicAddresses + electronicAddresses: [{ + type: 'email', + electronicAddress: 'sphereon@sphereon.com' + }] } - const result: IContact = await agent.cmAddContact(contact) + const result: Party = await agent.cmAddContact(contact) - expect(result.contactType.type).toEqual(contact.contactType.type) - expect(result.contactType.name).toEqual(contact.contactType.name) - expect(result.contactType.description).toEqual(contact.contactType.description) - expect((result.contactOwner).firstName).toEqual((contact.contactOwner).firstName) - expect((result.contactOwner).middleName).toEqual((contact.contactOwner).middleName) - expect((result.contactOwner).lastName).toEqual((contact.contactOwner).lastName) - expect((result.contactOwner).displayName).toEqual((contact.contactOwner).displayName) + expect(result.partyType.type).toEqual(contact.contactType.type) + expect(result.partyType.name).toEqual(contact.contactType.name) + expect(result.partyType.description).toEqual(contact.contactType.description) + expect((result.contact).firstName).toEqual(contact.firstName) + expect((result.contact).middleName).toEqual(contact.middleName) + expect((result.contact).lastName).toEqual(contact.lastName) + expect((result.contact).displayName).toEqual(contact.displayName) expect(result.uri).toEqual(contact.uri) - }) - - it('should throw error when adding contact with duplicate display name', async (): Promise => { - const displayName = 'default_display_name' - const contact: IBasicContact = { - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d287', - name: 'example_name2', - }, - contactOwner: { - firstName: 'default_first_name2', - middleName: 'default_middle_name2', - lastName: 'default_last_name2', - displayName, - }, - uri: 'example.com', - } - - await expect(agent.cmAddContact(contact)).rejects.toThrow(`Duplicate names or display are not allowed. Display name: ${displayName}`) + expect(result.electronicAddresses).toBeDefined() + expect(result.electronicAddresses.length).toEqual(1) }) it('should update contact by id', async (): Promise => { const contactFirstName = 'updated_contact_first_name' - const contact: IContact = { + const contact: Party = { ...defaultContact, - contactOwner: { - ...defaultContact.contactOwner, + contact: { + ...defaultContact.contact, firstName: contactFirstName, }, } - const result: IContact = await agent.cmUpdateContact({ contact }) + const result: Party = await agent.cmUpdateContact({ contact }) - expect((result.contactOwner).firstName).toEqual(contactFirstName) + expect((result.contact).firstName).toEqual(contactFirstName) }) it('should throw error when updating contact with unknown id', async (): Promise => { const contactId = 'unknownContactId' - const contact: IContact = { + const contact: Party = { ...defaultContact, id: contactId, - contactOwner: { - ...defaultContact.contactOwner, + contact: { + ...defaultContact.contact, firstName: 'new_first_name', }, } - await expect(agent.cmUpdateContact({ contact })).rejects.toThrow(`No contact found for id: ${contactId}`) + await expect(agent.cmUpdateContact({ contact })).rejects.toThrow(`No party found for id: ${contactId}`) }) it('should get identity by id', async (): Promise => { - const result: IIdentity = await agent.cmGetIdentity({ identityId: defaultIdentity.id }) + const result: Identity = await agent.cmGetIdentity({ identityId: defaultIdentity.id }) expect(result.id).toEqual(defaultIdentity.id) }) @@ -228,14 +221,14 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro }) it('should get all identities for contact', async (): Promise => { - const result: Array = await agent.cmGetIdentities({ filter: [{ contactId: defaultContact.id }] }) + const result: Array = await agent.cmGetIdentities({ filter: [{ partyId: defaultContact.id }] }) expect(result.length).toBeGreaterThan(0) }) it('should add identity to contact', async (): Promise => { const correlationId = 'new_example_did' - const identity: IBasicIdentity = { + const identity: NonPersistedIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -244,8 +237,8 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro }, } - const result: IIdentity = await agent.cmAddIdentity({ contactId: defaultContact.id, identity }) - const contact: IContact = await agent.cmGetContact({ contactId: defaultContact.id }) + const result: Identity = await agent.cmAddIdentity({ contactId: defaultContact.id, identity }) + const contact: Party = await agent.cmGetContact({ contactId: defaultContact.id }) expect(result).not.toBeNull() expect(contact.identities.length).toEqual(2) @@ -259,7 +252,7 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro it('should throw error when adding identity with invalid identifier', async (): Promise => { const correlationId = 'missing_connection_add_example' - const identity: IBasicIdentity = { + const identity: NonPersistedIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -275,7 +268,7 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro it('should throw error when updating identity with invalid identifier', async (): Promise => { const correlationId = 'missing_connection_update_example' - const identity: IBasicIdentity = { + const identity: NonPersistedIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -283,7 +276,7 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro correlationId, }, } - const result: IIdentity = await agent.cmAddIdentity({ contactId: defaultContact.id, identity }) + const result: Identity = await agent.cmAddIdentity({ contactId: defaultContact.id, identity }) result.identifier = { ...result.identifier, type: CorrelationIdentifierEnum.URL } await expect(agent.cmUpdateIdentity({ identity: result })).rejects.toThrow(`Identity with correlation type url should contain a connection`) @@ -291,7 +284,7 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro it('should update identity', async (): Promise => { const correlationId = 'new_update_example_did' - const identity: IBasicIdentity = { + const identity: NonPersistedIdentity = { alias: 'update_example_did', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -299,48 +292,52 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro correlationId: 'update_example_did', }, } - const result: IIdentity = await agent.cmAddIdentity({ contactId: defaultContact.id, identity }) + const result: Identity = await agent.cmAddIdentity({ contactId: defaultContact.id, identity }) result.identifier = { ...result.identifier, correlationId } await agent.cmUpdateIdentity({ identity: result }) - const updatedIdentity: IIdentity = await agent.cmGetIdentity({ identityId: result.id }) + const updatedIdentity: Identity = await agent.cmGetIdentity({ identityId: result.id }) expect(updatedIdentity).not.toBeNull() expect(updatedIdentity.identifier.correlationId).toEqual(correlationId) }) it('should add relationship', async (): Promise => { - const contact: IBasicContact = { + const contact: AddContactArgs = { //NonPersistedParty + firstName: 'relation_first_name', + middleName: 'relation_middle_name', + lastName: 'relation_last_name', + displayName: 'relation_display_name', contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d287', + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d285', name: 'relation_contact_type_name', description: 'new_description', }, - contactOwner: { - firstName: 'relation_first_name', - middleName: 'relation_middle_name', - lastName: 'relation_last_name', - displayName: 'relation_display_name', - }, + // contact: { + // firstName: 'relation_first_name', + // middleName: 'relation_middle_name', + // lastName: 'relation_last_name', + // displayName: 'relation_display_name', + // }, uri: 'example.com', } - const savedContact: IContact = await agent.cmAddContact(contact) + const savedContact: Party = await agent.cmAddContact(contact) // TODO why does this filter not work on only first name? - const args1: IGetContactsArgs = { + const args1: GetPartiesArgs = { filter: [ - { contactOwner: { firstName: 'default_first_name' } }, - { contactOwner: { middleName: 'default_middle_name' } }, + { contact: { firstName: 'default_first_name' } }, + { contact: { middleName: 'default_middle_name' } }, // { contactOwner: { lastName: 'default_last_name'} }, ], } - const otherContacts: Array = await agent.cmGetContacts(args1) + const otherContacts: Array = await agent.cmGetContacts(args1) expect(otherContacts.length).toEqual(1) - const relationship: IContactRelationship = await agent.cmAddRelationship({ + const relationship: PartyRelationship = await agent.cmAddRelationship({ leftId: savedContact.id, rightId: otherContacts[0].id, }) @@ -348,14 +345,13 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro expect(relationship).toBeDefined() // TODO why does this filter not work on only first name? - const args2: IGetContactsArgs = { + const args2: GetPartiesArgs = { filter: [ - { contactOwner: { firstName: 'relation_first_name' } }, - { contactOwner: { middleName: 'relation_middle_name' } }, - // { contactOwner: { lastName: 'default_last_name'} }, + { contact: { firstName: 'relation_first_name' } }, + { contact: { middleName: 'relation_middle_name' } }, ], } - const result: Array = await agent.cmGetContacts(args2) + const result: Array = await agent.cmGetContacts(args2) expect(result.length).toEqual(1) expect(result[0].relationships.length).toEqual(1) @@ -364,37 +360,41 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro }) it('should remove relationship', async (): Promise => { - const contact: IBasicContact = { + const contact: AddContactArgs = { //NonPersistedParty + firstName: 'remove_relation_first_name', + middleName: 'remove_relation_middle_name', + lastName: 'remove_relation_last_name', + displayName: 'remove_relation_display_name', contactType: { - type: ContactTypeEnum.PERSON, + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d286', name: 'remove_relation_contact_type_name', description: 'new_description', }, - contactOwner: { - firstName: 'remove_relation_first_name', - middleName: 'remove_relation_middle_name', - lastName: 'remove_relation_last_name', - displayName: 'remove_relation_display_name', - }, + // contact: { + // firstName: 'remove_relation_first_name', + // middleName: 'remove_relation_middle_name', + // lastName: 'remove_relation_last_name', + // displayName: 'remove_relation_display_name', + // }, uri: 'example.com', } - const savedContact: IContact = await agent.cmAddContact(contact) + const savedContact: Party = await agent.cmAddContact(contact) // TODO why does this filter not work on only first name? - const args1: IGetContactsArgs = { + const args1: GetPartiesArgs = { filter: [ - { contactOwner: { firstName: 'default_first_name' } }, - { contactOwner: { middleName: 'default_middle_name' } }, + { contact: { firstName: 'default_first_name' } }, + { contact: { middleName: 'default_middle_name' } }, // { contactOwner: { lastName: 'default_last_name'} }, ], } - const otherContacts: Array = await agent.cmGetContacts(args1) + const otherContacts: Array = await agent.cmGetContacts(args1) expect(otherContacts.length).toEqual(1) - const relationship: IContactRelationship = await agent.cmAddRelationship({ + const relationship: PartyRelationship = await agent.cmAddRelationship({ leftId: savedContact.id, rightId: otherContacts[0].id, }) @@ -402,14 +402,14 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro expect(relationship).toBeDefined() // TODO why does this filter not work on only first name? - const args2: IGetContactsArgs = { + const args2: GetPartiesArgs = { filter: [ - { contactOwner: { firstName: 'relation_first_name' } }, - { contactOwner: { middleName: 'relation_middle_name' } }, + { contact: { firstName: 'relation_first_name' } }, + { contact: { middleName: 'relation_middle_name' } }, // { contactOwner: { lastName: 'default_last_name'} }, ], } - const retrievedContact: Array = await agent.cmGetContacts(args2) + const retrievedContact: Array = await agent.cmGetContacts(args2) expect(retrievedContact.length).toEqual(1) expect(retrievedContact[0].relationships.length).toEqual(1) @@ -419,13 +419,9 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro const removeRelationshipResult: boolean = await agent.cmRemoveRelationship({ relationshipId: relationship.id }) expect(removeRelationshipResult).toBeTruthy() - const result: IContact = await agent.cmGetContact({ contactId: savedContact.id }) + const result: Party = await agent.cmGetContact({ contactId: savedContact.id }) expect(result.relationships.length).toEqual(0) }) - - // TODO test all new crud functions - - // remove relation }) } diff --git a/packages/contact-manager/package.json b/packages/contact-manager/package.json index 0f19c6511..475542996 100644 --- a/packages/contact-manager/package.json +++ b/packages/contact-manager/package.json @@ -14,13 +14,13 @@ "build:clean": "tsc --build --clean && tsc --build" }, "dependencies": { - "@sphereon/ssi-sdk.data-store": "workspace:*", + "@sphereon/ssi-sdk.data-store": "file://C:\\ssi-sdk\\packages\\data-store\\sphereon-ssi-sdk.data-store-0.23.0-bram.tgz", "cross-fetch": "^3.1.5", "typeorm": "^0.3.12" }, "devDependencies": { "@sphereon/ssi-sdk.agent-config": "workspace:*", - "@sphereon/ssi-sdk.data-store": "workspace:*", + "@sphereon/ssi-sdk.data-store": "file://C:\\ssi-sdk\\packages\\data-store\\sphereon-ssi-sdk.data-store-0.23.0-bram.tgz", "@veramo/remote-client": "4.2.0", "@veramo/remote-server": "4.2.0" }, diff --git a/packages/contact-manager/src/agent/ContactManager.ts b/packages/contact-manager/src/agent/ContactManager.ts index 07f057ce5..8be365d6f 100644 --- a/packages/contact-manager/src/agent/ContactManager.ts +++ b/packages/contact-manager/src/agent/ContactManager.ts @@ -1,30 +1,36 @@ import { IAgentPlugin } from '@veramo/core' import { schema } from '../index' import { - IAddContactArgs, - IUpdateContactArgs, - IGetIdentitiesArgs, - IRemoveContactArgs, - IAddIdentityArgs, + AddContactArgs, + UpdateContactArgs, + GetIdentitiesArgs, + RemoveContactArgs, + AddIdentityArgs, IContactManager, - IGetIdentityArgs, - IRemoveIdentityArgs, - IRequiredContext, - IUpdateIdentityArgs, - IGetContactsArgs, - IGetContactArgs, - IAddRelationshipArgs, - IRemoveRelationshipArgs, - IGetRelationshipArgs, - IGetRelationshipsArgs, - IUpdateRelationshipArgs, - IAddContactTypeArgs, - IGetContactTypeArgs, - IGetContactTypesArgs, - IRemoveContactTypeArgs, - IUpdateContactTypeArgs, + GetIdentityArgs, + RemoveIdentityArgs, + RequiredContext, + UpdateIdentityArgs, + GetContactsArgs, + GetContactArgs, + AddRelationshipArgs, + RemoveRelationshipArgs, + GetRelationshipArgs, + GetRelationshipsArgs, + UpdateRelationshipArgs, + AddContactTypeArgs, + GetContactTypeArgs, + GetContactTypesArgs, + RemoveContactTypeArgs, + UpdateContactTypeArgs, } from '../types/IContactManager' -import { IContact, IIdentity, AbstractContactStore, IContactRelationship, IContactType } from '@sphereon/ssi-sdk.data-store' +import { + AbstractContactStore, + Party as Contact, + Identity, + PartyRelationship as ContactRelationship, + PartyType as ContactType +} from '@sphereon/ssi-sdk.data-store' /** * {@inheritDoc IContactManager} @@ -61,102 +67,121 @@ export class ContactManager implements IAgentPlugin { } /** {@inheritDoc IContactManager.cmGetContact} */ - private async cmGetContact(args: IGetContactArgs, context: IRequiredContext): Promise { - return this.store.getContact(args) + private async cmGetContact(args: GetContactArgs, context: RequiredContext): Promise { + return this.store.getParty({ partyId: args.contactId }) } /** {@inheritDoc IContactManager.cmGetContacts} */ - private async cmGetContacts(args?: IGetContactsArgs): Promise> { - return this.store.getContacts(args) + private async cmGetContacts(args?: GetContactsArgs): Promise> { + return this.store.getParties(args) } /** {@inheritDoc IContactManager.cmAddContact} */ - private async cmAddContact(args: IAddContactArgs, context: IRequiredContext): Promise { - return this.store.addContact(args) + private async cmAddContact(args: AddContactArgs, context: RequiredContext): Promise { + // TODO this needs to be improved + const contact = ('firstName' in args && 'lastName' in args) + ? { firstName: args.firstName, middleName: args.middleName, lastName: args.lastName, displayName: args.displayName} + : { legalName: args.legalName, displayName: args.displayName } + + + // export type AddPartyArgs = { + // uri?: string + // partyType: NonPersistedPartyType + // contact: NonPersistedContact + // identities?: Array + // } + // TODO add electronic addresses + return this.store.addParty({ + uri: args.uri, + partyType: args.contactType, + contact, + identities: args.identities, + electronicAddresses: args.electronicAddresses + }) } /** {@inheritDoc IContactManager.cmUpdateContact} */ - private async cmUpdateContact(args: IUpdateContactArgs, context: IRequiredContext): Promise { - return this.store.updateContact(args) + private async cmUpdateContact(args: UpdateContactArgs, context: RequiredContext): Promise { + return this.store.updateParty({ party: args.contact }) } /** {@inheritDoc IContactManager.cmRemoveContact} */ - private async cmRemoveContact(args: IRemoveContactArgs, context: IRequiredContext): Promise { - return this.store.removeContact(args).then(() => true) + private async cmRemoveContact(args: RemoveContactArgs, context: RequiredContext): Promise { + return this.store.removeParty({ partyId: args.contactId }).then(() => true) } /** {@inheritDoc IContactManager.cmGetIdentity} */ - private async cmGetIdentity(args: IGetIdentityArgs, context: IRequiredContext): Promise { + private async cmGetIdentity(args: GetIdentityArgs, context: RequiredContext): Promise { return this.store.getIdentity(args) } /** {@inheritDoc IContactManager.cmGetIdentities} */ - private async cmGetIdentities(args?: IGetIdentitiesArgs): Promise> { + private async cmGetIdentities(args?: GetIdentitiesArgs): Promise> { return this.store.getIdentities(args) } /** {@inheritDoc IContactManager.cmAddIdentity} */ - private async cmAddIdentity(args: IAddIdentityArgs, context: IRequiredContext): Promise { - return this.store.addIdentity(args) + private async cmAddIdentity(args: AddIdentityArgs, context: RequiredContext): Promise { + return this.store.addIdentity({ partyId: args.contactId, identity: args.identity }) } /** {@inheritDoc IContactManager.cmUpdateIdentity} */ - private async cmUpdateIdentity(args: IUpdateIdentityArgs, context: IRequiredContext): Promise { + private async cmUpdateIdentity(args: UpdateIdentityArgs, context: RequiredContext): Promise { return this.store.updateIdentity(args) } /** {@inheritDoc IContactManager.cmRemoveIdentity} */ - private async cmRemoveIdentity(args: IRemoveIdentityArgs, context: IRequiredContext): Promise { + private async cmRemoveIdentity(args: RemoveIdentityArgs, context: RequiredContext): Promise { return this.store.removeIdentity(args).then(() => true) } /** {@inheritDoc IContactManager.cmAddRelationship} */ - private async cmAddRelationship(args: IAddRelationshipArgs, context: IRequiredContext): Promise { + private async cmAddRelationship(args: AddRelationshipArgs, context: RequiredContext): Promise { return this.store.addRelationship(args) } /** {@inheritDoc IContactManager.cmRemoveRelationship} */ - private async cmRemoveRelationship(args: IRemoveRelationshipArgs, context: IRequiredContext): Promise { + private async cmRemoveRelationship(args: RemoveRelationshipArgs, context: RequiredContext): Promise { return this.store.removeRelationship(args).then(() => true) } /** {@inheritDoc IContactManager.cmGetRelationship} */ - private async cmGetRelationship(args: IGetRelationshipArgs, context: IRequiredContext): Promise { + private async cmGetRelationship(args: GetRelationshipArgs, context: RequiredContext): Promise { return this.store.getRelationship(args) } /** {@inheritDoc IContactManager.cmGetRelationships} */ - private async cmGetRelationships(args?: IGetRelationshipsArgs): Promise> { + private async cmGetRelationships(args?: GetRelationshipsArgs): Promise> { return this.store.getRelationships(args) } /** {@inheritDoc IContactManager.cmUpdateRelationship} */ - private async cmUpdateRelationship(args: IUpdateRelationshipArgs, context: IRequiredContext): Promise { + private async cmUpdateRelationship(args: UpdateRelationshipArgs, context: RequiredContext): Promise { return this.store.updateRelationship(args) } /** {@inheritDoc IContactManager.cmGetContactType} */ - private async cmGetContactType(args: IGetContactTypeArgs, context: IRequiredContext): Promise { - return this.store.getContactType(args) + private async cmGetContactType(args: GetContactTypeArgs, context: RequiredContext): Promise { + return this.store.getPartyType({ partyTypeId: args.contactTypeId }) } /** {@inheritDoc IContactManager.cmGetContactTypes} */ - private async cmGetContactTypes(args?: IGetContactTypesArgs): Promise> { - return this.store.getContactTypes(args) + private async cmGetContactTypes(args?: GetContactTypesArgs): Promise> { + return this.store.getPartyTypes(args) } /** {@inheritDoc IContactManager.cmAddContactType} */ - private async cmAddContactType(args: IAddContactTypeArgs, context: IRequiredContext): Promise { - return this.store.addContactType(args) + private async cmAddContactType(args: AddContactTypeArgs, context: RequiredContext): Promise { + return this.store.addPartyType(args) } /** {@inheritDoc IContactManager.cmUpdateContactType} */ - private async cmUpdateContactType(args: IUpdateContactTypeArgs, context: IRequiredContext): Promise { - return this.store.updateContactType(args) + private async cmUpdateContactType(args: UpdateContactTypeArgs, context: RequiredContext): Promise { + return this.store.updatePartyType({partyType: args.contactType}) } /** {@inheritDoc IContactManager.cmRemoveContactType} */ - private async cmRemoveContactType(args: IRemoveContactTypeArgs, context: IRequiredContext): Promise { - return this.store.removeContactType(args).then(() => true) + private async cmRemoveContactType(args: RemoveContactTypeArgs, context: RequiredContext): Promise { + return this.store.removePartyType({ partyTypeId: args.contactTypeId }).then(() => true) } } diff --git a/packages/contact-manager/src/types/IContactManager.ts b/packages/contact-manager/src/types/IContactManager.ts index 6a18e0a0e..752ffb3c5 100644 --- a/packages/contact-manager/src/types/IContactManager.ts +++ b/packages/contact-manager/src/types/IContactManager.ts @@ -1,128 +1,131 @@ import { IAgentContext, IPluginMethodMap } from '@veramo/core' import { - BasicContactOwner, - BasicContactType, - FindContactArgs, - FindIdentityArgs, - IBasicIdentity, - IContact, - IContactRelationship, - IIdentity, + Identity, + NonPersistedIdentity, FindRelationshipArgs, - ContactTypeEnum, - FindContactTypeArgs, - IContactType, + FindIdentityArgs, + NonPersistedContact, + PartyTypeEnum as ContactTypeEnum, + NonPersistedPartyType as NonPersistedContactType, + FindPartyTypeArgs as FindContactTypeArgs, + FindPartyArgs as FindContactArgs, + PartyRelationship as ContactRelationship, + PartyType as ContactType, + Party as Contact, NonPersistedParty } from '@sphereon/ssi-sdk.data-store' export interface IContactManager extends IPluginMethodMap { - cmGetContact(args: IGetContactArgs, context: IRequiredContext): Promise - cmGetContacts(args?: IGetContactsArgs): Promise> - cmAddContact(args: IAddContactArgs, context: IRequiredContext): Promise - cmUpdateContact(args: IUpdateContactArgs, context: IRequiredContext): Promise - cmRemoveContact(args: IRemoveContactArgs, context: IRequiredContext): Promise - cmGetIdentity(args: IGetIdentityArgs, context: IRequiredContext): Promise - cmGetIdentities(args?: IGetIdentitiesArgs): Promise> - cmAddIdentity(args: IAddIdentityArgs, context: IRequiredContext): Promise - cmUpdateIdentity(args: IUpdateIdentityArgs, context: IRequiredContext): Promise - cmRemoveIdentity(args: IRemoveIdentityArgs, context: IRequiredContext): Promise - cmGetRelationship(args: IGetRelationshipArgs, context: IRequiredContext): Promise - cmGetRelationships(args?: IGetRelationshipsArgs): Promise> - cmUpdateRelationship(args: IUpdateRelationshipArgs, context: IRequiredContext): Promise - cmAddRelationship(args: IAddRelationshipArgs, context: IRequiredContext): Promise - cmRemoveRelationship(args: IRemoveRelationshipArgs, context: IRequiredContext): Promise - cmGetContactType(args: IGetContactTypeArgs, context: IRequiredContext): Promise - cmGetContactTypes(args?: IGetContactTypesArgs): Promise> - cmAddContactType(args: IAddContactTypeArgs, context: IRequiredContext): Promise - cmUpdateContactType(args: IUpdateContactTypeArgs, context: IRequiredContext): Promise - cmRemoveContactType(args: IRemoveContactTypeArgs, context: IRequiredContext): Promise -} - -export interface IGetContactArgs { + cmGetContact(args: GetContactArgs, context: RequiredContext): Promise + cmGetContacts(args?: GetContactsArgs): Promise> + cmAddContact(args: AddContactArgs, context: RequiredContext): Promise + cmUpdateContact(args: UpdateContactArgs, context: RequiredContext): Promise + cmRemoveContact(args: RemoveContactArgs, context: RequiredContext): Promise + cmGetIdentity(args: GetIdentityArgs, context: RequiredContext): Promise + cmGetIdentities(args?: GetIdentitiesArgs): Promise> + cmAddIdentity(args: AddIdentityArgs, context: RequiredContext): Promise + cmUpdateIdentity(args: UpdateIdentityArgs, context: RequiredContext): Promise + cmRemoveIdentity(args: RemoveIdentityArgs, context: RequiredContext): Promise + cmGetRelationship(args: GetRelationshipArgs, context: RequiredContext): Promise + cmGetRelationships(args?: GetRelationshipsArgs): Promise> + cmUpdateRelationship(args: UpdateRelationshipArgs, context: RequiredContext): Promise + cmAddRelationship(args: AddRelationshipArgs, context: RequiredContext): Promise + cmRemoveRelationship(args: RemoveRelationshipArgs, context: RequiredContext): Promise + cmGetContactType(args: GetContactTypeArgs, context: RequiredContext): Promise + cmGetContactTypes(args?: GetContactTypesArgs): Promise> + cmAddContactType(args: AddContactTypeArgs, context: RequiredContext): Promise + cmUpdateContactType(args: UpdateContactTypeArgs, context: RequiredContext): Promise + cmRemoveContactType(args: RemoveContactTypeArgs, context: RequiredContext): Promise +} + +export type GetContactArgs = { contactId: string } -export interface IGetContactsArgs { +export type GetContactsArgs = { filter?: FindContactArgs } -export interface IAddContactArgs { - uri?: string - contactType: BasicContactType - contactOwner: BasicContactOwner - identities?: Array +// export type AddContactArgs = { +// uri?: string +// contactType: NonPersistedContactType +// identities?: Array +// } & NonPersistedNaturalPerson | NonPersistedOrganization + +export type AddContactArgs = Omit & NonPersistedContact & { + contactType: NonPersistedContactType } -export interface IUpdateContactArgs { - contact: IContact +export type UpdateContactArgs = { + contact: Contact } -export interface IRemoveContactArgs { +export type RemoveContactArgs = { contactId: string } -export interface IGetIdentityArgs { +export type GetIdentityArgs = { identityId: string } -export interface IGetIdentitiesArgs { +export type GetIdentitiesArgs = { filter?: FindIdentityArgs } -export interface IAddIdentityArgs { +export type AddIdentityArgs = { contactId: string - identity: IBasicIdentity + identity: NonPersistedIdentity } -export interface IUpdateIdentityArgs { - identity: IIdentity +export type UpdateIdentityArgs = { + identity: Identity } -export interface IRemoveIdentityArgs { +export type RemoveIdentityArgs = { identityId: string } -export interface IAddRelationshipArgs { +export type AddRelationshipArgs = { leftId: string rightId: string } -export interface IRemoveRelationshipArgs { +export type RemoveRelationshipArgs = { relationshipId: string } -export interface IGetRelationshipArgs { +export type GetRelationshipArgs = { relationshipId: string } -export interface IGetRelationshipsArgs { +export type GetRelationshipsArgs = { filter: FindRelationshipArgs } -export interface IUpdateRelationshipArgs { - relationship: IContactRelationship // TODO do we also want the omits here? +export type UpdateRelationshipArgs = { + relationship: Omit } -export interface IAddContactTypeArgs { +export type AddContactTypeArgs = { type: ContactTypeEnum name: string tenantId: string description?: string } -export interface IGetContactTypeArgs { +export type GetContactTypeArgs = { contactTypeId: string } -export interface IGetContactTypesArgs { +export type GetContactTypesArgs = { filter?: FindContactTypeArgs } -export interface IUpdateContactTypeArgs { - contactType: Omit // TODO do we also want the omits here? +export type UpdateContactTypeArgs = { + contactType: Omit } -export interface IRemoveContactTypeArgs { +export type RemoveContactTypeArgs = { contactTypeId: string } -export type IRequiredContext = IAgentContext +export type RequiredContext = IAgentContext diff --git a/packages/data-store/package.json b/packages/data-store/package.json index 8aa532e27..6b265e0e7 100644 --- a/packages/data-store/package.json +++ b/packages/data-store/package.json @@ -1,6 +1,6 @@ { "name": "@sphereon/ssi-sdk.data-store", - "version": "0.13.0", + "version": "0.23.0-bram", "source": "src/index.ts", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/data-store/src/__tests__/contact.entities.test.ts b/packages/data-store/src/__tests__/contact.entities.test.ts index 6f4f74ca9..689f82b6b 100644 --- a/packages/data-store/src/__tests__/contact.entities.test.ts +++ b/packages/data-store/src/__tests__/contact.entities.test.ts @@ -1,40 +1,48 @@ -import { DataSource - , FindOptionsWhere -} from 'typeorm' +import { DataSource, FindOptionsWhere } from 'typeorm' -import { DataStoreContactEntities +import { + DataStoreContactEntities, // , DataStoreMigrations } from '../index' +import { NaturalPersonEntity } from '../entities/contact/NaturalPersonEntity' +import { OrganizationEntity } from '../entities/contact/OrganizationEntity' +import { PartyRelationshipEntity } from '../entities/contact/PartyRelationshipEntity' +import { PartyTypeEntity } from '../entities/contact/PartyTypeEntity' +import { PartyEntity } from '../entities/contact/PartyEntity' +import { IdentityEntity } from '../entities/contact/IdentityEntity' +import { OpenIdConfigEntity } from '../entities/contact/OpenIdConfigEntity' +import { DidAuthConfigEntity } from '../entities/contact/DidAuthConfigEntity' +import { ConnectionEntity } from '../entities/contact/ConnectionEntity' +import { CorrelationIdentifierEntity } from '../entities/contact/CorrelationIdentifierEntity' +import { IdentityMetadataItemEntity } from '../entities/contact/IdentityMetadataItemEntity' +import { BaseContactEntity } from '../entities/contact/BaseContactEntity' import { - IBasicContact, - ContactTypeEnum, - IPerson, - IOrganization, + NonPersistedParty, + PartyTypeEnum, + NaturalPerson, + Organization, IdentityRoleEnum, CorrelationIdentifierEnum, ConnectionTypeEnum, - BasicContactType, - BasicOrganization, - BasicPerson, - IBasicConnection, - IBasicIdentity, - BasicDidAuthConfig, - BasicOpenIdConfig, + NonPersistedPartyType, + NonPersistedOrganization, + NonPersistedNaturalPerson, + NonPersistedConnection, + NonPersistedIdentity, + NonPersistedDidAuthConfig, + NonPersistedOpenIdConfig, } from '../types' -import { PersonEntity - , personEntityFrom -} from '../entities/contact/PersonEntity' -import { OrganizationEntity, organizationEntityFrom } from '../entities/contact/OrganizationEntity' -import { ContactRelationshipEntity, contactRelationshipEntityFrom } from '../entities/contact/ContactRelationshipEntity' -import { ContactTypeEntity, contactTypeEntityFrom } from '../entities/contact/ContactTypeEntity' -import { ContactEntity, contactEntityFrom } from '../entities/contact/ContactEntity' -import { IdentityEntity, identityEntityFrom } from '../entities/contact/IdentityEntity' -import { OpenIdConfigEntity, openIdConfigEntityFrom } from '../entities/contact/OpenIdConfigEntity' -import { DidAuthConfigEntity, didAuthConfigEntityFrom } from '../entities/contact/DidAuthConfigEntity' -import { ConnectionEntity, connectionEntityFrom } from '../entities/contact/ConnectionEntity' -import { CorrelationIdentifierEntity } from '../entities/contact/CorrelationIdentifierEntity' -import { IdentityMetadataItemEntity } from '../entities/contact/IdentityMetadataItemEntity' -import { ContactOwnerEntity } from '../entities/contact/ContactOwnerEntity' +import { + connectionEntityFrom, + didAuthConfigEntityFrom, + identityEntityFrom, + naturalPersonEntityFrom, + openIdConfigEntityFrom, + organizationEntityFrom, + partyEntityFrom, + partyRelationshipEntityFrom, + partyTypeEntityFrom, +} from '../utils/contact/MappingUtils' describe('Database entities tests', (): void => { let dbConnection: DataSource @@ -85,15 +93,15 @@ describe('Database entities tests', (): void => { await (await dbConnection).destroy() }) - it('Should save person contact to database', async (): Promise => { - const contact: IBasicContact = { + it('Should save person party to database', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', @@ -101,75 +109,73 @@ describe('Database entities tests', (): void => { }, } - const contactEntity: ContactEntity = contactEntityFrom(contact) - await dbConnection.getRepository(ContactEntity).save(contactEntity, { + const partyEntity: PartyEntity = partyEntityFrom(party) + await dbConnection.getRepository(PartyEntity).save(partyEntity, { transaction: true, }) - const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: contactEntity.id }, + const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: partyEntity.id }, }) expect(fromDb).toBeDefined() expect(fromDb?.identities?.length).toEqual(0) - expect(fromDb?.uri).toEqual(contact.uri) - expect(fromDb?.contactType).toBeDefined() - expect(fromDb?.contactType.type).toEqual(contact.contactType.type) - expect(fromDb?.contactType.tenantId).toEqual(contact.contactType.tenantId) - expect(fromDb?.contactType.name).toEqual(contact.contactType.name) - expect(fromDb?.contactOwner).toBeDefined() - expect((fromDb?.contactOwner).firstName).toEqual((contact.contactOwner).firstName) - expect((fromDb?.contactOwner).middleName).toEqual((contact.contactOwner).middleName) - expect((fromDb?.contactOwner).lastName).toEqual((contact.contactOwner).lastName) - expect((fromDb?.contactOwner).displayName).toEqual((contact.contactOwner).displayName) - }) - - it('Should save organization contact to database', async (): Promise => { - const contact: IBasicContact = { + expect(fromDb?.uri).toEqual(party.uri) + expect(fromDb?.partyType).toBeDefined() + expect(fromDb?.partyType.type).toEqual(party.partyType.type) + expect(fromDb?.partyType.tenantId).toEqual(party.partyType.tenantId) + expect(fromDb?.partyType.name).toEqual(party.partyType.name) + expect(fromDb?.contact).toBeDefined() + expect((fromDb?.contact).firstName).toEqual((party.contact).firstName) + expect((fromDb?.contact).middleName).toEqual((party.contact).middleName) + expect((fromDb?.contact).lastName).toEqual((party.contact).lastName) + expect((fromDb?.contact).displayName).toEqual((party.contact).displayName) + }) + + it('Should save organization party to database', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.ORGANIZATION, + partyType: { + type: PartyTypeEnum.ORGANIZATION, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { legalName: 'example_legal_name', displayName: 'example_display_name', - cocNumber: 'example_coc_number', }, } - const contactEntity: ContactEntity = contactEntityFrom(contact) - await dbConnection.getRepository(ContactEntity).save(contactEntity, { + const partyEntity: PartyEntity = partyEntityFrom(party) + await dbConnection.getRepository(PartyEntity).save(partyEntity, { transaction: true, }) - const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: contactEntity.id }, + const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: partyEntity.id }, }) expect(fromDb).toBeDefined() expect(fromDb?.identities?.length).toEqual(0) - expect(fromDb?.uri).toEqual(contact.uri) - expect(fromDb?.contactType).toBeDefined() - expect(fromDb?.contactType.type).toEqual(contact.contactType.type) - expect(fromDb?.contactType.tenantId).toEqual(contact.contactType.tenantId) - expect(fromDb?.contactType.name).toEqual(contact.contactType.name) - expect(fromDb?.contactOwner).toBeDefined() - expect((fromDb?.contactOwner).legalName).toEqual((contact.contactOwner).legalName) - expect((fromDb?.contactOwner).displayName).toEqual((contact.contactOwner).displayName) - expect((fromDb?.contactOwner).cocNumber).toEqual((contact.contactOwner).cocNumber) - }) - - it('Should result in contact relationship for the owner side only', async (): Promise => { - const contact1: IBasicContact = { + expect(fromDb?.uri).toEqual(party.uri) + expect(fromDb?.partyType).toBeDefined() + expect(fromDb?.partyType.type).toEqual(party.partyType.type) + expect(fromDb?.partyType.tenantId).toEqual(party.partyType.tenantId) + expect(fromDb?.partyType.name).toEqual(party.partyType.name) + expect(fromDb?.contact).toBeDefined() + expect((fromDb?.contact).legalName).toEqual((party.contact).legalName) + expect((fromDb?.contact).displayName).toEqual((party.contact).displayName) + }) + + it('Should result in party relationship for the owner side only', async (): Promise => { + const party1: NonPersistedParty = { uri: 'example1.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name1', }, - contactOwner: { + contact: { firstName: 'example_first_name1', middleName: 'example_middle_name1', lastName: 'example_last_name1', @@ -177,19 +183,19 @@ describe('Database entities tests', (): void => { }, } - const contactEntity1: ContactEntity = contactEntityFrom(contact1) - const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + const partyEntity1: PartyEntity = partyEntityFrom(party1) + const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { transaction: true, }) - const contact2: IBasicContact = { + const party2: NonPersistedParty = { uri: 'example2.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'example_name2', }, - contactOwner: { + contact: { firstName: 'example_first_name2', middleName: 'example_middle_name2', lastName: 'example_last_name2', @@ -197,26 +203,26 @@ describe('Database entities tests', (): void => { }, } - const contactEntity2: ContactEntity = contactEntityFrom(contact2) - const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + const partyEntity2: PartyEntity = partyEntityFrom(party2) + const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { transaction: true, }) - const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ - leftId: savedContact1.id, - rightId: savedContact2.id, + const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ + leftId: savedParty1.id, + rightId: savedParty2.id, }) - await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { + await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { transaction: true, }) - const fromDb1: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: savedContact1.id }, + const fromDb1: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: savedParty1.id }, }) - const fromDb2: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: savedContact2.id }, + const fromDb2: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: savedParty2.id }, }) expect(fromDb1).toBeDefined() @@ -225,15 +231,15 @@ describe('Database entities tests', (): void => { expect(fromDb2?.relationships.length).toEqual(0) }) - it('should throw error when saving person contact with blank first name', async (): Promise => { - const contact: IBasicContact = { + it('should throw error when saving person party with blank first name', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: '', middleName: 'example_middle_name1', lastName: 'example_last_name1', @@ -241,20 +247,20 @@ describe('Database entities tests', (): void => { }, } - const contactEntity: ContactEntity = contactEntityFrom(contact) + const partyEntity: PartyEntity = partyEntityFrom(party) - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank first names are not allowed') + await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank first names are not allowed') }) - it('should throw error when saving person contact with blank middle name', async (): Promise => { - const contact: IBasicContact = { + it('should throw error when saving person party with blank middle name', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: '', lastName: 'example_last_name', @@ -262,20 +268,20 @@ describe('Database entities tests', (): void => { }, } - const contactEntity: ContactEntity = contactEntityFrom(contact) + const partyEntity: PartyEntity = partyEntityFrom(party) - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank middle names are not allowed') + await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank middle names are not allowed') }) - it('should throw error when saving person contact with blank last name', async (): Promise => { - const contact: IBasicContact = { + it('should throw error when saving person party with blank last name', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: '', @@ -283,20 +289,20 @@ describe('Database entities tests', (): void => { }, } - const contactEntity: ContactEntity = contactEntityFrom(contact) + const partyEntity: PartyEntity = partyEntityFrom(party) - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank last names are not allowed') + await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank last names are not allowed') }) - it('should throw error when saving person contact with blank display name', async (): Promise => { - const contact: IBasicContact = { + it('should throw error when saving person party with blank display name', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', @@ -304,80 +310,58 @@ describe('Database entities tests', (): void => { }, } - const contactEntity: ContactEntity = contactEntityFrom(contact) + const partyEntity: PartyEntity = partyEntityFrom(party) - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank display names are not allowed') + await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank display names are not allowed') }) - it('should throw error when saving organization contact with blank legal name', async (): Promise => { - const contact: IBasicContact = { + it('should throw error when saving organization party with blank legal name', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.ORGANIZATION, + partyType: { + type: PartyTypeEnum.ORGANIZATION, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { legalName: '', displayName: 'example_legal_name', - cocNumber: 'example_coc_number', }, } - const contactEntity: ContactEntity = contactEntityFrom(contact) + const partyEntity: PartyEntity = partyEntityFrom(party) - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank legal names are not allowed') + await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank legal names are not allowed') }) - it('should throw error when saving organization contact with blank display name', async (): Promise => { - const contact: IBasicContact = { + it('should throw error when saving organization party with blank display name', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.ORGANIZATION, + partyType: { + type: PartyTypeEnum.ORGANIZATION, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { legalName: 'example_first_name', displayName: '', - cocNumber: 'example_coc_number', }, } - const contactEntity: ContactEntity = contactEntityFrom(contact) + const partyEntity: PartyEntity = partyEntityFrom(party) - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank display names are not allowed') + await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank display names are not allowed') }) - it('should throw error when saving organization contact with blank coc number', async (): Promise => { - const contact: IBasicContact = { + it('should throw error when saving party with blank party type name', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.ORGANIZATION, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - legalName: 'example_first_name', - displayName: 'example_display_name', - cocNumber: '', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank coc numbers are not allowed') - }) - - it('should throw error when saving contact with blank contact type name', async (): Promise => { - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: '', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', @@ -385,21 +369,21 @@ describe('Database entities tests', (): void => { }, } - const contactEntity: ContactEntity = contactEntityFrom(contact) + const partyEntity: PartyEntity = partyEntityFrom(party) - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank names are not allowed') + await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank names are not allowed') }) - it('should throw error when saving contact with blank contact type description', async (): Promise => { - const contact: IBasicContact = { + it('should throw error when saving party with blank party type description', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', description: '', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', @@ -407,20 +391,20 @@ describe('Database entities tests', (): void => { }, } - const contactEntity: ContactEntity = contactEntityFrom(contact) + const partyEntity: PartyEntity = partyEntityFrom(party) - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError('Blank descriptions are not allowed') + await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank descriptions are not allowed') }) - it('should throw error when saving contact with blank contact type tenant id', async (): Promise => { - const contact: IBasicContact = { + it('should throw error when saving party with blank party type tenant id', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', @@ -428,92 +412,14 @@ describe('Database entities tests', (): void => { }, } - const contactEntity: ContactEntity = contactEntityFrom(contact) - - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity)).rejects.toThrowError("Blank tenant id's are not allowed") - }) - - it('Should enforce unique display name for a person contact', async (): Promise => { - const contactDisplayName = 'non_unique_name' - const contact1: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - name: 'example_name', - }, - contactOwner: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: contactDisplayName, - }, - } - const contact1Entity: ContactEntity = contactEntityFrom(contact1) - await dbConnection.getRepository(ContactEntity).save(contact1Entity) - - const contact2: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: contactDisplayName, - }, - } - const contact2Entity: ContactEntity = contactEntityFrom(contact2) - - await expect(dbConnection.getRepository(ContactEntity).save(contact2Entity)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactType.name' - ) - }) - - it('Should enforce unique display name for a organization contact', async (): Promise => { - const contactDisplayName = 'non_unique_name' - const contact1: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.ORGANIZATION, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - name: 'example_name', - }, - contactOwner: { - legalName: 'example_first_name', - displayName: contactDisplayName, - cocNumber: 'example_coc_number', - }, - } - const contact1Entity: ContactEntity = contactEntityFrom(contact1) - await dbConnection.getRepository(ContactEntity).save(contact1Entity) - - const contact2: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.ORGANIZATION, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - legalName: 'example_first_name', - displayName: contactDisplayName, - cocNumber: 'example_coc_number', - }, - } - const contact2Entity: ContactEntity = contactEntityFrom(contact2) + const partyEntity: PartyEntity = partyEntityFrom(party) - await expect(dbConnection.getRepository(ContactEntity).save(contact2Entity)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactType.name' - ) + await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError("Blank tenant id's are not allowed") }) it('Should enforce unique alias for an identity', async (): Promise => { const alias = 'non_unique_alias' - const identity1: IBasicIdentity = { + const identity1: NonPersistedIdentity = { alias, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -524,7 +430,7 @@ describe('Database entities tests', (): void => { const identity1Entity: IdentityEntity = identityEntityFrom(identity1) await dbConnection.getRepository(IdentityEntity).save(identity1Entity) - const identity2: IBasicIdentity = { + const identity2: NonPersistedIdentity = { alias: alias, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -540,7 +446,7 @@ describe('Database entities tests', (): void => { it('Should enforce unique correlationId for a identity', async (): Promise => { const correlationId = 'non_unique_correlationId' - const identity1: IBasicIdentity = { + const identity1: NonPersistedIdentity = { alias: 'unique_alias1', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -551,7 +457,7 @@ describe('Database entities tests', (): void => { const identity1Entity: IdentityEntity = identityEntityFrom(identity1) await dbConnection.getRepository(IdentityEntity).save(identity1Entity) - const identity2: IBasicIdentity = { + const identity2: NonPersistedIdentity = { alias: 'unique_alias2', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -567,7 +473,7 @@ describe('Database entities tests', (): void => { it('Should save identity to database', async (): Promise => { const correlationId = 'example_did' - const identity: IBasicIdentity = { + const identity: NonPersistedIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -596,7 +502,7 @@ describe('Database entities tests', (): void => { }) it('should throw error when saving identity with blank alias', async (): Promise => { - const identity: IBasicIdentity = { + const identity: NonPersistedIdentity = { alias: '', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -611,7 +517,7 @@ describe('Database entities tests', (): void => { }) it('should throw error when saving identity with blank correlation id', async (): Promise => { - const identity: IBasicIdentity = { + const identity: NonPersistedIdentity = { alias: 'example_did', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -627,7 +533,7 @@ describe('Database entities tests', (): void => { it('should throw error when saving identity with blank metadata label', async (): Promise => { const correlationId = 'example_did' - const identity: IBasicIdentity = { + const identity: NonPersistedIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -649,7 +555,7 @@ describe('Database entities tests', (): void => { it('should throw error when saving identity with blank metadata value', async (): Promise => { const correlationId = 'example_did' - const identity: IBasicIdentity = { + const identity: NonPersistedIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -671,7 +577,7 @@ describe('Database entities tests', (): void => { it('Should save identity with openid connection to database', async (): Promise => { const correlationId = 'example.com' - const identity: IBasicIdentity = { + const identity: NonPersistedIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -711,12 +617,12 @@ describe('Database entities tests', (): void => { expect(fromDb?.identifier.type).toEqual(identity.identifier.type) expect(fromDb?.connection?.type).toEqual(identity.connection?.type) expect(fromDb?.connection?.config).toBeDefined() - expect((fromDb?.connection?.config).clientId).toEqual((identity.connection?.config).clientId) + expect((fromDb?.connection?.config).clientId).toEqual((identity.connection?.config).clientId) }) it('Should save identity with didauth connection to database', async (): Promise => { const correlationId = 'example.com' - const identity: IBasicIdentity = { + const identity: NonPersistedIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -758,11 +664,13 @@ describe('Database entities tests', (): void => { expect(fromDb?.identifier.type).toEqual(identity.identifier.type) expect(fromDb?.connection?.type).toEqual(identity.connection?.type) expect(fromDb?.connection?.config).toBeDefined() - expect((fromDb?.connection?.config).identifier).toEqual((identity.connection?.config).identifier.did) + expect((fromDb?.connection?.config).identifier).toEqual( + (identity.connection?.config).identifier.did + ) }) it('Should save connection with openid config to database', async (): Promise => { - const connection: IBasicConnection = { + const connection: NonPersistedConnection = { type: ConnectionTypeEnum.OPENID_CONNECT, config: { clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', @@ -792,11 +700,11 @@ describe('Database entities tests', (): void => { expect(fromDbConfig).toBeDefined() expect(fromDb?.type).toEqual(connection.type) expect(fromDb?.config).toBeDefined() - expect((fromDb?.config).clientId).toEqual((connection.config).clientId) + expect((fromDb?.config).clientId).toEqual((connection.config).clientId) }) it('Should save connection with didauth config to database', async (): Promise => { - const connection: IBasicConnection = { + const connection: NonPersistedConnection = { type: ConnectionTypeEnum.SIOPv2, config: { identifier: { @@ -828,12 +736,12 @@ describe('Database entities tests', (): void => { expect(fromDbConfig).toBeDefined() expect(fromDb?.type).toEqual(connection.type) expect(fromDb?.config).toBeDefined() - expect((fromDb?.config).identifier).toEqual((connection.config).identifier.did) + expect((fromDb?.config).identifier).toEqual((connection.config).identifier.did) }) it('Should save openid config to database', async (): Promise => { const clientId = '138d7bf8-c930-4c6e-b928-97d3a4928b01' - const config: BasicOpenIdConfig = { + const config: NonPersistedOpenIdConfig = { clientId, clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', scopes: ['auth'], @@ -858,7 +766,7 @@ describe('Database entities tests', (): void => { it('Should save didauth config to database', async (): Promise => { const sessionId = 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01' - const config: BasicDidAuthConfig = { + const config: NonPersistedDidAuthConfig = { identifier: { did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', provider: 'test_provider', @@ -883,15 +791,15 @@ describe('Database entities tests', (): void => { expect((fromDb).identifier).toEqual(config.identifier.did) }) - it('Should delete contact and all child relations', async (): Promise => { - const contact1: IBasicContact = { + it('Should delete party and all child relations', async (): Promise => { + const party1: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name1', }, - contactOwner: { + contact: { firstName: 'example_first_name1', middleName: 'example_middle_name1', lastName: 'example_last_name1', @@ -899,19 +807,19 @@ describe('Database entities tests', (): void => { }, } - const contactEntity1: ContactEntity = contactEntityFrom(contact1) - const savedContact1: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity1) + const partyEntity1: PartyEntity = partyEntityFrom(party1) + const savedParty1: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity1) - expect(savedContact1).toBeDefined() + expect(savedParty1).toBeDefined() - const contact2: IBasicContact = { + const party2: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'example_name2', }, - contactOwner: { + contact: { firstName: 'example_first_name2', middleName: 'example_middle_name2', lastName: 'example_last_name2', @@ -919,13 +827,13 @@ describe('Database entities tests', (): void => { }, } - const contactEntity2: ContactEntity = contactEntityFrom(contact2) - const savedContact2: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity2) + const partyEntity2: PartyEntity = partyEntityFrom(party2) + const savedParty2: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity2) - expect(savedContact2).toBeDefined() + expect(savedParty2).toBeDefined() const correlationId = 'relation_example.com' - const identity: IBasicIdentity = { + const identity: NonPersistedIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -953,42 +861,42 @@ describe('Database entities tests', (): void => { } const identityEntity: IdentityEntity = identityEntityFrom(identity) - identityEntity.contact = savedContact1 + identityEntity.party = savedParty1 const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) expect(savedIdentity).toBeDefined() - const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ - leftId: savedContact1.id, - rightId: savedContact2.id, + const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ + leftId: savedParty1.id, + rightId: savedParty2.id, }) - const savedRelationship: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { + const savedRelationship: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { transaction: true, }) expect(savedRelationship).toBeDefined() expect( - await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: savedContact1.id }, + await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: savedParty1.id }, }) ).toBeDefined() - await dbConnection.getRepository(ContactEntity).delete({ id: savedContact1.id }) + await dbConnection.getRepository(PartyEntity).delete({ id: savedParty1.id }) - // check contact + // check party await expect( - await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: savedContact1.id }, + await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: savedParty1.id }, }) ).toBeNull() // check identity expect( await dbConnection.getRepository(IdentityEntity).findOne({ - where: { id: savedContact1.id }, + where: { id: savedParty1.id }, }) ).toBeNull() @@ -1020,37 +928,37 @@ describe('Database entities tests', (): void => { }) ).toBeNull() - // check contact owner + // check contact expect( - await dbConnection.getRepository(ContactOwnerEntity).findOne({ - where: { id: savedContact1.contactOwner.id }, + await dbConnection.getRepository(BaseContactEntity).findOne({ + where: { id: savedParty1.contact.id }, }) ).toBeNull() - // check contact type + // check party type expect( - await dbConnection.getRepository(ContactTypeEntity).findOne({ - where: { id: savedContact1.contactType.id }, + await dbConnection.getRepository(PartyTypeEntity).findOne({ + where: { id: savedParty1.partyType.id }, }) ).toBeDefined() // check relation expect( - await dbConnection.getRepository(ContactRelationshipEntity).findOne({ + await dbConnection.getRepository(PartyRelationshipEntity).findOne({ where: { id: savedRelationship.id }, }) ).toBeNull() }) it('Should delete identity and all child relations', async (): Promise => { - const contact: IBasicContact = { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', @@ -1058,13 +966,13 @@ describe('Database entities tests', (): void => { }, } - const contactEntity: ContactEntity = contactEntityFrom(contact) - const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) + const partyEntity: PartyEntity = partyEntityFrom(party) + const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) - expect(savedContact).toBeDefined() + expect(savedParty).toBeDefined() const correlationId = 'relation_example.com' - const identity: IBasicIdentity = { + const identity: NonPersistedIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -1094,13 +1002,13 @@ describe('Database entities tests', (): void => { } const identityEntity: IdentityEntity = identityEntityFrom(identity) - identityEntity.contact = savedContact + identityEntity.party = savedParty const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) expect( - await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: savedContact.id }, + await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: savedParty.id }, }) ).toBeDefined() @@ -1142,15 +1050,15 @@ describe('Database entities tests', (): void => { ).toBeNull() }) - it('Should not delete contact when deleting identity', async (): Promise => { - const contact: IBasicContact = { + it('Should not delete party when deleting identity', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', @@ -1158,13 +1066,13 @@ describe('Database entities tests', (): void => { }, } - const contactEntity: ContactEntity = contactEntityFrom(contact) - const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) + const partyEntity: PartyEntity = partyEntityFrom(party) + const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) - expect(savedContact).toBeDefined() + expect(savedParty).toBeDefined() const correlationId = 'relation_example.com' - const identity: IBasicIdentity = { + const identity: NonPersistedIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -1194,7 +1102,7 @@ describe('Database entities tests', (): void => { } const identityEntity: IdentityEntity = identityEntityFrom(identity) - identityEntity.contact = savedContact + identityEntity.party = savedParty const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) @@ -1209,23 +1117,23 @@ describe('Database entities tests', (): void => { }) ).toBeNull() - // check contact + // check party expect( - await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: savedContact.id }, + await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: savedParty.id }, }) ).toBeDefined() }) - it('Should set creation date when saving contact', async (): Promise => { - const contact: IBasicContact = { + it('Should set creation date when saving party', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', @@ -1233,26 +1141,26 @@ describe('Database entities tests', (): void => { }, } - const contactEntity: ContactEntity = contactEntityFrom(contact) - const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) + const partyEntity: PartyEntity = partyEntityFrom(party) + const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) - const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: savedContact.id }, + const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: savedParty.id }, }) expect(fromDb).toBeDefined() expect(fromDb?.createdAt).toBeDefined() }) - it('Should not update creation date when updating contact', async (): Promise => { - const contact: IBasicContact = { + it('Should not update creation date when updating party', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', @@ -1260,32 +1168,32 @@ describe('Database entities tests', (): void => { }, } - const contactEntity: ContactEntity = contactEntityFrom(contact) - const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) + const partyEntity: PartyEntity = partyEntityFrom(party) + const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) - expect(savedContact).toBeDefined() + expect(savedParty).toBeDefined() const newContactFirstName = 'new_first_name' - await dbConnection.getRepository(ContactEntity).save({ - ...savedContact, - contactOwner: { - ...savedContact.contactOwner, + await dbConnection.getRepository(PartyEntity).save({ + ...savedParty, + contact: { + ...savedParty.contact, firstName: newContactFirstName, }, }) - const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: savedContact.id }, + const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: savedParty.id }, }) expect(fromDb).toBeDefined() - expect((fromDb?.contactOwner).firstName).toEqual(newContactFirstName) - expect(fromDb?.createdAt).toEqual(savedContact?.createdAt) + expect((fromDb?.contact).firstName).toEqual(newContactFirstName) + expect(fromDb?.createdAt).toEqual(savedParty?.createdAt) }) it('Should set creation date when saving identity', async (): Promise => { const correlationId = 'example_did' - const identity: IBasicIdentity = { + const identity: NonPersistedIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -1311,7 +1219,7 @@ describe('Database entities tests', (): void => { it('Should not update creation date when saving identity', async (): Promise => { const correlationId = 'example_did' - const identity: IBasicIdentity = { + const identity: NonPersistedIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -1339,15 +1247,15 @@ describe('Database entities tests', (): void => { expect(fromDb?.createdAt).toEqual(savedIdentity?.createdAt) }) - it('Should set last updated date when saving contact', async (): Promise => { - const contact: IBasicContact = { + it('Should set last updated date when saving party', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', @@ -1355,26 +1263,26 @@ describe('Database entities tests', (): void => { }, } - const contactEntity: ContactEntity = contactEntityFrom(contact) - const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) + const partyEntity: PartyEntity = partyEntityFrom(party) + const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) - const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: savedContact.id }, + const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: savedParty.id }, }) expect(fromDb).toBeDefined() expect(fromDb?.lastUpdatedAt).toBeDefined() }) - it('Should update last updated date when updating contact', async (): Promise => { - const contact: IBasicContact = { + it('Should update last updated date when updating party', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', @@ -1382,64 +1290,64 @@ describe('Database entities tests', (): void => { }, } - const contactEntity: ContactEntity = contactEntityFrom(contact) - const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity) - expect(savedContact).toBeDefined() + const partyEntity: PartyEntity = partyEntityFrom(party) + const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) + expect(savedParty).toBeDefined() // waiting here to get a different timestamp await new Promise((resolve) => setTimeout(resolve, 2000)) const newContactFirstName = 'new_first_name' - await dbConnection.getRepository(ContactEntity).save({ - ...savedContact, + await dbConnection.getRepository(PartyEntity).save({ + ...savedParty, // FIXME there is still an issue when updating nested objects, the parent does not update // https://github.com/typeorm/typeorm/issues/5378 uri: 'new uri', // TODO remove this to trigger the bug - contactOwner: { - ...savedContact.contactOwner, + contact: { + ...savedParty.contact, firstName: newContactFirstName, }, }) - const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: savedContact.id }, + const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: savedParty.id }, }) expect(fromDb).toBeDefined() - expect((fromDb?.contactOwner).firstName).toEqual(newContactFirstName) - expect(fromDb?.lastUpdatedAt).not.toEqual(savedContact?.lastUpdatedAt) + expect((fromDb?.contact).firstName).toEqual(newContactFirstName) + expect(fromDb?.lastUpdatedAt).not.toEqual(savedParty?.lastUpdatedAt) }) - it('Should set last updated date when saving contact type', async (): Promise => { - const contactType: BasicContactType = { - type: ContactTypeEnum.PERSON, + it('Should set last updated date when saving party type', async (): Promise => { + const partyType: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', } - const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) - const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) + const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) + const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) - const fromDb: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).findOne({ - where: { id: savedContactType.id }, + const fromDb: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).findOne({ + where: { id: savedPartyType.id }, }) expect(fromDb).toBeDefined() expect(fromDb?.lastUpdatedAt).toBeDefined() }) - it('Should set last creation date when saving contact type', async (): Promise => { - const contactType: BasicContactType = { - type: ContactTypeEnum.PERSON, + it('Should set last creation date when saving party type', async (): Promise => { + const partyType: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', } - const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) - const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) + const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) + const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) - const fromDb: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).findOne({ - where: { id: savedContactType.id }, + const fromDb: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).findOne({ + where: { id: savedPartyType.id }, }) expect(fromDb).toBeDefined() @@ -1448,7 +1356,7 @@ describe('Database entities tests', (): void => { it('Should set last updated date when saving identity', async (): Promise => { const correlationId = 'example_did' - const identity: IBasicIdentity = { + const identity: NonPersistedIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -1472,60 +1380,60 @@ describe('Database entities tests', (): void => { expect(fromDb?.lastUpdatedAt).toBeDefined() }) - it('Should enforce unique type and tenant id combination when saving contact type', async (): Promise => { + it('Should enforce unique type and tenant id combination when saving party type', async (): Promise => { const tenantId = 'non_unique_value' const name = 'non_unique_value' - const contactType1: BasicContactType = { - type: ContactTypeEnum.PERSON, + const partyType1: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, tenantId, name, } - const contactTypeEntity1: ContactTypeEntity = contactTypeEntityFrom(contactType1) - const savedContactType1: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity1) + const partyTypeEntity1: PartyTypeEntity = partyTypeEntityFrom(partyType1) + const savedPartyType1: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity1) - expect(savedContactType1).toBeDefined() + expect(savedPartyType1).toBeDefined() - const contactType2: BasicContactType = { - type: ContactTypeEnum.PERSON, + const partyType2: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, tenantId, name, } - const contactTypeEntity2: ContactTypeEntity = contactTypeEntityFrom(contactType2) - await expect(dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity2)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactType.type, ContactType.tenantId' + const partyTypeEntity2: PartyTypeEntity = partyTypeEntityFrom(partyType2) + await expect(dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity2)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: PartyType.type, PartyType.tenant_id' ) }) - it('Should enforce unique name when saving contact type', async (): Promise => { + it('Should enforce unique name when saving party type', async (): Promise => { const name = 'non_unique_value' - const contactType1: BasicContactType = { - type: ContactTypeEnum.PERSON, + const partyType1: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name, } - const contactTypeEntity1: ContactTypeEntity = contactTypeEntityFrom(contactType1) - const savedContactType1: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity1) + const partyTypeEntity1: PartyTypeEntity = partyTypeEntityFrom(partyType1) + const savedPartyType1: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity1) - expect(savedContactType1).toBeDefined() + expect(savedPartyType1).toBeDefined() - const contactType2: BasicContactType = { - type: ContactTypeEnum.PERSON, + const partyType2: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name, } - const contactTypeEntity2: ContactTypeEntity = contactTypeEntityFrom(contactType2) - await expect(dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity2)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactType.name' + const partyTypeEntity2: PartyTypeEntity = partyTypeEntityFrom(partyType2) + await expect(dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity2)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: PartyType.name' ) }) it('Should enforce unique legal name when saving organization', async (): Promise => { const legalName = 'non_unique_value' - const organization1: BasicOrganization = { + const organization1: NonPersistedOrganization = { legalName, displayName: 'example_display_name', } @@ -1537,45 +1445,20 @@ describe('Database entities tests', (): void => { expect(savedOrganization1).toBeDefined() - const organization2: BasicOrganization = { + const organization2: NonPersistedOrganization = { legalName, displayName: 'example_display_name', } const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.legalName' - ) - }) - - it('Should enforce unique display name when saving organization', async (): Promise => { - const displayName = 'non_unique_value' - const organization1: BasicOrganization = { - legalName: 'example_legal_name1', - displayName, - } - - const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) - const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { - transaction: true, - }) - - expect(savedOrganization1).toBeDefined() - - const organization2: BasicOrganization = { - legalName: 'example_legal_name2', - displayName, - } - - const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) - await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.displayName' + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: BaseContact.legal_name' ) }) it('Should enforce unique legal name when saving organization', async (): Promise => { const legalName = 'example_legal_name' - const organization1: BasicOrganization = { + const organization1: NonPersistedOrganization = { legalName, displayName: 'example_display_name', } @@ -1587,93 +1470,26 @@ describe('Database entities tests', (): void => { expect(savedOrganization1).toBeDefined() - const organization2: BasicOrganization = { + const organization2: NonPersistedOrganization = { legalName, displayName: 'example_display_name', } const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.legalName' + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: BaseContact.legal_name' ) }) - it('Should enforce unique coc number when saving organization per tenant id', async (): Promise => { - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.ORGANIZATION, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contactOwner: { - legalName: 'example_legal_name', - displayName: 'example_display_name', - cocNumber: 'example_coc_number', - }, - } - - const contactEntity: ContactEntity = contactEntityFrom(contact) - await dbConnection.getRepository(ContactEntity).save(contactEntity, { - transaction: true, - }) - - const contact2: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name2', - }, - contactOwner: { - legalName: 'example_legal_name2', - displayName: 'example_display_name2', - cocNumber: 'example_coc_number', - }, - } - - const contactEntity2: ContactEntity = contactEntityFrom(contact2) - await expect(dbConnection.getRepository(ContactEntity).save(contactEntity2, { transaction: true })).rejects.toThrowError( - 'Coc number already in use' - ) - }) - - it('Should enforce unique display name when saving person', async (): Promise => { - const displayName = 'non_unique_value' - const person1: BasicPerson = { - firstName: 'example_first_name1', - lastName: 'lastName2', - displayName, - } - - const personEntity1: PersonEntity = personEntityFrom(person1) - const savedPerson1: PersonEntity | null = await dbConnection.getRepository(PersonEntity).save(personEntity1, { - transaction: true, - }) - - expect(savedPerson1).toBeDefined() - - const person2: BasicPerson = { - firstName: 'example_first_name2', - lastName: 'lastName2', - displayName, - } - - const personEntity2: PersonEntity = personEntityFrom(person2) - await expect(dbConnection.getRepository(PersonEntity).save(personEntity2)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactOwner.displayName' - ) - }) - - it('Should save contact relationship to database', async (): Promise => { - const contact1: IBasicContact = { + it('Should save party relationship to database', async (): Promise => { + const party1: NonPersistedParty = { uri: 'example1.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name1', }, - contactOwner: { + contact: { firstName: 'example_first_name1', middleName: 'example_middle_name1', lastName: 'example_last_name1', @@ -1681,21 +1497,21 @@ describe('Database entities tests', (): void => { }, } - const contactEntity1: ContactEntity = contactEntityFrom(contact1) - const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + const partyEntity1: PartyEntity = partyEntityFrom(party1) + const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { transaction: true, }) - expect(savedContact1).toBeDefined() + expect(savedParty1).toBeDefined() - const contact2: IBasicContact = { + const party2: NonPersistedParty = { uri: 'example2.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'example_name2', }, - contactOwner: { + contact: { firstName: 'example_first_name2', middleName: 'example_middle_name2', lastName: 'example_last_name2', @@ -1703,39 +1519,39 @@ describe('Database entities tests', (): void => { }, } - const contactEntity2: ContactEntity = contactEntityFrom(contact2) - const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + const partyEntity2: PartyEntity = partyEntityFrom(party2) + const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { transaction: true, }) - expect(savedContact2).toBeDefined() + expect(savedParty2).toBeDefined() - const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ - leftId: savedContact1.id, - rightId: savedContact2.id, + const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ + leftId: savedParty1.id, + rightId: savedParty2.id, }) - await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { + await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { transaction: true, }) // TODO check the relation field - const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: contactEntity1.id }, + const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: partyEntity1.id }, }) expect(fromDb).toBeDefined() }) - it('Should set last updated date when saving contact relationship', async (): Promise => { - const contact1: IBasicContact = { + it('Should set last updated date when saving party relationship', async (): Promise => { + const party1: NonPersistedParty = { uri: 'example1.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name1', }, - contactOwner: { + contact: { firstName: 'example_first_name1', middleName: 'example_middle_name1', lastName: 'example_last_name1', @@ -1743,19 +1559,19 @@ describe('Database entities tests', (): void => { }, } - const contactEntity1: ContactEntity = contactEntityFrom(contact1) - const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + const partyEntity1: PartyEntity = partyEntityFrom(party1) + const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { transaction: true, }) - const contact2: IBasicContact = { + const party2: NonPersistedParty = { uri: 'example2.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'example_name2', }, - contactOwner: { + contact: { firstName: 'example_first_name2', middleName: 'example_middle_name2', lastName: 'example_last_name2', @@ -1763,37 +1579,37 @@ describe('Database entities tests', (): void => { }, } - const contactEntity2: ContactEntity = contactEntityFrom(contact2) - const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + const partyEntity2: PartyEntity = partyEntityFrom(party2) + const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { transaction: true, }) - const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ - leftId: savedContact1.id, - rightId: savedContact2.id, + const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ + leftId: savedParty1.id, + rightId: savedParty2.id, }) - await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { + await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { transaction: true, }) - const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: contactEntity1.id }, + const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: partyEntity1.id }, }) expect(fromDb).toBeDefined() expect(fromDb?.lastUpdatedAt).toBeDefined() }) - it('Should set creation date when saving contact relationship', async (): Promise => { - const contact1: IBasicContact = { + it('Should set creation date when saving party relationship', async (): Promise => { + const party1: NonPersistedParty = { uri: 'example1.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name1', }, - contactOwner: { + contact: { firstName: 'example_first_name1', middleName: 'example_middle_name1', lastName: 'example_last_name1', @@ -1801,19 +1617,19 @@ describe('Database entities tests', (): void => { }, } - const contactEntity1: ContactEntity = contactEntityFrom(contact1) - const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + const partyEntity1: PartyEntity = partyEntityFrom(party1) + const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { transaction: true, }) - const contact2: IBasicContact = { + const party2: NonPersistedParty = { uri: 'example2.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'example_name2', }, - contactOwner: { + contact: { firstName: 'example_first_name2', middleName: 'example_middle_name2', lastName: 'example_last_name2', @@ -1821,37 +1637,37 @@ describe('Database entities tests', (): void => { }, } - const contactEntity2: ContactEntity = contactEntityFrom(contact2) - const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + const partyEntity2: PartyEntity = partyEntityFrom(party2) + const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { transaction: true, }) - const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ - leftId: savedContact1.id, - rightId: savedContact2.id, + const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ + leftId: savedParty1.id, + rightId: savedParty2.id, }) - await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { + await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { transaction: true, }) - const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: contactEntity1.id }, + const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: partyEntity1.id }, }) expect(fromDb).toBeDefined() expect(fromDb?.createdAt).toBeDefined() }) - it('Should save bidirectional contact relationships to database', async (): Promise => { - const contact1: IBasicContact = { + it('Should save bidirectional party relationships to database', async (): Promise => { + const party1: NonPersistedParty = { uri: 'example1.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name1', }, - contactOwner: { + contact: { firstName: 'example_first_name1', middleName: 'example_middle_name1', lastName: 'example_last_name1', @@ -1859,21 +1675,21 @@ describe('Database entities tests', (): void => { }, } - const contactEntity1: ContactEntity = contactEntityFrom(contact1) - const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + const partyEntity1: PartyEntity = partyEntityFrom(party1) + const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { transaction: true, }) - expect(savedContact1).toBeDefined() + expect(savedParty1).toBeDefined() - const contact2: IBasicContact = { + const party2: NonPersistedParty = { uri: 'example2.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'example_name2', }, - contactOwner: { + contact: { firstName: 'example_first_name2', middleName: 'example_middle_name2', lastName: 'example_last_name2', @@ -1881,51 +1697,51 @@ describe('Database entities tests', (): void => { }, } - const contactEntity2: ContactEntity = contactEntityFrom(contact2) - const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + const partyEntity2: PartyEntity = partyEntityFrom(party2) + const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { transaction: true, }) - expect(savedContact2).toBeDefined() + expect(savedParty2).toBeDefined() - const relationship1: ContactRelationshipEntity = contactRelationshipEntityFrom({ - leftId: savedContact1.id, - rightId: savedContact2.id, + const relationship1: PartyRelationshipEntity = partyRelationshipEntityFrom({ + leftId: savedParty1.id, + rightId: savedParty2.id, }) - const savedRelationship1: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship1, { + const savedRelationship1: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship1, { transaction: true, }) expect(savedRelationship1).toBeDefined() - const relationship2: ContactRelationshipEntity = contactRelationshipEntityFrom({ - leftId: savedContact2.id, - rightId: savedContact1.id, + const relationship2: PartyRelationshipEntity = partyRelationshipEntityFrom({ + leftId: savedParty2.id, + rightId: savedParty1.id, }) - const savedRelationship2: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship2, { + const savedRelationship2: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship2, { transaction: true, }) expect(savedRelationship2).toBeDefined() - const fromDb: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).findOne({ + const fromDb: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).findOne({ where: { id: savedRelationship2.id }, }) expect(fromDb).toBeDefined() }) - it('Should enforce unique owner combination for contact relationship', async (): Promise => { - const contact1: IBasicContact = { + it('Should enforce unique owner combination for party relationship', async (): Promise => { + const party1: NonPersistedParty = { uri: 'example1.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name1', }, - contactOwner: { + contact: { firstName: 'example_first_name1', middleName: 'example_middle_name1', lastName: 'example_last_name1', @@ -1933,21 +1749,21 @@ describe('Database entities tests', (): void => { }, } - const contactEntity1: ContactEntity = contactEntityFrom(contact1) - const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + const partyEntity1: PartyEntity = partyEntityFrom(party1) + const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { transaction: true, }) - expect(savedContact1).toBeDefined() + expect(savedParty1).toBeDefined() - const contact2: IBasicContact = { + const party2: NonPersistedParty = { uri: 'example2.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'example_name2', }, - contactOwner: { + contact: { firstName: 'example_first_name2', middleName: 'example_middle_name2', lastName: 'example_last_name2', @@ -1955,64 +1771,64 @@ describe('Database entities tests', (): void => { }, } - const contactEntity2: ContactEntity = contactEntityFrom(contact2) - const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + const partyEntity2: PartyEntity = partyEntityFrom(party2) + const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { transaction: true, }) - expect(savedContact2).toBeDefined() + expect(savedParty2).toBeDefined() - const relationship1: ContactRelationshipEntity = contactRelationshipEntityFrom({ - leftId: savedContact1.id, - rightId: savedContact2.id, + const relationship1: PartyRelationshipEntity = partyRelationshipEntityFrom({ + leftId: savedParty1.id, + rightId: savedParty2.id, }) - const savedRelationship1: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship1, { + const savedRelationship1: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship1, { transaction: true, }) expect(savedRelationship1).toBeDefined() - const relationship2: ContactRelationshipEntity = contactRelationshipEntityFrom({ - leftId: savedContact1.id, - rightId: savedContact2.id, + const relationship2: PartyRelationshipEntity = partyRelationshipEntityFrom({ + leftId: savedParty1.id, + rightId: savedParty2.id, }) - await expect(dbConnection.getRepository(ContactRelationshipEntity).save(relationship2)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: ContactRelationship.leftId, ContactRelationship.rightId' + await expect(dbConnection.getRepository(PartyRelationshipEntity).save(relationship2)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: PartyRelationship.left_id, PartyRelationship.right_id' ) }) - it('Should save contact type to database', async (): Promise => { - const contactType: BasicContactType = { - type: ContactTypeEnum.PERSON, + it('Should save party type to database', async (): Promise => { + const partyType: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', } - const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) - const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) + const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) + const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) - const fromDb: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).findOne({ - where: { id: savedContactType.id }, + const fromDb: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).findOne({ + where: { id: savedPartyType.id }, }) expect(fromDb).toBeDefined() }) it('Should save person to database', async (): Promise => { - const person: BasicPerson = { + const person: NonPersistedNaturalPerson = { firstName: 'example_first_name', lastName: 'lastName2', displayName: 'displayName', } - const personEntity: PersonEntity = personEntityFrom(person) - const savedPerson: PersonEntity | null = await dbConnection.getRepository(PersonEntity).save(personEntity, { + const personEntity: NaturalPersonEntity = naturalPersonEntityFrom(person) + const savedPerson: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).save(personEntity, { transaction: true, }) - const fromDb: PersonEntity | null = await dbConnection.getRepository(PersonEntity).findOne({ + const fromDb: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).findOne({ where: { id: savedPerson.id }, }) @@ -2020,18 +1836,18 @@ describe('Database entities tests', (): void => { }) it('Should set last updated date when saving person', async (): Promise => { - const person: BasicPerson = { + const person: NonPersistedNaturalPerson = { firstName: 'example_first_name', lastName: 'lastName2', displayName: 'displayName', } - const personEntity: PersonEntity = personEntityFrom(person) - const savedPerson: PersonEntity | null = await dbConnection.getRepository(PersonEntity).save(personEntity, { + const personEntity: NaturalPersonEntity = naturalPersonEntityFrom(person) + const savedPerson: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).save(personEntity, { transaction: true, }) - const fromDb: PersonEntity | null = await dbConnection.getRepository(PersonEntity).findOne({ + const fromDb: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).findOne({ where: { id: savedPerson.id }, }) @@ -2040,18 +1856,18 @@ describe('Database entities tests', (): void => { }) it('Should set creation date when saving person', async (): Promise => { - const person: BasicPerson = { + const person: NonPersistedNaturalPerson = { firstName: 'example_first_name', lastName: 'lastName2', displayName: 'displayName', } - const personEntity: PersonEntity = personEntityFrom(person) - const savedPerson: PersonEntity | null = await dbConnection.getRepository(PersonEntity).save(personEntity, { + const personEntity: NaturalPersonEntity = naturalPersonEntityFrom(person) + const savedPerson: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).save(personEntity, { transaction: true, }) - const fromDb: PersonEntity | null = await dbConnection.getRepository(PersonEntity).findOne({ + const fromDb: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).findOne({ where: { id: savedPerson.id }, }) @@ -2060,7 +1876,7 @@ describe('Database entities tests', (): void => { }) it('Should save organization to database', async (): Promise => { - const organization: BasicOrganization = { + const organization: NonPersistedOrganization = { legalName: 'example_legal_name', displayName: 'example_display_name', } @@ -2078,7 +1894,7 @@ describe('Database entities tests', (): void => { }) it('Should set last updated date when saving organization', async (): Promise => { - const organization: BasicOrganization = { + const organization: NonPersistedOrganization = { legalName: 'example_legal_name', displayName: 'example_display_name', } @@ -2097,7 +1913,7 @@ describe('Database entities tests', (): void => { }) it('Should set creation date when saving organization', async (): Promise => { - const organization: BasicOrganization = { + const organization: NonPersistedOrganization = { legalName: 'example_legal_name', displayName: 'example_display_name', } @@ -2115,16 +1931,16 @@ describe('Database entities tests', (): void => { expect(fromDb?.createdAt).toBeDefined() }) - it('Should get contact based on person information', async (): Promise => { + it('Should get party based on person information', async (): Promise => { const firstName = 'example_first_name' - const contact: IBasicContact = { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName, middleName: 'example_middle_name', lastName: 'example_last_name', @@ -2132,63 +1948,62 @@ describe('Database entities tests', (): void => { }, } - const contactEntity: ContactEntity = contactEntityFrom(contact) - await dbConnection.getRepository(ContactEntity).save(contactEntity, { + const partyEntity: PartyEntity = partyEntityFrom(party) + await dbConnection.getRepository(PartyEntity).save(partyEntity, { transaction: true, }) - const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ where: { - contactOwner: { + contact: { firstName, - } as FindOptionsWhere, + } as FindOptionsWhere, //NaturalPersonEntity | OrganizationEntity }, }) expect(fromDb).toBeDefined() }) - it('Should get contact based on organization information', async (): Promise => { + it('Should get party based on organization information', async (): Promise => { const legalName = 'example_legal_name' - const contact: IBasicContact = { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.ORGANIZATION, + partyType: { + type: PartyTypeEnum.ORGANIZATION, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { legalName, displayName: 'example_display_name', - cocNumber: 'example_coc_number', }, } - const contactEntity: ContactEntity = contactEntityFrom(contact) - await dbConnection.getRepository(ContactEntity).save(contactEntity, { + const partyEntity: PartyEntity = partyEntityFrom(party) + await dbConnection.getRepository(PartyEntity).save(partyEntity, { transaction: true, }) - const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ + const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ where: { - contactOwner: { + contact: { legalName, - } as FindOptionsWhere, + } as FindOptionsWhere, //NaturalPersonEntity | OrganizationEntity }, }) expect(fromDb).toBeDefined() }) - it("Should enforce unique contact id's for relationship sides", async (): Promise => { - const contact: IBasicContact = { + it("Should enforce unique party id's for relationship sides", async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', @@ -2196,32 +2011,32 @@ describe('Database entities tests', (): void => { }, } - const contactEntity: ContactEntity = contactEntityFrom(contact) - const savedContact: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity, { + const partyEntity: PartyEntity = partyEntityFrom(party) + const savedParty: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity, { transaction: true, }) - expect(savedContact).toBeDefined() + expect(savedParty).toBeDefined() - const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ - leftId: savedContact.id, - rightId: savedContact.id, + const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ + leftId: savedParty.id, + rightId: savedParty.id, }) - await expect(dbConnection.getRepository(ContactRelationshipEntity).save(relationship)).rejects.toThrowError( + await expect(dbConnection.getRepository(PartyRelationshipEntity).save(relationship)).rejects.toThrowError( 'Cannot use the same id for both sides of the relationship' ) }) - it('Should delete contact relationship', async (): Promise => { - const contact1: IBasicContact = { + it('Should delete party relationship', async (): Promise => { + const party1: NonPersistedParty = { uri: 'example1.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name1', }, - contactOwner: { + contact: { firstName: 'example_first_name1', middleName: 'example_middle_name1', lastName: 'example_last_name1', @@ -2229,21 +2044,21 @@ describe('Database entities tests', (): void => { }, } - const contactEntity1: ContactEntity = contactEntityFrom(contact1) - const savedContact1: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity1, { + const partyEntity1: PartyEntity = partyEntityFrom(party1) + const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { transaction: true, }) - expect(savedContact1).toBeDefined() + expect(savedParty1).toBeDefined() - const contact2: IBasicContact = { + const party2: NonPersistedParty = { uri: 'example2.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'example_name2', }, - contactOwner: { + contact: { firstName: 'example_first_name2', middleName: 'example_middle_name2', lastName: 'example_last_name2', @@ -2251,63 +2066,63 @@ describe('Database entities tests', (): void => { }, } - const contactEntity2: ContactEntity = contactEntityFrom(contact2) - const savedContact2: ContactEntity = await dbConnection.getRepository(ContactEntity).save(contactEntity2, { + const partyEntity2: PartyEntity = partyEntityFrom(party2) + const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { transaction: true, }) - expect(savedContact2).toBeDefined() + expect(savedParty2).toBeDefined() - const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ - leftId: savedContact1.id, - rightId: savedContact2.id, + const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ + leftId: savedParty1.id, + rightId: savedParty2.id, }) - const savedRelationship: ContactRelationshipEntity | null = await dbConnection.getRepository(ContactRelationshipEntity).save(relationship, { + const savedRelationship: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { transaction: true, }) expect(savedRelationship).toBeDefined() - await dbConnection.getRepository(ContactRelationshipEntity).delete({ id: savedRelationship.id }) + await dbConnection.getRepository(PartyRelationshipEntity).delete({ id: savedRelationship.id }) await expect( - await dbConnection.getRepository(ContactRelationshipEntity).findOne({ + await dbConnection.getRepository(PartyRelationshipEntity).findOne({ where: { id: savedRelationship.id }, }) ).toBeNull() }) - it('Should delete contact type', async (): Promise => { - const contactType: BasicContactType = { - type: ContactTypeEnum.PERSON, + it('Should delete party type', async (): Promise => { + const partyType: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', } - const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) - const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) + const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) + const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) - expect(savedContactType).toBeDefined() + expect(savedPartyType).toBeDefined() - await dbConnection.getRepository(ContactTypeEntity).delete({ id: savedContactType.id }) + await dbConnection.getRepository(PartyTypeEntity).delete({ id: savedPartyType.id }) await expect( - await dbConnection.getRepository(ContactTypeEntity).findOne({ - where: { id: savedContactType.id }, + await dbConnection.getRepository(PartyTypeEntity).findOne({ + where: { id: savedPartyType.id }, }) ).toBeNull() }) - it('Should not be able to remove contact type when used by contacts', async (): Promise => { - const contact: IBasicContact = { + it('Should not be able to remove party type when used by parties', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', @@ -2315,32 +2130,32 @@ describe('Database entities tests', (): void => { }, } - const contactEntity: ContactEntity = contactEntityFrom(contact) - const savedContact: ContactEntity | null = await dbConnection.getRepository(ContactEntity).save(contactEntity, { + const partyEntity: PartyEntity = partyEntityFrom(party) + const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity, { transaction: true, }) - expect(savedContact).toBeDefined() + expect(savedParty).toBeDefined() - await expect(dbConnection.getRepository(ContactTypeEntity).delete({ id: savedContact.contactType.id })).rejects.toThrowError( + await expect(dbConnection.getRepository(PartyTypeEntity).delete({ id: savedParty.partyType.id })).rejects.toThrowError( 'FOREIGN KEY constraint failed' ) }) - it('Should save contact with existing contact type', async (): Promise => { - const contactType: BasicContactType = { - type: ContactTypeEnum.PERSON, + it('Should save party with existing party type', async (): Promise => { + const partyType: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', } - const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) - const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) + const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) + const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) - const contact: IBasicContact = { + const party: NonPersistedParty = { uri: 'example.com', - contactType: savedContactType, - contactOwner: { + partyType: savedPartyType, + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', @@ -2348,45 +2163,42 @@ describe('Database entities tests', (): void => { }, } - const contactEntity: ContactEntity = contactEntityFrom(contact) - contactEntity.contactType = savedContactType - await dbConnection.getRepository(ContactEntity).save(contactEntity, { + const partyEntity: PartyEntity = partyEntityFrom(party) + partyEntity.partyType = savedPartyType + await dbConnection.getRepository(PartyEntity).save(partyEntity, { transaction: true, }) - const fromDb: ContactEntity | null = await dbConnection.getRepository(ContactEntity).findOne({ - where: { id: contactEntity.id }, + const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: partyEntity.id }, }) expect(fromDb).toBeDefined() - expect(fromDb?.contactType).toBeDefined() - expect(fromDb?.contactType.id).toEqual(savedContactType.id) - expect(fromDb?.contactType.type).toEqual(savedContactType.type) - expect(fromDb?.contactType.tenantId).toEqual(savedContactType.tenantId) - expect(fromDb?.contactType.name).toEqual(savedContactType.name) + expect(fromDb?.partyType).toBeDefined() + expect(fromDb?.partyType.id).toEqual(savedPartyType.id) + expect(fromDb?.partyType.type).toEqual(savedPartyType.type) + expect(fromDb?.partyType.tenantId).toEqual(savedPartyType.tenantId) + expect(fromDb?.partyType.name).toEqual(savedPartyType.name) }) - it('Should not update creation date when saving contact type', async (): Promise => { - const contactType: BasicContactType = { - type: ContactTypeEnum.PERSON, + it('Should not update creation date when saving party type', async (): Promise => { + const partyType: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', } - const contactTypeEntity: ContactTypeEntity = contactTypeEntityFrom(contactType) - const savedContactType: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).save(contactTypeEntity) - await dbConnection - .getRepository(ContactTypeEntity) - .save({ ...savedContactType, type: ContactTypeEnum.ORGANIZATION }) + const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) + const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) + await dbConnection.getRepository(PartyTypeEntity).save({ ...savedPartyType, type: PartyTypeEnum.ORGANIZATION }) - const fromDb: ContactTypeEntity | null = await dbConnection.getRepository(ContactTypeEntity).findOne({ + const fromDb: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).findOne({ where: { - type: ContactTypeEnum.ORGANIZATION, + type: PartyTypeEnum.ORGANIZATION, }, }) expect(fromDb).toBeDefined() - expect(fromDb?.createdAt).toEqual(savedContactType?.createdAt) + expect(fromDb?.createdAt).toEqual(savedPartyType?.createdAt) }) - }) diff --git a/packages/data-store/src/__tests__/contact.store.test.ts b/packages/data-store/src/__tests__/contact.store.test.ts index 950a38785..7c2055d03 100644 --- a/packages/data-store/src/__tests__/contact.store.test.ts +++ b/packages/data-store/src/__tests__/contact.store.test.ts @@ -4,21 +4,21 @@ import { DataStoreContactEntities } from '../index' import { ContactStore } from '../contact/ContactStore' import { IdentityRoleEnum, - ContactTypeEnum, - IBasicContact, - IContact, + PartyTypeEnum, + NonPersistedParty, + Party, CorrelationIdentifierEnum, - IIdentity, - IPerson, - BasicPerson, - IBasicIdentity, - IGetIdentitiesArgs, - IGetContactsArgs, - BasicContactRelationship, - IContactRelationship, - IContactType, - IGetRelationshipsArgs, - BasicContactType, + Identity, + NaturalPerson, + NonPersistedNaturalPerson, + NonPersistedIdentity, + GetIdentitiesArgs, + GetPartiesArgs, + NonPersistedPartyRelationship, + PartyRelationship, + PartyType, + GetRelationshipsArgs, + NonPersistedPartyType, } from '../types' describe('Contact store tests', (): void => { @@ -59,15 +59,15 @@ describe('Contact store tests', (): void => { await (await dbConnection).destroy() }) - it('should get contact by id', async (): Promise => { - const contact: IBasicContact = { + it('should get party by id', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', @@ -75,117 +75,117 @@ describe('Contact store tests', (): void => { }, } - const savedContact: IContact = await contactStore.addContact(contact) - expect(savedContact).toBeDefined() + const savedParty: Party = await contactStore.addParty(party) + expect(savedParty).toBeDefined() - const result: IContact = await contactStore.getContact({ contactId: savedContact.id }) + const result: Party = await contactStore.getParty({ partyId: savedParty.id }) expect(result).toBeDefined() }) - it('should throw error when getting contact with unknown id', async (): Promise => { - const contactId = 'unknownContactId' + it('should throw error when getting party with unknown id', async (): Promise => { + const partyId = 'unknownPartyId' - await expect(contactStore.getContact({ contactId })).rejects.toThrow(`No contact found for id: ${contactId}`) + await expect(contactStore.getParty({ partyId })).rejects.toThrow(`No party found for id: ${partyId}`) }) - it('should get all contacts', async (): Promise => { - const contact1: IBasicContact = { + it('should get all parties', async (): Promise => { + const party1: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name1', }, - contactOwner: { + contact: { firstName: 'example_first_name1', middleName: 'example_middle_name1', lastName: 'example_last_name1', displayName: 'example_display_name1', }, } - const savedContact1: IContact = await contactStore.addContact(contact1) - expect(savedContact1).toBeDefined() + const savedParty1: Party = await contactStore.addParty(party1) + expect(savedParty1).toBeDefined() - const contact2: IBasicContact = { + const party2: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'example_name2', }, - contactOwner: { + contact: { firstName: 'example_first_name2', middleName: 'example_middle_name2', lastName: 'example_last_name2', displayName: 'example_display_name2', }, } - const savedContact2: IContact = await contactStore.addContact(contact2) - expect(savedContact2).toBeDefined() + const savedParty2: Party = await contactStore.addParty(party2) + expect(savedParty2).toBeDefined() - const result: Array = await contactStore.getContacts() + const result: Array = await contactStore.getParties() expect(result).toBeDefined() expect(result.length).toEqual(2) }) - it('should get contacts by filter', async (): Promise => { - const contact: IBasicContact = { + it('should get parties by filter', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', displayName: 'example_display_name', }, } - const savedContact: IContact = await contactStore.addContact(contact) - expect(savedContact).toBeDefined() + const savedParty: Party = await contactStore.addParty(party) + expect(savedParty).toBeDefined() - const args: IGetContactsArgs = { + const args: GetPartiesArgs = { filter: [ { - contactOwner: { - firstName: (contact.contactOwner).firstName, + contact: { + firstName: (party.contact).firstName, }, }, { - contactOwner: { - middleName: (contact.contactOwner).middleName, + contact: { + middleName: (party.contact).middleName, }, }, { - contactOwner: { - lastName: (contact.contactOwner).lastName, + contact: { + lastName: (party.contact).lastName, }, }, { - contactOwner: { - displayName: (contact.contactOwner).displayName, + contact: { + displayName: (party.contact).displayName, }, }, ], } - const result: Array = await contactStore.getContacts(args) + const result: Array = await contactStore.getParties(args) expect(result.length).toEqual(1) }) - it('should get whole contacts by filter', async (): Promise => { - const contact: IBasicContact = { + it('should get whole parties by filter', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', @@ -217,11 +217,15 @@ describe('Contact store tests', (): void => { }, }, ], + electronicAddresses: [{ + type: 'email', + electronicAddress: 'sphereon@sphereon.com' + }] } - const savedContact: IContact = await contactStore.addContact(contact) - expect(savedContact).toBeDefined() + const savedParty: Party = await contactStore.addParty(party) + expect(savedParty).toBeDefined() - const args: IGetContactsArgs = { + const args: GetPartiesArgs = { filter: [ { identities: { @@ -232,20 +236,21 @@ describe('Contact store tests', (): void => { }, ], } - const result: Array = await contactStore.getContacts(args) + const result: Array = await contactStore.getParties(args) expect(result[0].identities.length).toEqual(3) + expect(result[0].electronicAddresses.length).toEqual(1) }) - it('should get contacts by name', async (): Promise => { - const contact: IBasicContact = { + it('should get parties by name', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'something', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', @@ -253,42 +258,42 @@ describe('Contact store tests', (): void => { }, } - const savedContact: IContact = await contactStore.addContact(contact) - expect(savedContact).toBeDefined() + const savedParty: Party = await contactStore.addParty(party) + expect(savedParty).toBeDefined() - const args: IGetContactsArgs = { + const args: GetPartiesArgs = { filter: [ { - contactOwner: { - firstName: (contact.contactOwner).firstName, + contact: { + firstName: (party.contact).firstName, }, }, { - contactOwner: { - middleName: (contact.contactOwner).middleName, + contact: { + middleName: (party.contact).middleName, }, }, { - contactOwner: { - lastName: (contact.contactOwner).lastName, + contact: { + lastName: (party.contact).lastName, }, }, ], } - const result: Array = await contactStore.getContacts(args) + const result: Array = await contactStore.getParties(args) expect(result.length).toEqual(1) }) - it('should get contacts by display name', async (): Promise => { - const contact: IBasicContact = { + it('should get parties by display name', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', @@ -296,83 +301,83 @@ describe('Contact store tests', (): void => { }, } - const savedContact: IContact = await contactStore.addContact(contact) - expect(savedContact).toBeDefined() + const savedParty: Party = await contactStore.addParty(party) + expect(savedParty).toBeDefined() - const args: IGetContactsArgs = { + const args: GetPartiesArgs = { filter: [ { - contactOwner: { - displayName: (contact.contactOwner).displayName, + contact: { + displayName: (party.contact).displayName, }, }, ], } - const result: Array = await contactStore.getContacts(args) + const result: Array = await contactStore.getParties(args) expect(result.length).toEqual(1) }) - it('should get contacts by uri', async (): Promise => { - const contact: IBasicContact = { + it('should get parties by uri', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', displayName: 'example_display_name', }, } - const savedContact: IContact = await contactStore.addContact(contact) - expect(savedContact).toBeDefined() + const savedParty: Party = await contactStore.addParty(party) + expect(savedParty).toBeDefined() - const args: IGetContactsArgs = { + const args: GetPartiesArgs = { filter: [{ uri: 'example.com' }], } - const result: Array = await contactStore.getContacts(args) + const result: Array = await contactStore.getParties(args) expect(result.length).toEqual(1) }) - it('should return no contacts if filter does not match', async (): Promise => { - const args: IGetContactsArgs = { + it('should return no parties if filter does not match', async (): Promise => { + const args: GetPartiesArgs = { filter: [ { - contactOwner: { + contact: { firstName: 'no_match_firstName', }, }, { - contactOwner: { + contact: { middleName: 'no_match_middleName', }, }, { - contactOwner: { + contact: { lastName: 'no_match_lastName', }, }, ], } - const result: Array = await contactStore.getContacts(args) + const result: Array = await contactStore.getParties(args) expect(result.length).toEqual(0) }) - it('should add contact without identities', async (): Promise => { - const contact: IBasicContact = { + it('should add party without identities', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', @@ -380,24 +385,24 @@ describe('Contact store tests', (): void => { }, } - const result: IContact = await contactStore.addContact(contact) + const result: Party = await contactStore.addParty(party) expect(result).toBeDefined() - expect((result.contactOwner).firstName).toEqual((contact.contactOwner).firstName) - expect((result.contactOwner).middleName).toEqual((contact.contactOwner).middleName) - expect((result.contactOwner).lastName).toEqual((contact.contactOwner).lastName) + expect((result.contact).firstName).toEqual((party.contact).firstName) + expect((result.contact).middleName).toEqual((party.contact).middleName) + expect((result.contact).lastName).toEqual((party.contact).lastName) expect(result.identities.length).toEqual(0) }) - it('should add contact with identities', async (): Promise => { - const contact: IBasicContact = { + it('should add party with identities', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', @@ -423,24 +428,24 @@ describe('Contact store tests', (): void => { ], } - const result: IContact = await contactStore.addContact(contact) + const result: Party = await contactStore.addParty(party) expect(result).toBeDefined() - expect((result.contactOwner).firstName).toEqual((contact.contactOwner).firstName) - expect((result.contactOwner).middleName).toEqual((contact.contactOwner).middleName) - expect((result.contactOwner).lastName).toEqual((contact.contactOwner).lastName) + expect((result.contact).firstName).toEqual((party.contact).firstName) + expect((result.contact).middleName).toEqual((party.contact).middleName) + expect((result.contact).lastName).toEqual((party.contact).lastName) expect(result.identities.length).toEqual(2) }) - it('should throw error when adding contact with invalid identity', async (): Promise => { - const contact: IBasicContact = { + it('should throw error when adding party with invalid identity', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'something', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', @@ -466,98 +471,28 @@ describe('Contact store tests', (): void => { ], } - await expect(contactStore.addContact(contact)).rejects.toThrow(`Identity with correlation type url should contain a connection`) + await expect(contactStore.addParty(party)).rejects.toThrow(`Identity with correlation type url should contain a connection`) }) - it('should throw error when adding person contact with duplicate display name', async (): Promise => { - const displayName = 'non_unique_value' - const contact1: IBasicContact = { + it('should update party by id', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name1', - }, - contactOwner: { - firstName: 'example_first_name1', - middleName: 'example_middle_name1', - lastName: 'example_last_name1', - displayName, - }, - } - const savedContact1: IContact = await contactStore.addContact(contact1) - expect(savedContact1).toBeDefined() - - const contact2: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - name: 'example_name2', - }, - contactOwner: { - firstName: 'example_first_name2', - middleName: 'example_middle_name2', - lastName: 'example_last_name2', - displayName, - }, - } - - await expect(contactStore.addContact(contact2)).rejects.toThrow(`Duplicate display names are not allowed. Display name: ${displayName}`) - }) - - it('should throw error when adding organization contact with duplicate display name', async (): Promise => { - const displayName = 'non_unique_value' - const contact1: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.ORGANIZATION, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name1', - }, - contactOwner: { - legalName: 'example_legal_name1', - displayName, - }, - } - const savedContact1: IContact = await contactStore.addContact(contact1) - expect(savedContact1).toBeDefined() - - const contact2: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.ORGANIZATION, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - name: 'example_name2', - }, - contactOwner: { - legalName: 'example_legal_name2', - displayName, - }, - } - - await expect(contactStore.addContact(contact2)).rejects.toThrow(`Duplicate display names are not allowed. Display name: ${displayName}`) - }) - - it('should update contact by id', async (): Promise => { - const contact: IBasicContact = { - uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', displayName: 'example_display_name', }, } - const savedContact: IContact = await contactStore.addContact(contact) - expect(savedContact).toBeDefined() + const savedParty: Party = await contactStore.addParty(party) + expect(savedParty).toBeDefined() - const identity1: IBasicIdentity = { + const identity1: NonPersistedIdentity = { alias: 'test_alias1', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -565,10 +500,10 @@ describe('Contact store tests', (): void => { correlationId: 'example_did1', }, } - const savedIdentity1: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity1 }) + const savedIdentity1: Identity = await contactStore.addIdentity({ partyId: savedParty.id, identity: identity1 }) expect(savedIdentity1).toBeDefined() - const identity2: IBasicIdentity = { + const identity2: NonPersistedIdentity = { alias: 'test_alias2', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -576,77 +511,77 @@ describe('Contact store tests', (): void => { correlationId: 'example_did2', }, } - const savedIdentity2: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity2 }) + const savedIdentity2: Identity = await contactStore.addIdentity({ partyId: savedParty.id, identity: identity2 }) expect(savedIdentity2).toBeDefined() const contactFirstName = 'updated_first_name' - const updatedContact: IContact = { - ...savedContact, - contactOwner: { - ...savedContact.contactOwner, + const updatedParty: Party = { + ...savedParty, + contact: { + ...savedParty.contact, firstName: contactFirstName, }, } - await contactStore.updateContact({ contact: updatedContact }) - const result: IContact = await contactStore.getContact({ contactId: savedContact.id }) + await contactStore.updateParty({ party: updatedParty }) + const result: Party = await contactStore.getParty({ partyId: savedParty.id }) expect(result).toBeDefined() - expect((result.contactOwner).firstName).toEqual(contactFirstName) + expect((result.contact).firstName).toEqual(contactFirstName) expect(result.identities.length).toEqual(2) }) - it('should throw error when updating contact with unknown id', async (): Promise => { - const contact: IBasicContact = { + it('should throw error when updating party with unknown id', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', displayName: 'example_display_name', }, } - const savedContact: IContact = await contactStore.addContact(contact) - expect(savedContact).toBeDefined() + const savedParty: Party = await contactStore.addParty(party) + expect(savedParty).toBeDefined() - const contactId = 'unknownContactId' + const partyId = 'unknownPartyId' const contactFirstName = 'updated_first_name' - const updatedContact: IContact = { - ...savedContact, - id: contactId, - contactOwner: { - ...savedContact.contactOwner, + const updatedParty: Party = { + ...savedParty, + id: partyId, + contact: { + ...savedParty.contact, firstName: contactFirstName, }, } - await expect(contactStore.updateContact({ contact: updatedContact })).rejects.toThrow(`No contact found for id: ${contactId}`) + await expect(contactStore.updateParty({ party: updatedParty })).rejects.toThrow(`No party found for id: ${partyId}`) }) it('should get identity by id', async (): Promise => { - const contact: IBasicContact = { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', displayName: 'example_display_name', }, } - const savedContact: IContact = await contactStore.addContact(contact) - expect(savedContact).toBeDefined() + const savedParty: Party = await contactStore.addParty(party) + expect(savedParty).toBeDefined() - const identity: IBasicIdentity = { + const identity: NonPersistedIdentity = { alias: 'test_alias', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -654,33 +589,33 @@ describe('Contact store tests', (): void => { correlationId: 'example_did', }, } - const savedIdentity: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity }) + const savedIdentity: Identity = await contactStore.addIdentity({ partyId: savedParty.id, identity }) expect(savedIdentity).toBeDefined() - const result: IIdentity = await contactStore.getIdentity({ identityId: savedIdentity.id }) + const result: Identity = await contactStore.getIdentity({ identityId: savedIdentity.id }) expect(result).toBeDefined() }) it('should get holderDID identity by id', async (): Promise => { - const contact: IBasicContact = { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', displayName: 'example_display_name', }, } - const savedContact: IContact = await contactStore.addContact(contact) - expect(savedContact).toBeDefined() + const savedParty: Party = await contactStore.addParty(party) + expect(savedParty).toBeDefined() - const identity: IBasicIdentity = { + const identity: NonPersistedIdentity = { alias: 'test_alias', roles: [IdentityRoleEnum.HOLDER], identifier: { @@ -688,10 +623,10 @@ describe('Contact store tests', (): void => { correlationId: 'example_did', }, } - const savedIdentity: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity }) + const savedIdentity: Identity = await contactStore.addIdentity({ partyId: savedParty.id, identity }) expect(savedIdentity).toBeDefined() - const result: IIdentity = await contactStore.getIdentity({ identityId: savedIdentity.id }) + const result: Identity = await contactStore.getIdentity({ identityId: savedIdentity.id }) expect(result).toBeDefined() }) @@ -703,24 +638,24 @@ describe('Contact store tests', (): void => { }) it('should get all identities for contact', async (): Promise => { - const contact: IBasicContact = { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', displayName: 'example_display_name', }, } - const savedContact: IContact = await contactStore.addContact(contact) - expect(savedContact).toBeDefined() + const savedParty: Party = await contactStore.addParty(party) + expect(savedParty).toBeDefined() - const identity1: IBasicIdentity = { + const identity1: NonPersistedIdentity = { alias: 'test_alias1', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -728,10 +663,10 @@ describe('Contact store tests', (): void => { correlationId: 'example_did1', }, } - const savedIdentity1: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity1 }) + const savedIdentity1: Identity = await contactStore.addIdentity({ partyId: savedParty.id, identity: identity1 }) expect(savedIdentity1).toBeDefined() - const identity2: IBasicIdentity = { + const identity2: NonPersistedIdentity = { alias: 'test_alias2', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -739,37 +674,37 @@ describe('Contact store tests', (): void => { correlationId: 'example_did2', }, } - const savedIdentity2: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity2 }) + const savedIdentity2: Identity = await contactStore.addIdentity({ partyId: savedParty.id, identity: identity2 }) expect(savedIdentity2).toBeDefined() - const args: IGetIdentitiesArgs = { - filter: [{ contactId: savedContact.id }], + const args: GetIdentitiesArgs = { + filter: [{ partyId: savedParty.id }], } - const result: Array = await contactStore.getIdentities(args) + const result: Array = await contactStore.getIdentities(args) expect(result.length).toEqual(2) }) it('should get all identities', async (): Promise => { - const contact: IBasicContact = { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', displayName: 'example_display_name', }, } - const savedContact: IContact = await contactStore.addContact(contact) - expect(savedContact).toBeDefined() + const savedParty: Party = await contactStore.addParty(party) + expect(savedParty).toBeDefined() - const identity1: IBasicIdentity = { + const identity1: NonPersistedIdentity = { alias: 'test_alias1', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -777,10 +712,10 @@ describe('Contact store tests', (): void => { correlationId: 'example_did1', }, } - const savedIdentity1: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity1 }) + const savedIdentity1: Identity = await contactStore.addIdentity({ partyId: savedParty.id, identity: identity1 }) expect(savedIdentity1).toBeDefined() - const identity2: IBasicIdentity = { + const identity2: NonPersistedIdentity = { alias: 'test_alias2', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -788,34 +723,34 @@ describe('Contact store tests', (): void => { correlationId: 'example_did2', }, } - const savedIdentity2: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity2 }) + const savedIdentity2: Identity = await contactStore.addIdentity({ partyId: savedParty.id, identity: identity2 }) expect(savedIdentity2).toBeDefined() - const result: Array = await contactStore.getIdentities() + const result: Array = await contactStore.getIdentities() expect(result.length).toEqual(2) }) it('should get identities by filter', async (): Promise => { - const contact: IBasicContact = { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', displayName: 'example_display_name', }, } - const savedContact: IContact = await contactStore.addContact(contact) - expect(savedContact).toBeDefined() + const savedParty: Party = await contactStore.addParty(party) + expect(savedParty).toBeDefined() const alias = 'test_alias1' - const identity1: IBasicIdentity = { + const identity1: NonPersistedIdentity = { alias, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -823,10 +758,10 @@ describe('Contact store tests', (): void => { correlationId: 'example_did1', }, } - const savedIdentity1: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity1 }) + const savedIdentity1: Identity = await contactStore.addIdentity({ partyId: savedParty.id, identity: identity1 }) expect(savedIdentity1).toBeDefined() - const identity2: IBasicIdentity = { + const identity2: NonPersistedIdentity = { alias: 'test_alias2', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -834,38 +769,38 @@ describe('Contact store tests', (): void => { correlationId: 'example_did2', }, } - const savedIdentity2: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity2 }) + const savedIdentity2: Identity = await contactStore.addIdentity({ partyId: savedParty.id, identity: identity2 }) expect(savedIdentity2).toBeDefined() - const args: IGetIdentitiesArgs = { + const args: GetIdentitiesArgs = { filter: [{ alias }], } - const result: Array = await contactStore.getIdentities(args) + const result: Array = await contactStore.getIdentities(args) expect(result.length).toEqual(1) }) it('should get whole identities by filter', async (): Promise => { - const contact: IBasicContact = { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', displayName: 'example_display_name', }, } - const savedContact: IContact = await contactStore.addContact(contact) - expect(savedContact).toBeDefined() + const savedParty: Party = await contactStore.addParty(party) + expect(savedParty).toBeDefined() const alias = 'test_alias1' - const identity1: IBasicIdentity = { + const identity1: NonPersistedIdentity = { alias, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -883,38 +818,38 @@ describe('Contact store tests', (): void => { }, ], } - const savedIdentity1: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity: identity1 }) + const savedIdentity1: Identity = await contactStore.addIdentity({ partyId: savedParty.id, identity: identity1 }) expect(savedIdentity1).toBeDefined() - const args: IGetIdentitiesArgs = { + const args: GetIdentitiesArgs = { filter: [{ metadata: { label: 'label1' } }], } - const result: Array = await contactStore.getIdentities(args) + const result: Array = await contactStore.getIdentities(args) expect(result[0]).toBeDefined() expect(result[0].metadata!.length).toEqual(2) }) it('should add identity to contact', async (): Promise => { - const contact: IBasicContact = { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', displayName: 'example_display_name', }, } - const savedContact: IContact = await contactStore.addContact(contact) - expect(savedContact).toBeDefined() + const savedParty: Party = await contactStore.addParty(party) + expect(savedParty).toBeDefined() - const identity: IBasicIdentity = { + const identity: NonPersistedIdentity = { alias: 'test_alias', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -922,10 +857,10 @@ describe('Contact store tests', (): void => { correlationId: 'example_did', }, } - const savedIdentity: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity }) + const savedIdentity: Identity = await contactStore.addIdentity({ partyId: savedParty.id, identity }) expect(savedIdentity).toBeDefined() - const result: IContact = await contactStore.getContact({ contactId: savedContact.id }) + const result: Party = await contactStore.getParty({ partyId: savedParty.id }) expect(result.identities.length).toEqual(1) }) @@ -936,25 +871,25 @@ describe('Contact store tests', (): void => { }) it('should throw error when adding identity with invalid identifier', async (): Promise => { - const contact: IBasicContact = { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', displayName: 'example_display_name', }, } - const savedContact: IContact = await contactStore.addContact(contact) - expect(savedContact).toBeDefined() + const savedParty: Party = await contactStore.addParty(party) + expect(savedParty).toBeDefined() const correlationId = 'missing_connection_example' - const identity: IBasicIdentity = { + const identity: NonPersistedIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -963,31 +898,31 @@ describe('Contact store tests', (): void => { }, } - await expect(contactStore.addIdentity({ contactId: savedContact.id, identity })).rejects.toThrow( + await expect(contactStore.addIdentity({ partyId: savedParty.id, identity })).rejects.toThrow( `Identity with correlation type url should contain a connection` ) }) it('should throw error when updating identity with invalid identifier', async (): Promise => { - const contact: IBasicContact = { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', displayName: 'example_display_name', }, } - const savedContact: IContact = await contactStore.addContact(contact) - expect(savedContact).toBeDefined() + const savedParty: Party = await contactStore.addParty(party) + expect(savedParty).toBeDefined() const correlationId = 'missing_connection_example' - const identity: IBasicIdentity = { + const identity: NonPersistedIdentity = { alias: correlationId, roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER, IdentityRoleEnum.HOLDER], identifier: { @@ -995,7 +930,7 @@ describe('Contact store tests', (): void => { correlationId, }, } - const storedIdentity: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity }) + const storedIdentity: Identity = await contactStore.addIdentity({ partyId: savedParty.id, identity }) storedIdentity.identifier = { ...storedIdentity.identifier, type: CorrelationIdentifierEnum.URL } await expect(contactStore.updateIdentity({ identity: storedIdentity })).rejects.toThrow( @@ -1004,24 +939,24 @@ describe('Contact store tests', (): void => { }) it('should update identity by id', async (): Promise => { - const contact: IBasicContact = { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', displayName: 'example_display_name', }, } - const savedContact: IContact = await contactStore.addContact(contact) - expect(savedContact).toBeDefined() + const savedParty: Party = await contactStore.addParty(party) + expect(savedParty).toBeDefined() - const identity: IBasicIdentity = { + const identity: NonPersistedIdentity = { alias: 'example_did', roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], identifier: { @@ -1029,26 +964,26 @@ describe('Contact store tests', (): void => { correlationId: 'example_did', }, } - const storedIdentity: IIdentity = await contactStore.addIdentity({ contactId: savedContact.id, identity }) + const storedIdentity: Identity = await contactStore.addIdentity({ partyId: savedParty.id, identity }) const correlationId = 'new_update_example_did' storedIdentity.identifier = { ...storedIdentity.identifier, correlationId } await contactStore.updateIdentity({ identity: storedIdentity }) - const result: IIdentity = await contactStore.getIdentity({ identityId: storedIdentity.id }) + const result: Identity = await contactStore.getIdentity({ identityId: storedIdentity.id }) expect(result).toBeDefined() expect(result.identifier.correlationId).toEqual(correlationId) }) - it('should get aggregate of identity roles on contact', async (): Promise => { - const contact: IBasicContact = { + it('should get aggregate of identity roles on party', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', @@ -1082,8 +1017,8 @@ describe('Contact store tests', (): void => { ], } - const savedContact: IContact = await contactStore.addContact(contact) - const result: IContact = await contactStore.getContact({ contactId: savedContact.id }) + const savedParty: Party = await contactStore.addParty(party) + const result: Party = await contactStore.getParty({ partyId: savedParty.id }) expect(result.roles).toBeDefined() expect(result.roles.length).toEqual(3) @@ -1091,100 +1026,100 @@ describe('Contact store tests', (): void => { }) it('should add relationship', async (): Promise => { - const contact1: IBasicContact = { + const party1: NonPersistedParty = { uri: 'example1.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name1', }, - contactOwner: { + contact: { firstName: 'example_first_name1', middleName: 'example_middle_name1', lastName: 'example_last_name1', displayName: 'example_display_name1', }, } - const savedContact1: IContact = await contactStore.addContact(contact1) - expect(savedContact1).toBeDefined() + const savedParty1: Party = await contactStore.addParty(party1) + expect(savedParty1).toBeDefined() - const contact2: IBasicContact = { + const party2: NonPersistedParty = { uri: 'example2.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'example_name2', }, - contactOwner: { + contact: { firstName: 'example_first_name2', middleName: 'example_middle_name2', lastName: 'example_last_name2', displayName: 'example_display_name2', }, } - const savedContact2: IContact = await contactStore.addContact(contact2) - expect(savedContact2).toBeDefined() + const savedParty2: Party = await contactStore.addParty(party2) + expect(savedParty2).toBeDefined() - const relationship: BasicContactRelationship = { - leftId: savedContact1.id, - rightId: savedContact2.id, + const relationship: NonPersistedPartyRelationship = { + leftId: savedParty1.id, + rightId: savedParty2.id, } await contactStore.addRelationship(relationship) - const result: IContact = await contactStore.getContact({ contactId: savedContact1.id }) + const result: Party = await contactStore.getParty({ partyId: savedParty1.id }) expect(result).toBeDefined() expect(result.relationships.length).toEqual(1) - expect(result.relationships[0].leftId).toEqual(savedContact1.id) - expect(result.relationships[0].rightId).toEqual(savedContact2.id) + expect(result.relationships[0].leftId).toEqual(savedParty1.id) + expect(result.relationships[0].rightId).toEqual(savedParty2.id) }) it('should get relationship', async (): Promise => { - const contact1: IBasicContact = { + const party1: NonPersistedParty = { uri: 'example1.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name1', }, - contactOwner: { + contact: { firstName: 'example_first_name1', middleName: 'example_middle_name1', lastName: 'example_last_name1', displayName: 'example_display_name1', }, } - const savedContact1: IContact = await contactStore.addContact(contact1) - expect(savedContact1).toBeDefined() + const savedParty1: Party = await contactStore.addParty(party1) + expect(savedParty1).toBeDefined() - const contact2: IBasicContact = { + const party2: NonPersistedParty = { uri: 'example2.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'example_name2', }, - contactOwner: { + contact: { firstName: 'example_first_name2', middleName: 'example_middle_name2', lastName: 'example_last_name2', displayName: 'example_display_name2', }, } - const savedContact2: IContact = await contactStore.addContact(contact2) - expect(savedContact2).toBeDefined() + const savedParty2: Party = await contactStore.addParty(party2) + expect(savedParty2).toBeDefined() - const relationship: BasicContactRelationship = { - leftId: savedContact1.id, - rightId: savedContact2.id, + const relationship: NonPersistedPartyRelationship = { + leftId: savedParty1.id, + rightId: savedParty2.id, } - const savedRelationship: IContactRelationship = await contactStore.addRelationship(relationship) + const savedRelationship: PartyRelationship = await contactStore.addRelationship(relationship) - const result: IContactRelationship = await contactStore.getRelationship({ relationshipId: savedRelationship.id }) + const result: PartyRelationship = await contactStore.getRelationship({ relationshipId: savedRelationship.id }) expect(result).toBeDefined() - expect(result.leftId).toEqual(savedContact1.id) - expect(result.rightId).toEqual(savedContact2.id) + expect(result.leftId).toEqual(savedParty1.id) + expect(result.rightId).toEqual(savedParty2.id) }) it('should throw error when getting relationship with unknown id', async (): Promise => { @@ -1194,165 +1129,165 @@ describe('Contact store tests', (): void => { }) it('should get all relationships', async (): Promise => { - const contact1: IBasicContact = { + const party1: NonPersistedParty = { uri: 'example1.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name1', }, - contactOwner: { + contact: { firstName: 'example_first_name1', middleName: 'example_middle_name1', lastName: 'example_last_name1', displayName: 'example_display_name1', }, } - const savedContact1: IContact = await contactStore.addContact(contact1) - expect(savedContact1).toBeDefined() + const savedParty1: Party = await contactStore.addParty(party1) + expect(savedParty1).toBeDefined() - const contact2: IBasicContact = { + const party2: NonPersistedParty = { uri: 'example2.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'example_name2', }, - contactOwner: { + contact: { firstName: 'example_first_name2', middleName: 'example_middle_name2', lastName: 'example_last_name2', displayName: 'example_display_name2', }, } - const savedContact2: IContact = await contactStore.addContact(contact2) - expect(savedContact2).toBeDefined() + const savedParty2: Party = await contactStore.addParty(party2) + expect(savedParty2).toBeDefined() - const relationship1: BasicContactRelationship = { - leftId: savedContact1.id, - rightId: savedContact2.id, + const relationship1: NonPersistedPartyRelationship = { + leftId: savedParty1.id, + rightId: savedParty2.id, } await contactStore.addRelationship(relationship1) - const relationship2: BasicContactRelationship = { - leftId: savedContact2.id, - rightId: savedContact1.id, + const relationship2: NonPersistedPartyRelationship = { + leftId: savedParty2.id, + rightId: savedParty1.id, } await contactStore.addRelationship(relationship2) - const result: Array = await contactStore.getRelationships() + const result: Array = await contactStore.getRelationships() expect(result).toBeDefined() expect(result.length).toEqual(2) }) it('should get relationships by filter', async (): Promise => { - const contact1: IBasicContact = { + const party1: NonPersistedParty = { uri: 'example1.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name1', }, - contactOwner: { + contact: { firstName: 'example_first_name1', middleName: 'example_middle_name1', lastName: 'example_last_name1', displayName: 'example_display_name1', }, } - const savedContact1: IContact = await contactStore.addContact(contact1) - expect(savedContact1).toBeDefined() + const savedParty1: Party = await contactStore.addParty(party1) + expect(savedParty1).toBeDefined() - const contact2: IBasicContact = { + const party2: NonPersistedParty = { uri: 'example2.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'example_name2', }, - contactOwner: { + contact: { firstName: 'example_first_name2', middleName: 'example_middle_name2', lastName: 'example_last_name2', displayName: 'example_display_name2', }, } - const savedContact2: IContact = await contactStore.addContact(contact2) - expect(savedContact2).toBeDefined() + const savedParty2: Party = await contactStore.addParty(party2) + expect(savedParty2).toBeDefined() - const relationship1: BasicContactRelationship = { - leftId: savedContact1.id, - rightId: savedContact2.id, + const relationship1: NonPersistedPartyRelationship = { + leftId: savedParty1.id, + rightId: savedParty2.id, } await contactStore.addRelationship(relationship1) - const relationship2: BasicContactRelationship = { - leftId: savedContact2.id, - rightId: savedContact1.id, + const relationship2: NonPersistedPartyRelationship = { + leftId: savedParty2.id, + rightId: savedParty1.id, } await contactStore.addRelationship(relationship2) - const args: IGetRelationshipsArgs = { + const args: GetRelationshipsArgs = { filter: [ { - leftId: savedContact1.id, - rightId: savedContact2.id, + leftId: savedParty1.id, + rightId: savedParty2.id, }, ], } - const result: Array = await contactStore.getRelationships(args) + const result: Array = await contactStore.getRelationships(args) expect(result).toBeDefined() expect(result.length).toEqual(1) }) it('should remove relationship', async (): Promise => { - const contact1: IBasicContact = { + const party1: NonPersistedParty = { uri: 'example1.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name1', }, - contactOwner: { + contact: { firstName: 'example_first_name1', middleName: 'example_middle_name1', lastName: 'example_last_name1', displayName: 'example_display_name1', }, } - const savedContact1: IContact = await contactStore.addContact(contact1) - expect(savedContact1).toBeDefined() + const savedParty1: Party = await contactStore.addParty(party1) + expect(savedParty1).toBeDefined() - const contact2: IBasicContact = { + const party2: NonPersistedParty = { uri: 'example2.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'example_name2', }, - contactOwner: { + contact: { firstName: 'example_first_name2', middleName: 'example_middle_name2', lastName: 'example_last_name2', displayName: 'example_display_name2', }, } - const savedContact2: IContact = await contactStore.addContact(contact2) - expect(savedContact2).toBeDefined() + const savedParty2: Party = await contactStore.addParty(party2) + expect(savedParty2).toBeDefined() - const relationship: BasicContactRelationship = { - leftId: savedContact1.id, - rightId: savedContact2.id, + const relationship: NonPersistedPartyRelationship = { + leftId: savedParty1.id, + rightId: savedParty2.id, } - const savedRelationship: IContactRelationship = await contactStore.addRelationship(relationship) + const savedRelationship: PartyRelationship = await contactStore.addRelationship(relationship) expect(savedRelationship).toBeDefined() await contactStore.removeRelationship({ relationshipId: savedRelationship.id }) - const result: IContact = await contactStore.getContact({ contactId: savedContact1.id }) + const result: Party = await contactStore.getParty({ partyId: savedParty1.id }) expect(result).toBeDefined() expect(result?.relationships?.length).toEqual(0) @@ -1365,291 +1300,291 @@ describe('Contact store tests', (): void => { }) it('should return no relationships if filter does not match', async (): Promise => { - const args: IGetRelationshipsArgs = { + const args: GetRelationshipsArgs = { filter: [ { leftId: 'unknown_id', }, ], } - const result: Array = await contactStore.getRelationships(args) + const result: Array = await contactStore.getRelationships(args) expect(result.length).toEqual(0) }) it('should update relationship by id', async (): Promise => { - const contact1: IBasicContact = { + const party1: NonPersistedParty = { uri: 'example1.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name1', }, - contactOwner: { + contact: { firstName: 'example_first_name1', middleName: 'example_middle_name1', lastName: 'example_last_name1', displayName: 'example_display_name1', }, } - const savedContact1: IContact = await contactStore.addContact(contact1) - expect(savedContact1).toBeDefined() + const savedParty1: Party = await contactStore.addParty(party1) + expect(savedParty1).toBeDefined() - const contact2: IBasicContact = { + const party2: NonPersistedParty = { uri: 'example2.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'example_name2', }, - contactOwner: { + contact: { firstName: 'example_first_name2', middleName: 'example_middle_name2', lastName: 'example_last_name2', displayName: 'example_display_name2', }, } - const savedContact2: IContact = await contactStore.addContact(contact2) - expect(savedContact2).toBeDefined() + const savedParty2: Party = await contactStore.addParty(party2) + expect(savedParty2).toBeDefined() - const contact3: IBasicContact = { + const party3: NonPersistedParty = { uri: 'example3.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d287', name: 'example_name3', }, - contactOwner: { + contact: { firstName: 'example_first_name3', middleName: 'example_middle_name3', lastName: 'example_last_name3', displayName: 'example_display_name3', }, } - const savedContact3: IContact = await contactStore.addContact(contact3) - expect(savedContact3).toBeDefined() + const savedParty3: Party = await contactStore.addParty(party3) + expect(savedParty3).toBeDefined() - const relationship: BasicContactRelationship = { - leftId: savedContact1.id, - rightId: savedContact2.id, + const relationship: NonPersistedPartyRelationship = { + leftId: savedParty1.id, + rightId: savedParty2.id, } - const savedRelationship: IContactRelationship = await contactStore.addRelationship(relationship) + const savedRelationship: PartyRelationship = await contactStore.addRelationship(relationship) - const updatedRelationship: IContactRelationship = { + const updatedRelationship: PartyRelationship = { ...savedRelationship, - rightId: savedContact3.id, + rightId: savedParty3.id, } await contactStore.updateRelationship({ relationship: updatedRelationship }) - const result: IContact = await contactStore.getContact({ contactId: savedContact1.id }) + const result: Party = await contactStore.getParty({ partyId: savedParty1.id }) expect(result).toBeDefined() expect(result.relationships.length).toEqual(1) - expect(result.relationships[0].leftId).toEqual(savedContact1.id) - expect(result.relationships[0].rightId).toEqual(savedContact3.id) + expect(result.relationships[0].leftId).toEqual(savedParty1.id) + expect(result.relationships[0].rightId).toEqual(savedParty3.id) }) it('should throw error when updating relationship with unknown id', async (): Promise => { - const contact1: IBasicContact = { + const party1: NonPersistedParty = { uri: 'example1.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name1', }, - contactOwner: { + contact: { firstName: 'example_first_name1', middleName: 'example_middle_name1', lastName: 'example_last_name1', displayName: 'example_display_name1', }, } - const savedContact1: IContact = await contactStore.addContact(contact1) - expect(savedContact1).toBeDefined() + const savedParty1: Party = await contactStore.addParty(party1) + expect(savedParty1).toBeDefined() - const contact2: IBasicContact = { + const party2: NonPersistedParty = { uri: 'example2.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'example_name2', }, - contactOwner: { + contact: { firstName: 'example_first_name2', middleName: 'example_middle_name2', lastName: 'example_last_name2', displayName: 'example_display_name2', }, } - const savedContact2: IContact = await contactStore.addContact(contact2) - expect(savedContact2).toBeDefined() + const savedParty2: Party = await contactStore.addParty(party2) + expect(savedParty2).toBeDefined() - const relationship: BasicContactRelationship = { - leftId: savedContact1.id, - rightId: savedContact2.id, + const relationship: NonPersistedPartyRelationship = { + leftId: savedParty1.id, + rightId: savedParty2.id, } - const savedRelationship: IContactRelationship = await contactStore.addRelationship(relationship) + const savedRelationship: PartyRelationship = await contactStore.addRelationship(relationship) const relationshipId = 'unknownRelationshipId' - const updatedRelationship: IContactRelationship = { + const updatedRelationship: PartyRelationship = { ...savedRelationship, id: relationshipId, - rightId: savedContact2.id, + rightId: savedParty2.id, } await expect(contactStore.updateRelationship({ relationship: updatedRelationship })).rejects.toThrow( - `No contact relationship found for id: ${relationshipId}` + `No party relationship found for id: ${relationshipId}` ) }) it('should throw error when updating relationship with unknown right side id', async (): Promise => { - const contact1: IBasicContact = { + const party1: NonPersistedParty = { uri: 'example1.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name1', }, - contactOwner: { + contact: { firstName: 'example_first_name1', middleName: 'example_middle_name1', lastName: 'example_last_name1', displayName: 'example_display_name1', }, } - const savedContact1: IContact = await contactStore.addContact(contact1) - expect(savedContact1).toBeDefined() + const savedParty1: Party = await contactStore.addParty(party1) + expect(savedParty1).toBeDefined() - const contact2: IBasicContact = { + const party2: NonPersistedParty = { uri: 'example2.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'example_name2', }, - contactOwner: { + contact: { firstName: 'example_first_name2', middleName: 'example_middle_name2', lastName: 'example_last_name2', displayName: 'example_display_name2', }, } - const savedContact2: IContact = await contactStore.addContact(contact2) - expect(savedContact2).toBeDefined() + const savedParty2: Party = await contactStore.addParty(party2) + expect(savedParty2).toBeDefined() - const relationship: BasicContactRelationship = { - leftId: savedContact1.id, - rightId: savedContact2.id, + const relationship: NonPersistedPartyRelationship = { + leftId: savedParty1.id, + rightId: savedParty2.id, } - const savedRelationship: IContactRelationship = await contactStore.addRelationship(relationship) + const savedRelationship: PartyRelationship = await contactStore.addRelationship(relationship) - const contactId = 'unknownContactId' - const updatedRelationship: IContactRelationship = { + const partyId = 'unknownPartyId' + const updatedRelationship: PartyRelationship = { ...savedRelationship, - rightId: contactId, + rightId: partyId, } await expect(contactStore.updateRelationship({ relationship: updatedRelationship })).rejects.toThrow( - `No contact found for right contact id: ${contactId}` + `No party found for right side of the relationship, party id: ${partyId}` ) }) it('should throw error when updating relationship with unknown left side id', async (): Promise => { - const contact1: IBasicContact = { + const party1: NonPersistedParty = { uri: 'example1.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name1', }, - contactOwner: { + contact: { firstName: 'example_first_name1', middleName: 'example_middle_name1', lastName: 'example_last_name1', displayName: 'example_display_name1', }, } - const savedContact1: IContact = await contactStore.addContact(contact1) - expect(savedContact1).toBeDefined() + const savedParty1: Party = await contactStore.addParty(party1) + expect(savedParty1).toBeDefined() - const contact2: IBasicContact = { + const party2: NonPersistedParty = { uri: 'example2.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'example_name2', }, - contactOwner: { + contact: { firstName: 'example_first_name2', middleName: 'example_middle_name2', lastName: 'example_last_name2', displayName: 'example_display_name2', }, } - const savedContact2: IContact = await contactStore.addContact(contact2) - expect(savedContact2).toBeDefined() + const savedParty2: Party = await contactStore.addParty(party2) + expect(savedParty2).toBeDefined() - const relationship: BasicContactRelationship = { - leftId: savedContact1.id, - rightId: savedContact2.id, + const relationship: NonPersistedPartyRelationship = { + leftId: savedParty1.id, + rightId: savedParty2.id, } - const savedRelationship: IContactRelationship = await contactStore.addRelationship(relationship) + const savedRelationship: PartyRelationship = await contactStore.addRelationship(relationship) - const contactId = 'unknownContactId' - const updatedRelationship: IContactRelationship = { + const partyId = 'unknownPartyId' + const updatedRelationship: PartyRelationship = { ...savedRelationship, - leftId: contactId, + leftId: partyId, } await expect(contactStore.updateRelationship({ relationship: updatedRelationship })).rejects.toThrow( - `No contact found for left contact id: ${contactId}` + `No party found for left side of the relationship, party id: ${partyId}` ) }) - it('should add contact type', async (): Promise => { - const contactType: BasicContactType = { - type: ContactTypeEnum.PERSON, + it('should add party type', async (): Promise => { + const partyType: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'example_name', description: 'example_description', } - const savedContactType: IContactType = await contactStore.addContactType(contactType) - const result: IContactType = await contactStore.getContactType({ contactTypeId: savedContactType.id }) + const savedPartyType: PartyType = await contactStore.addPartyType(partyType) + const result: PartyType = await contactStore.getPartyType({ partyTypeId: savedPartyType.id }) expect(result).toBeDefined() - expect(result.name).toEqual(contactType.name) - expect(result.type).toEqual(contactType.type) - expect(result.tenantId).toEqual(contactType.tenantId) - expect(result.description).toEqual(contactType.description) + expect(result.name).toEqual(partyType.name) + expect(result.type).toEqual(partyType.type) + expect(result.tenantId).toEqual(partyType.tenantId) + expect(result.description).toEqual(partyType.description) expect(result.lastUpdatedAt).toBeDefined() expect(result.createdAt).toBeDefined() }) - it('should get contact types by filter', async (): Promise => { - const contactType1: BasicContactType = { - type: ContactTypeEnum.PERSON, + it('should get party types by filter', async (): Promise => { + const partyType1: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'example_name1', description: 'example_description1', } - const savedContactType1: IContactType = await contactStore.addContactType(contactType1) - expect(savedContactType1).toBeDefined() + const savedPartyType1: PartyType = await contactStore.addPartyType(partyType1) + expect(savedPartyType1).toBeDefined() - const contactType2: BasicContactType = { - type: ContactTypeEnum.PERSON, + const partyType2: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d287', name: 'example_name2', description: 'example_description2', } - const savedContactType2: IContactType = await contactStore.addContactType(contactType2) - expect(savedContactType2).toBeDefined() + const savedPartyType2: PartyType = await contactStore.addPartyType(partyType2) + expect(savedPartyType2).toBeDefined() - const result: Array = await contactStore.getContactTypes({ + const result: Array = await contactStore.getPartyTypes({ filter: [ { - type: ContactTypeEnum.PERSON, + type: PartyTypeEnum.NATURAL_PERSON, name: 'example_name1', description: 'example_description1', }, @@ -1660,29 +1595,29 @@ describe('Contact store tests', (): void => { expect(result.length).toEqual(1) }) - it('should return no contact types if filter does not match', async (): Promise => { - const contactType1: BasicContactType = { - type: ContactTypeEnum.PERSON, + it('should return no party types if filter does not match', async (): Promise => { + const partyType1: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'example_name1', description: 'example_description1', } - const savedContactType1: IContactType = await contactStore.addContactType(contactType1) - expect(savedContactType1).toBeDefined() + const savedPartyType1: PartyType = await contactStore.addPartyType(partyType1) + expect(savedPartyType1).toBeDefined() - const contactType2: BasicContactType = { - type: ContactTypeEnum.PERSON, + const partyType2: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d287', name: 'example_name2', description: 'example_description2', } - const savedContactType2: IContactType = await contactStore.addContactType(contactType2) - expect(savedContactType2).toBeDefined() + const savedPartyType2: PartyType = await contactStore.addPartyType(partyType2) + expect(savedPartyType2).toBeDefined() - const result: Array = await contactStore.getContactTypes({ + const result: Array = await contactStore.getPartyTypes({ filter: [ { - type: ContactTypeEnum.PERSON, + type: PartyTypeEnum.NATURAL_PERSON, name: 'unknown_name', description: 'unknown_description', }, @@ -1693,113 +1628,111 @@ describe('Contact store tests', (): void => { expect(result.length).toEqual(0) }) - it('should throw error when updating contact type with unknown id', async (): Promise => { - const contactType: BasicContactType = { - type: ContactTypeEnum.PERSON, + it('should throw error when updating party type with unknown id', async (): Promise => { + const partyType: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'example_name', description: 'example_description', } - const savedContactType: IContactType = await contactStore.addContactType(contactType) - expect(savedContactType).toBeDefined() + const savedPartyType: PartyType = await contactStore.addPartyType(partyType) + expect(savedPartyType).toBeDefined() - const contactTypeId = 'unknownContactTypeId' - const updatedContactType: IContactType = { - ...savedContactType, - id: contactTypeId, + const partyTypeId = 'unknownPartyTypeId' + const updatedPartyType: PartyType = { + ...savedPartyType, + id: partyTypeId, description: 'new_example_description', } - await expect(contactStore.updateContactType({ contactType: updatedContactType })).rejects.toThrow( - `No contact type found for id: ${contactTypeId}` - ) + await expect(contactStore.updatePartyType({ partyType: updatedPartyType })).rejects.toThrow(`No party type found for id: ${partyTypeId}`) }) - it('should update contact type by id', async (): Promise => { - const contactType: BasicContactType = { - type: ContactTypeEnum.PERSON, + it('should update party type by id', async (): Promise => { + const partyType: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'example_name', description: 'example_description', } - const savedContactType: IContactType = await contactStore.addContactType(contactType) - expect(savedContactType).toBeDefined() + const savedPartyType: PartyType = await contactStore.addPartyType(partyType) + expect(savedPartyType).toBeDefined() const newDescription = 'new_example_description' - const updatedContactType: IContactType = { - ...savedContactType, + const updatedPartyType: PartyType = { + ...savedPartyType, description: newDescription, } - const result: IContactType = await contactStore.updateContactType({ contactType: updatedContactType }) + const result: PartyType = await contactStore.updatePartyType({ partyType: updatedPartyType }) expect(result).toBeDefined() expect(result.description).toEqual(newDescription) }) - it('should throw error when removing contact type with unknown id', async (): Promise => { - const contactTypeId = 'unknownContactTypeId' + it('should throw error when removing party type with unknown id', async (): Promise => { + const partyTypeId = 'unknownPartyTypeId' - await expect(contactStore.removeContactType({ contactTypeId })).rejects.toThrow(`No contact type found for id: ${contactTypeId}`) + await expect(contactStore.removePartyType({ partyTypeId })).rejects.toThrow(`No party type found for id: ${partyTypeId}`) }) - it('should remove contact type', async (): Promise => { - const contactType: BasicContactType = { - type: ContactTypeEnum.PERSON, + it('should remove party type', async (): Promise => { + const partyType: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', name: 'example_name', description: 'example_description', } - const savedContactType: IContactType = await contactStore.addContactType(contactType) - expect(savedContactType).toBeDefined() + const savedPartyType: PartyType = await contactStore.addPartyType(partyType) + expect(savedPartyType).toBeDefined() - const retrievedContactType: IContactType = await contactStore.getContactType({ contactTypeId: savedContactType.id }) - expect(retrievedContactType).toBeDefined() + const resultPartyType: PartyType = await contactStore.getPartyType({ partyTypeId: savedPartyType.id }) + expect(resultPartyType).toBeDefined() - await contactStore.removeContactType({ contactTypeId: savedContactType.id }) + await contactStore.removePartyType({ partyTypeId: savedPartyType.id }) - const result: Array = await contactStore.getContactTypes() + const result: Array = await contactStore.getPartyTypes() expect(result).toBeDefined() expect(result.length).toEqual(0) }) - it('should throw error when removing contact type attached to contact', async (): Promise => { - const contact: IBasicContact = { + it('should throw error when removing party type attached to contact', async (): Promise => { + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: ContactTypeEnum.PERSON, + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', displayName: 'example_display_name', }, } - const savedContact: IContact = await contactStore.addContact(contact) - expect(savedContact).toBeDefined() + const savedParty: Party = await contactStore.addParty(party) + expect(savedParty).toBeDefined() - await expect(contactStore.removeContactType({ contactTypeId: savedContact.contactType.id })).rejects.toThrow( - `Unable to remove contact type with id: ${savedContact.contactType.id}. Contact type is in use` + await expect(contactStore.removePartyType({ partyTypeId: savedParty.partyType.id })).rejects.toThrow( + `Unable to remove party type with id: ${savedParty.partyType.id}. Party type is in use` ) }) - it('Should save contact with existing contact type', async (): Promise => { - const contactType: BasicContactType = { - type: ContactTypeEnum.PERSON, + it('Should save party with existing party type', async (): Promise => { + const partyType: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', } - const savedContactType: IContactType = await contactStore.addContactType(contactType) - expect(savedContactType).toBeDefined() + const savedPartyType: PartyType = await contactStore.addPartyType(partyType) + expect(savedPartyType).toBeDefined() - const contact: IBasicContact = { + const party: NonPersistedParty = { uri: 'example.com', - contactType: savedContactType, - contactOwner: { + partyType: savedPartyType, + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', @@ -1807,26 +1740,26 @@ describe('Contact store tests', (): void => { }, } - const result: IContact = await contactStore.addContact(contact) + const result: Party = await contactStore.addParty(party) expect(result).toBeDefined() - expect(result?.contactType).toBeDefined() - expect(result?.contactType.id).toEqual(savedContactType.id) - expect(result?.contactType.type).toEqual(savedContactType.type) - expect(result?.contactType.tenantId).toEqual(savedContactType.tenantId) - expect(result?.contactType.name).toEqual(savedContactType.name) + expect(result?.partyType).toBeDefined() + expect(result?.partyType.id).toEqual(savedPartyType.id) + expect(result?.partyType.type).toEqual(savedPartyType.type) + expect(result?.partyType.tenantId).toEqual(savedPartyType.tenantId) + expect(result?.partyType.name).toEqual(savedPartyType.name) }) - it('should throw error when adding person contact with wrong contact type', async (): Promise => { - const contactType = ContactTypeEnum.ORGANIZATION - const contact: IBasicContact = { + it('should throw error when adding person party with wrong contact type', async (): Promise => { + const partyType = PartyTypeEnum.ORGANIZATION + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: contactType, + partyType: { + type: partyType, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { firstName: 'example_first_name', middleName: 'example_middle_name', lastName: 'example_last_name', @@ -1834,25 +1767,24 @@ describe('Contact store tests', (): void => { }, } - await expect(contactStore.addContact(contact)).rejects.toThrow(`Contact type ${contactType}, does not match for provided contact owner`) + await expect(contactStore.addParty(party)).rejects.toThrow(`Party type ${partyType}, does not match for provided contact`) }) - it('should throw error when adding organization contact with wrong contact type', async (): Promise => { - const contactType = ContactTypeEnum.PERSON - const contact: IBasicContact = { + it('should throw error when adding organization party with wrong contact type', async (): Promise => { + const partyType = PartyTypeEnum.NATURAL_PERSON + const party: NonPersistedParty = { uri: 'example.com', - contactType: { - type: contactType, + partyType: { + type: partyType, tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', name: 'example_name', }, - contactOwner: { + contact: { legalName: 'example_legal_name', displayName: 'example_display_name', }, } - await expect(contactStore.addContact(contact)).rejects.toThrow(`Contact type ${contactType}, does not match for provided contact owner`) + await expect(contactStore.addParty(party)).rejects.toThrow(`Party type ${partyType}, does not match for provided contact`) }) - }) diff --git a/packages/data-store/src/contact/AbstractContactStore.ts b/packages/data-store/src/contact/AbstractContactStore.ts index 7d5ac64b2..09d04afc3 100644 --- a/packages/data-store/src/contact/AbstractContactStore.ts +++ b/packages/data-store/src/contact/AbstractContactStore.ts @@ -1,49 +1,49 @@ import { - IContact, - IIdentity, - IAddIdentityArgs, - IGetIdentityArgs, - IGetIdentitiesArgs, - IGetContactArgs, - IRemoveIdentityArgs, - IUpdateIdentityArgs, - IAddContactArgs, - IGetContactsArgs, - IRemoveContactArgs, - IUpdateContactArgs, - IAddRelationshipArgs, - IContactRelationship, - IRemoveRelationshipArgs, - IAddContactTypeArgs, - IContactType, - IGetContactTypeArgs, - IUpdateContactTypeArgs, - IGetContactTypesArgs, - IRemoveContactTypeArgs, - IGetRelationshipsArgs, - IGetRelationshipArgs, - IUpdateRelationshipArgs, + Party, + Identity, + AddIdentityArgs, + GetIdentityArgs, + GetIdentitiesArgs, + GetPartyArgs, + RemoveIdentityArgs, + UpdateIdentityArgs, + AddPartyArgs, + GetPartiesArgs, + RemovePartyArgs, + UpdatePartyArgs, + AddRelationshipArgs, + PartyRelationship, + RemoveRelationshipArgs, + AddPartyTypeArgs, + PartyType, + GetPartyTypeArgs, + UpdatePartyTypeArgs, + GetPartyTypesArgs, + RemovePartyTypeArgs, + GetRelationshipsArgs, + GetRelationshipArgs, + UpdateRelationshipArgs, } from '../types' export abstract class AbstractContactStore { - abstract getContact(args: IGetContactArgs): Promise - abstract getContacts(args?: IGetContactsArgs): Promise> - abstract addContact(args: IAddContactArgs): Promise - abstract updateContact(args: IUpdateContactArgs): Promise - abstract removeContact(args: IRemoveContactArgs): Promise - abstract getIdentity(args: IGetIdentityArgs): Promise - abstract getIdentities(args?: IGetIdentitiesArgs): Promise> - abstract addIdentity(args: IAddIdentityArgs): Promise - abstract updateIdentity(args: IUpdateIdentityArgs): Promise - abstract removeIdentity(args: IRemoveIdentityArgs): Promise - abstract getRelationship(args: IGetRelationshipArgs): Promise - abstract getRelationships(args?: IGetRelationshipsArgs): Promise> - abstract addRelationship(args: IAddRelationshipArgs): Promise - abstract updateRelationship(args: IUpdateRelationshipArgs): Promise - abstract removeRelationship(args: IRemoveRelationshipArgs): Promise - abstract getContactType(args: IGetContactTypeArgs): Promise - abstract getContactTypes(args?: IGetContactTypesArgs): Promise> - abstract addContactType(args: IAddContactTypeArgs): Promise - abstract updateContactType(args: IUpdateContactTypeArgs): Promise - abstract removeContactType(args: IRemoveContactTypeArgs): Promise + abstract getParty(args: GetPartyArgs): Promise + abstract getParties(args?: GetPartiesArgs): Promise> + abstract addParty(args: AddPartyArgs): Promise + abstract updateParty(args: UpdatePartyArgs): Promise + abstract removeParty(args: RemovePartyArgs): Promise + abstract getIdentity(args: GetIdentityArgs): Promise + abstract getIdentities(args?: GetIdentitiesArgs): Promise> + abstract addIdentity(args: AddIdentityArgs): Promise + abstract updateIdentity(args: UpdateIdentityArgs): Promise + abstract removeIdentity(args: RemoveIdentityArgs): Promise + abstract getRelationship(args: GetRelationshipArgs): Promise + abstract getRelationships(args?: GetRelationshipsArgs): Promise> + abstract addRelationship(args: AddRelationshipArgs): Promise + abstract updateRelationship(args: UpdateRelationshipArgs): Promise + abstract removeRelationship(args: RemoveRelationshipArgs): Promise + abstract getPartyType(args: GetPartyTypeArgs): Promise + abstract getPartyTypes(args?: GetPartyTypesArgs): Promise> + abstract addPartyType(args: AddPartyTypeArgs): Promise + abstract updatePartyType(args: UpdatePartyTypeArgs): Promise + abstract removePartyType(args: RemovePartyTypeArgs): Promise } diff --git a/packages/data-store/src/contact/ContactStore.ts b/packages/data-store/src/contact/ContactStore.ts index edfc39014..8b777c1c3 100644 --- a/packages/data-store/src/contact/ContactStore.ts +++ b/packages/data-store/src/contact/ContactStore.ts @@ -1,49 +1,60 @@ -import Debug from 'debug' import { OrPromise } from '@sphereon/ssi-types' +import { DataSource, In, Repository } from 'typeorm' +import Debug from 'debug' import { AbstractContactStore } from './AbstractContactStore' +import { PartyEntity } from '../entities/contact/PartyEntity' +import { IdentityEntity } from '../entities/contact/IdentityEntity' +import { IdentityMetadataItemEntity } from '../entities/contact/IdentityMetadataItemEntity' +import { CorrelationIdentifierEntity } from '../entities/contact/CorrelationIdentifierEntity' +import { ConnectionEntity } from '../entities/contact/ConnectionEntity' +import { BaseConfigEntity } from '../entities/contact/BaseConfigEntity' +import { PartyRelationshipEntity } from '../entities/contact/PartyRelationshipEntity' +import { PartyTypeEntity } from '../entities/contact/PartyTypeEntity' +import { + identityEntityFrom, + identityFrom, + isDidAuthConfig, + isNaturalPerson, + isOpenIdConfig, + isOrganization, + partyEntityFrom, + partyFrom, + partyRelationshipEntityFrom, + partyRelationshipFrom, + partyTypeEntityFrom, + partyTypeFrom, +} from '../utils/contact/MappingUtils' import { - IAddIdentityArgs, - IGetIdentityArgs, - IGetIdentitiesArgs, - IGetContactArgs, - IRemoveIdentityArgs, - IUpdateIdentityArgs, - IGetContactsArgs, - IAddContactArgs, - IUpdateContactArgs, - IRemoveContactArgs, - BasicConnectionConfig, + AddIdentityArgs, + GetIdentityArgs, + GetIdentitiesArgs, + GetPartyArgs, + RemoveIdentityArgs, + UpdateIdentityArgs, + GetPartiesArgs, + AddPartyArgs, + UpdatePartyArgs, + RemovePartyArgs, + NonPersistedConnectionConfig, ConnectionTypeEnum, CorrelationIdentifierEnum, - IContact, - IIdentity, - IRemoveRelationshipArgs, - IContactRelationship, - IAddRelationshipArgs, - IGetRelationshipArgs, - IAddContactTypeArgs, - IContactType, - IGetContactTypeArgs, - IGetContactTypesArgs, - IUpdateContactTypeArgs, - IRemoveContactTypeArgs, - IGetRelationshipsArgs, - IUpdateRelationshipArgs, - ContactTypeEnum, - BasicContactOwner + Party, + Identity, + RemoveRelationshipArgs, + PartyRelationship, + AddRelationshipArgs, + GetRelationshipArgs, + AddPartyTypeArgs, + PartyType, + GetPartyTypeArgs, + GetPartyTypesArgs, + UpdatePartyTypeArgs, + RemovePartyTypeArgs, + GetRelationshipsArgs, + UpdateRelationshipArgs, + PartyTypeEnum, + NonPersistedContact, } from '../types' -import { ContactEntity, contactEntityFrom, contactFrom } from '../entities/contact/ContactEntity' -import { IdentityEntity, identityEntityFrom, identityFrom } from '../entities/contact/IdentityEntity' -import { IdentityMetadataItemEntity } from '../entities/contact/IdentityMetadataItemEntity' -import { CorrelationIdentifierEntity } from '../entities/contact/CorrelationIdentifierEntity' -import { ConnectionEntity } from '../entities/contact/ConnectionEntity' -import { BaseConfigEntity, isDidAuthConfig, isOpenIdConfig } from '../entities/contact/BaseConfigEntity' -import { DataSource, FindOptionsWhere, In, Repository } from 'typeorm' -import { PersonEntity } from '../entities/contact/PersonEntity' -import { OrganizationEntity } from '../entities/contact/OrganizationEntity' -import { ContactRelationshipEntity, contactRelationshipEntityFrom, contactRelationshipFrom } from '../entities/contact/ContactRelationshipEntity' -import { ContactTypeEntity, contactTypeEntityFrom, contactTypeFrom } from '../entities/contact/ContactTypeEntity' -import { isOrganization, isPerson } from '../entities/contact/ContactOwnerEntity' const debug: Debug.Debugger = Debug('sphereon:ssi-sdk:contact-store') @@ -55,54 +66,40 @@ export class ContactStore extends AbstractContactStore { this.dbConnection = dbConnection } - getContact = async ({ contactId }: IGetContactArgs): Promise => { - const result: ContactEntity | null = await (await this.dbConnection).getRepository(ContactEntity).findOne({ - where: { id: contactId }, + getParty = async ({ partyId }: GetPartyArgs): Promise => { + const result: PartyEntity | null = await (await this.dbConnection).getRepository(PartyEntity).findOne({ + where: { id: partyId }, }) if (!result) { - return Promise.reject(Error(`No contact found for id: ${contactId}`)) + return Promise.reject(Error(`No party found for id: ${partyId}`)) } - return contactFrom(result) + return partyFrom(result) } - getContacts = async (args?: IGetContactsArgs): Promise> => { - const contactRepository: Repository = (await this.dbConnection).getRepository(ContactEntity) - const initialResult: Array | null = await contactRepository.find({ + getParties = async (args?: GetPartiesArgs): Promise> => { + const partyRepository: Repository = (await this.dbConnection).getRepository(PartyEntity) + const initialResult: Array = await partyRepository.find({ ...(args?.filter && { where: args?.filter }), }) - const result: Array | null = await contactRepository.find({ + const result: Array = await partyRepository.find({ where: { - id: In(initialResult.map((contact: ContactEntity) => contact.id)), + id: In(initialResult.map((party: PartyEntity) => party.id)), }, }) - return result.map((contact: ContactEntity) => contactFrom(contact)) + return result.map((party: PartyEntity) => partyFrom(party)) } - addContact = async (args: IAddContactArgs): Promise => { - const { identities, contactOwner, contactType } = args + addParty = async (args: AddPartyArgs): Promise => { + const { identities, contact, partyType } = args - const contactRepository: Repository = (await this.dbConnection).getRepository(ContactEntity) + const partyRepository: Repository = (await this.dbConnection).getRepository(PartyEntity) - if (!this.hasCorrectContactType(contactType.type, contactOwner)) { - return Promise.reject(Error(`Contact type ${contactType.type}, does not match for provided contact owner`)) - } - - const result: ContactEntity | null = await contactRepository.findOne({ - where: [ - { - contactOwner: { - displayName: contactOwner.displayName, - } as FindOptionsWhere, - }, - ], - }) - - if (result) { - return Promise.reject(Error(`Duplicate display names are not allowed. Display name: ${contactOwner.displayName}`)) + if (!this.hasCorrectPartyType(partyType.type, contact)) { + return Promise.reject(Error(`Party type ${partyType.type}, does not match for provided contact`)) } for (const identity of identities ?? []) { @@ -117,56 +114,57 @@ export class ContactStore extends AbstractContactStore { } } - const contactEntity: ContactEntity = contactEntityFrom(args) - debug('Adding contact', args) - const createdResult: ContactEntity = await contactRepository.save(contactEntity) + const partyEntity: PartyEntity = partyEntityFrom(args) + debug('Adding party', args) + const createdResult: PartyEntity = await partyRepository.save(partyEntity) - return contactFrom(createdResult) + return partyFrom(createdResult) } - updateContact = async ({ contact }: IUpdateContactArgs): Promise => { - const contactRepository: Repository = (await this.dbConnection).getRepository(ContactEntity) - const result: ContactEntity | null = await contactRepository.findOne({ - where: { id: contact.id }, + updateParty = async ({ party }: UpdatePartyArgs): Promise => { + const partyRepository: Repository = (await this.dbConnection).getRepository(PartyEntity) + const result: PartyEntity | null = await partyRepository.findOne({ + where: { id: party.id }, }) if (!result) { - return Promise.reject(Error(`No contact found for id: ${contact.id}`)) + return Promise.reject(Error(`No party found for id: ${party.id}`)) } - const updatedContact = { - ...contact, + const updatedParty = { + ...party, identities: result.identities, - contactType: result.contactType, + type: result.partyType, relationships: result.relationships, + electronicAddresses: result.electronicAddresses, } - debug('Updating contact', contact) - const updatedResult: ContactEntity = await contactRepository.save(updatedContact, { transaction: true }) + debug('Updating party', party) + const updatedResult: PartyEntity = await partyRepository.save(updatedParty, { transaction: true }) - return contactFrom(updatedResult) + return partyFrom(updatedResult) } - removeContact = async ({ contactId }: IRemoveContactArgs): Promise => { - const contactRepository: Repository = (await this.dbConnection).getRepository(ContactEntity) - debug('Removing contact', contactId) - contactRepository - .findOneById(contactId) - .then(async (contact: ContactEntity | null): Promise => { - if (!contact) { - await Promise.reject(Error(`Unable to find the contact with id to remove: ${contactId}`)) + removeParty = async ({ partyId }: RemovePartyArgs): Promise => { + const partyRepository: Repository = (await this.dbConnection).getRepository(PartyEntity) + debug('Removing party', partyId) + partyRepository + .findOneById(partyId) + .then(async (party: PartyEntity | null): Promise => { + if (!party) { + await Promise.reject(Error(`Unable to find the party with id to remove: ${partyId}`)) } else { - await this.deleteIdentities(contact.identities) + await this.deleteIdentities(party.identities) - await contactRepository - .delete({ id: contactId }) - .catch((error) => Promise.reject(Error(`Unable to remove contact with id: ${contactId}. ${error}`))) + await partyRepository + .delete({ id: partyId }) + .catch((error) => Promise.reject(Error(`Unable to remove party with id: ${partyId}. ${error}`))) } }) - .catch((error) => Promise.reject(Error(`Unable to remove contact with id: ${contactId}. ${error}`))) + .catch((error) => Promise.reject(Error(`Unable to remove party with id: ${partyId}. ${error}`))) } - getIdentity = async ({ identityId }: IGetIdentityArgs): Promise => { + getIdentity = async ({ identityId }: GetIdentityArgs): Promise => { const result: IdentityEntity | null = await (await this.dbConnection).getRepository(IdentityEntity).findOne({ where: { id: identityId }, }) @@ -178,7 +176,7 @@ export class ContactStore extends AbstractContactStore { return identityFrom(result) } - getIdentities = async (args?: IGetIdentitiesArgs): Promise> => { + getIdentities = async (args?: GetIdentitiesArgs): Promise> => { const identityRepository: Repository = (await this.dbConnection).getRepository(IdentityEntity) const initialResult: Array = await identityRepository.find({ ...(args?.filter && { where: args?.filter }), @@ -193,13 +191,13 @@ export class ContactStore extends AbstractContactStore { return result.map((identity: IdentityEntity) => identityFrom(identity)) } - addIdentity = async ({ identity, contactId }: IAddIdentityArgs): Promise => { - const contact: ContactEntity | null = await (await this.dbConnection).getRepository(ContactEntity).findOne({ - where: { id: contactId }, + addIdentity = async ({ identity, partyId }: AddIdentityArgs): Promise => { + const party: PartyEntity | null = await (await this.dbConnection).getRepository(PartyEntity).findOne({ + where: { id: partyId }, }) - if (!contact) { - return Promise.reject(Error(`No contact found for id: ${contactId}`)) + if (!party) { + return Promise.reject(Error(`No party found for id: ${partyId}`)) } if (identity.identifier.type === CorrelationIdentifierEnum.URL) { @@ -213,7 +211,7 @@ export class ContactStore extends AbstractContactStore { } const identityEntity: IdentityEntity = identityEntityFrom(identity) - identityEntity.contact = contact + identityEntity.party = party debug('Adding identity', identity) const result: IdentityEntity = await (await this.dbConnection).getRepository(IdentityEntity).save(identityEntity, { transaction: true, @@ -222,7 +220,7 @@ export class ContactStore extends AbstractContactStore { return identityFrom(result) } - updateIdentity = async ({ identity }: IUpdateIdentityArgs): Promise => { + updateIdentity = async ({ identity }: UpdateIdentityArgs): Promise => { const identityRepository: Repository = (await this.dbConnection).getRepository(IdentityEntity) const result: IdentityEntity | null = await identityRepository.findOne({ where: { id: identity.id }, @@ -248,7 +246,7 @@ export class ContactStore extends AbstractContactStore { return identityFrom(updatedResult) } - removeIdentity = async ({ identityId }: IRemoveIdentityArgs): Promise => { + removeIdentity = async ({ identityId }: RemoveIdentityArgs): Promise => { const identity: IdentityEntity | null = await (await this.dbConnection).getRepository(IdentityEntity).findOne({ where: { id: identityId }, }) @@ -262,36 +260,22 @@ export class ContactStore extends AbstractContactStore { await this.deleteIdentities([identity]) } - addRelationship = async ({ leftId, rightId }: IAddRelationshipArgs): Promise => { - const contactRepository: Repository = (await this.dbConnection).getRepository(ContactEntity) - const leftContact: ContactEntity | null = await contactRepository.findOne({ - where: { id: leftId }, - }) - - if (!leftContact) { - return Promise.reject(Error(`No contact found for left contact id: ${leftId}`)) - } - - const rightContact: ContactEntity | null = await contactRepository.findOne({ - where: { id: rightId }, - }) + addRelationship = async ({ leftId, rightId }: AddRelationshipArgs): Promise => { + return this.assertRelationshipSides(leftId, rightId).then(async (): Promise => { + const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ + leftId, + rightId, + }) + debug('Adding party relationship', relationship) - if (!rightContact) { - return Promise.reject(Error(`No contact found for right contact id: ${rightId}`)) - } + const createdResult: PartyRelationshipEntity = await (await this.dbConnection).getRepository(PartyRelationshipEntity).save(relationship) - const relationship: ContactRelationshipEntity = contactRelationshipEntityFrom({ - leftId: leftContact.id, - rightId: rightContact.id, + return partyRelationshipFrom(createdResult) }) - - const createdResult: ContactRelationshipEntity = await (await this.dbConnection).getRepository(ContactRelationshipEntity).save(relationship) - - return contactRelationshipFrom(createdResult) } - getRelationship = async ({ relationshipId }: IGetRelationshipArgs): Promise => { - const result: ContactRelationshipEntity | null = await (await this.dbConnection).getRepository(ContactRelationshipEntity).findOne({ + getRelationship = async ({ relationshipId }: GetRelationshipArgs): Promise => { + const result: PartyRelationshipEntity | null = await (await this.dbConnection).getRepository(PartyRelationshipEntity).findOne({ where: { id: relationshipId }, }) @@ -299,60 +283,45 @@ export class ContactStore extends AbstractContactStore { return Promise.reject(Error(`No relationship found for id: ${relationshipId}`)) } - return contactRelationshipFrom(result) + return partyRelationshipFrom(result) } - getRelationships = async (args?: IGetRelationshipsArgs): Promise> => { - const contactRelationshipRepository: Repository = (await this.dbConnection).getRepository(ContactRelationshipEntity) - const initialResult: Array | null = await contactRelationshipRepository.find({ + getRelationships = async (args?: GetRelationshipsArgs): Promise> => { + const partyRelationshipRepository: Repository = (await this.dbConnection).getRepository(PartyRelationshipEntity) + const initialResult: Array = await partyRelationshipRepository.find({ ...(args?.filter && { where: args?.filter }), }) - const result: Array | null = await contactRelationshipRepository.find({ + const result: Array = await partyRelationshipRepository.find({ where: { - id: In(initialResult.map((contactRelationship: ContactRelationshipEntity) => contactRelationship.id)), + id: In(initialResult.map((partyRelationship: PartyRelationshipEntity) => partyRelationship.id)), }, }) - return result.map((contactRelationship: ContactRelationshipEntity) => contactRelationshipFrom(contactRelationship)) + return result.map((partyRelationship: PartyRelationshipEntity) => partyRelationshipFrom(partyRelationship)) } - updateRelationship = async ({ relationship }: IUpdateRelationshipArgs): Promise => { - const contactRelationshipRepository: Repository = (await this.dbConnection).getRepository(ContactRelationshipEntity) - const result: ContactRelationshipEntity | null = await contactRelationshipRepository.findOne({ + updateRelationship = async ({ relationship }: UpdateRelationshipArgs): Promise => { + const partyRelationshipRepository: Repository = (await this.dbConnection).getRepository(PartyRelationshipEntity) + const result: PartyRelationshipEntity | null = await partyRelationshipRepository.findOne({ where: { id: relationship.id }, }) if (!result) { - return Promise.reject(Error(`No contact relationship found for id: ${relationship.id}`)) + return Promise.reject(Error(`No party relationship found for id: ${relationship.id}`)) } - const contactRepository: Repository = (await this.dbConnection).getRepository(ContactEntity) - const leftContact: ContactEntity | null = await contactRepository.findOne({ - where: { id: relationship.leftId }, - }) + return this.assertRelationshipSides(relationship.leftId, relationship.rightId).then(async (): Promise => { + debug('Updating party relationship', relationship) + const updatedResult: PartyRelationshipEntity = await partyRelationshipRepository.save(relationship, { transaction: true }) - if (!leftContact) { - return Promise.reject(Error(`No contact found for left contact id: ${relationship.leftId}`)) - } - - const rightContact: ContactEntity | null = await contactRepository.findOne({ - where: { id: relationship.rightId }, + return partyRelationshipFrom(updatedResult) }) - - if (!rightContact) { - return Promise.reject(Error(`No contact found for right contact id: ${relationship.rightId}`)) - } - - debug('Updating contact relationship', relationship) - const updatedResult: ContactRelationshipEntity = await contactRelationshipRepository.save(relationship, { transaction: true }) - - return contactRelationshipFrom(updatedResult) } - removeRelationship = async ({ relationshipId }: IRemoveRelationshipArgs): Promise => { - const contactRelationshipRepository: Repository = (await this.dbConnection).getRepository(ContactRelationshipEntity) - const relationship: ContactRelationshipEntity | null = await contactRelationshipRepository.findOne({ + removeRelationship = async ({ relationshipId }: RemoveRelationshipArgs): Promise => { + const partyRelationshipRepository: Repository = (await this.dbConnection).getRepository(PartyRelationshipEntity) + const relationship: PartyRelationshipEntity | null = await partyRelationshipRepository.findOne({ where: { id: relationshipId }, }) @@ -362,88 +331,88 @@ export class ContactStore extends AbstractContactStore { debug('Removing relationship', relationshipId) - await contactRelationshipRepository.delete(relationshipId) + await partyRelationshipRepository.delete(relationshipId) } - addContactType = async (args: IAddContactTypeArgs): Promise => { - const contactEntity: ContactTypeEntity = contactTypeEntityFrom(args) - debug('Adding contact type', args) - const createdResult: ContactTypeEntity = await (await this.dbConnection).getRepository(ContactTypeEntity).save(contactEntity) + addPartyType = async (args: AddPartyTypeArgs): Promise => { + const partyEntity: PartyTypeEntity = partyTypeEntityFrom(args) + debug('Adding party type', args) + const createdResult: PartyTypeEntity = await (await this.dbConnection).getRepository(PartyTypeEntity).save(partyEntity) - return contactTypeFrom(createdResult) + return partyTypeFrom(createdResult) } - getContactType = async ({ contactTypeId }: IGetContactTypeArgs): Promise => { - const result: ContactTypeEntity | null = await (await this.dbConnection).getRepository(ContactTypeEntity).findOne({ - where: { id: contactTypeId }, + getPartyType = async ({ partyTypeId }: GetPartyTypeArgs): Promise => { + const result: PartyTypeEntity | null = await (await this.dbConnection).getRepository(PartyTypeEntity).findOne({ + where: { id: partyTypeId }, }) if (!result) { - return Promise.reject(Error(`No contact type found for id: ${contactTypeId}`)) + return Promise.reject(Error(`No party type found for id: ${partyTypeId}`)) } - return contactTypeFrom(result) + return partyTypeFrom(result) } - getContactTypes = async (args?: IGetContactTypesArgs): Promise> => { - const contactTypeRepository: Repository = (await this.dbConnection).getRepository(ContactTypeEntity) - const initialResult: Array | null = await contactTypeRepository.find({ + getPartyTypes = async (args?: GetPartyTypesArgs): Promise> => { + const partyTypeRepository: Repository = (await this.dbConnection).getRepository(PartyTypeEntity) + const initialResult: Array = await partyTypeRepository.find({ ...(args?.filter && { where: args?.filter }), }) - const result: Array | null = await contactTypeRepository.find({ + const result: Array = await partyTypeRepository.find({ where: { - id: In(initialResult.map((contactType: ContactTypeEntity) => contactType.id)), + id: In(initialResult.map((partyType: PartyTypeEntity) => partyType.id)), }, }) - return result.map((contactType: ContactTypeEntity) => contactTypeFrom(contactType)) + return result.map((partyType: PartyTypeEntity) => partyTypeFrom(partyType)) } - updateContactType = async ({ contactType }: IUpdateContactTypeArgs): Promise => { - const contactTypeRepository: Repository = (await this.dbConnection).getRepository(ContactTypeEntity) - const result: ContactTypeEntity | null = await contactTypeRepository.findOne({ - where: { id: contactType.id }, + updatePartyType = async ({ partyType }: UpdatePartyTypeArgs): Promise => { + const partyTypeRepository: Repository = (await this.dbConnection).getRepository(PartyTypeEntity) + const result: PartyTypeEntity | null = await partyTypeRepository.findOne({ + where: { id: partyType.id }, }) if (!result) { - return Promise.reject(Error(`No contact type found for id: ${contactType.id}`)) + return Promise.reject(Error(`No party type found for id: ${partyType.id}`)) } - debug('Updating contact type', contactType) - const updatedResult: ContactTypeEntity = await contactTypeRepository.save(contactType, { transaction: true }) + debug('Updating party type', partyType) + const updatedResult: PartyTypeEntity = await partyTypeRepository.save(partyType, { transaction: true }) - return contactTypeFrom(updatedResult) + return partyTypeFrom(updatedResult) } - removeContactType = async ({ contactTypeId }: IRemoveContactTypeArgs): Promise => { - const contacts: Array | null = await (await this.dbConnection).getRepository(ContactEntity).find({ + removePartyType = async ({ partyTypeId }: RemovePartyTypeArgs): Promise => { + const parties: Array = await (await this.dbConnection).getRepository(PartyEntity).find({ where: { - contactType: { - id: contactTypeId, + partyType: { + id: partyTypeId, }, }, }) - if (contacts?.length > 0) { - return Promise.reject(Error(`Unable to remove contact type with id: ${contactTypeId}. Contact type is in use`)) + if (parties.length > 0) { + return Promise.reject(Error(`Unable to remove party type with id: ${partyTypeId}. Party type is in use`)) } - const contactTypeRepository: Repository = (await this.dbConnection).getRepository(ContactTypeEntity) - const contactType: ContactTypeEntity | null = await contactTypeRepository.findOne({ - where: { id: contactTypeId }, + const partyTypeRepository: Repository = (await this.dbConnection).getRepository(PartyTypeEntity) + const partyType: PartyTypeEntity | null = await partyTypeRepository.findOne({ + where: { id: partyTypeId }, }) - if (!contactType) { - return Promise.reject(Error(`No contact type found for id: ${contactTypeId}`)) + if (!partyType) { + return Promise.reject(Error(`No party type found for id: ${partyTypeId}`)) } - debug('Removing contact type', contactTypeId) + debug('Removing party type', partyTypeId) - await contactTypeRepository.delete(contactTypeId) + await partyTypeRepository.delete(partyTypeId) } - private hasCorrectConnectionConfig(type: ConnectionTypeEnum, config: BasicConnectionConfig): boolean { + private hasCorrectConnectionConfig(type: ConnectionTypeEnum, config: NonPersistedConnectionConfig): boolean { switch (type) { case ConnectionTypeEnum.OPENID_CONNECT: return isOpenIdConfig(config) @@ -454,14 +423,14 @@ export class ContactStore extends AbstractContactStore { } } - private hasCorrectContactType(type: ContactTypeEnum, owner: BasicContactOwner): boolean { + private hasCorrectPartyType(type: PartyTypeEnum, contact: NonPersistedContact): boolean { switch (type) { - case ContactTypeEnum.PERSON: - return isPerson(owner) - case ContactTypeEnum.ORGANIZATION: - return isOrganization(owner) + case PartyTypeEnum.NATURAL_PERSON: + return isNaturalPerson(contact) + case PartyTypeEnum.ORGANIZATION: + return isOrganization(contact) default: - throw new Error('Contact type not supported') + throw new Error('Party type not supported') } } @@ -505,4 +474,22 @@ export class ContactStore extends AbstractContactStore { }) } + private async assertRelationshipSides(leftId: string, rightId: string): Promise { + const partyRepository: Repository = (await this.dbConnection).getRepository(PartyEntity) + const leftParty: PartyEntity | null = await partyRepository.findOne({ + where: { id: leftId }, + }) + + if (!leftParty) { + return Promise.reject(Error(`No party found for left side of the relationship, party id: ${leftId}`)) + } + + const rightParty: PartyEntity | null = await partyRepository.findOne({ + where: { id: rightId }, + }) + + if (!rightParty) { + return Promise.reject(Error(`No party found for right side of the relationship, party id: ${rightId}`)) + } + } } diff --git a/packages/data-store/src/entities/contact/BaseConfigEntity.ts b/packages/data-store/src/entities/contact/BaseConfigEntity.ts index 0999eebe9..aa371f67f 100644 --- a/packages/data-store/src/entities/contact/BaseConfigEntity.ts +++ b/packages/data-store/src/entities/contact/BaseConfigEntity.ts @@ -1,55 +1,16 @@ -import { BaseEntity, Entity, PrimaryGeneratedColumn, TableInheritance } from 'typeorm' -import { - BasicConnectionConfig, - ConnectionConfig, - IDidAuthConfig, - IOpenIdConfig -} from '../../types' -import { OpenIdConfigEntity } from './OpenIdConfigEntity' -import { DidAuthConfigEntity } from './DidAuthConfigEntity' +import { BaseEntity, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn, TableInheritance } from 'typeorm' +import { ConnectionEntity } from './ConnectionEntity' -@Entity('BaseConfigEntity') // FIXME rename it to 'BaseConfig' +@Entity('BaseConfig') @TableInheritance({ column: { type: 'varchar', name: 'type' } }) export abstract class BaseConfigEntity extends BaseEntity { @PrimaryGeneratedColumn('uuid') id!: string -} - -export const configFrom = (config: BaseConfigEntity): ConnectionConfig => { - if (isOpenIdConfig(config)) { - return openIdConfigFrom(config) - } else if (isDidAuthConfig(config)) { - return didAuthConfigFrom(config) - } - - throw new Error('config type not supported') -} -export const openIdConfigFrom = (config: OpenIdConfigEntity): IOpenIdConfig => { - return { - id: config.id, - clientId: config.clientId, - clientSecret: config.clientSecret, - scopes: config.scopes, - issuer: config.issuer, - redirectUrl: config.redirectUrl, - dangerouslyAllowInsecureHttpRequests: config.dangerouslyAllowInsecureHttpRequests, - clientAuthMethod: config.clientAuthMethod, - } + @OneToOne(() => ConnectionEntity, (connection: ConnectionEntity) => connection.config, { + cascade: ['insert', 'update'], + onDelete: 'CASCADE', + }) + @JoinColumn({ name: 'connection_id' }) + connection?: ConnectionEntity } - -export const didAuthConfigFrom = (config: DidAuthConfigEntity): IDidAuthConfig => { - return { - id: config.id, - identifier: { did: config.identifier, provider: '', keys: [], services: [] }, - stateId: '', // FIXME - redirectUrl: config.redirectUrl, - sessionId: config.sessionId, - } -} - -export const isOpenIdConfig = (config: BasicConnectionConfig | BaseConfigEntity): config is IOpenIdConfig | OpenIdConfigEntity => - 'clientSecret' in config && 'issuer' in config && 'redirectUrl' in config - -export const isDidAuthConfig = (config: BasicConnectionConfig | BaseConfigEntity): config is IDidAuthConfig | DidAuthConfigEntity => - 'identifier' in config && 'redirectUrl' in config && 'sessionId' in config diff --git a/packages/data-store/src/entities/contact/BaseContactEntity.ts b/packages/data-store/src/entities/contact/BaseContactEntity.ts new file mode 100644 index 000000000..64f219243 --- /dev/null +++ b/packages/data-store/src/entities/contact/BaseContactEntity.ts @@ -0,0 +1,21 @@ +import { BaseEntity, CreateDateColumn, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn, TableInheritance, UpdateDateColumn } from 'typeorm' +import { PartyEntity } from './PartyEntity' + +@Entity('BaseContact') +@TableInheritance({ column: { type: 'varchar', name: 'type' } }) +export abstract class BaseContactEntity extends BaseEntity { + @PrimaryGeneratedColumn('uuid') + id!: string + + @CreateDateColumn({ name: 'created_at', nullable: false }) + createdAt!: Date + + @UpdateDateColumn({ name: 'last_updated_at', nullable: false }) + lastUpdatedAt!: Date + + @OneToOne(() => PartyEntity, (party: PartyEntity) => party.contact, { + onDelete: 'CASCADE', + }) + @JoinColumn({ name: 'party_id' }) + party!: PartyEntity +} diff --git a/packages/data-store/src/entities/contact/ConnectionEntity.ts b/packages/data-store/src/entities/contact/ConnectionEntity.ts index ef568e5a8..1c4daecf0 100644 --- a/packages/data-store/src/entities/contact/ConnectionEntity.ts +++ b/packages/data-store/src/entities/contact/ConnectionEntity.ts @@ -1,20 +1,9 @@ import { Entity, Column, PrimaryGeneratedColumn, OneToOne, JoinColumn, BaseEntity } from 'typeorm' -import { - BaseConfigEntity, - configFrom, isDidAuthConfig, isOpenIdConfig -} from './BaseConfigEntity' -import { - BasicConnectionConfig, - BasicDidAuthConfig, BasicOpenIdConfig, - ConnectionTypeEnum, IBasicConnection, IConnection -} from '../../types' +import { BaseConfigEntity } from './BaseConfigEntity' +import { ConnectionTypeEnum } from '../../types' import { IdentityEntity } from './IdentityEntity' -import { - OpenIdConfigEntity, openIdConfigEntityFrom -} from './OpenIdConfigEntity' -import { - DidAuthConfigEntity, didAuthConfigEntityFrom -} from './DidAuthConfigEntity' +import { OpenIdConfigEntity } from './OpenIdConfigEntity' +import { DidAuthConfigEntity } from './DidAuthConfigEntity' @Entity('Connection') export class ConnectionEntity extends BaseEntity { @@ -35,32 +24,6 @@ export class ConnectionEntity extends BaseEntity { @OneToOne(() => IdentityEntity, (identity: IdentityEntity) => identity.connection, { onDelete: 'CASCADE', }) - @JoinColumn({ name: 'identityId' }) + @JoinColumn({ name: 'identity_id' }) identity!: IdentityEntity } - -export const connectionEntityFrom = (connection: IBasicConnection): ConnectionEntity => { - const connectionEntity: ConnectionEntity = new ConnectionEntity() - connectionEntity.type = connection.type - connectionEntity.config = configEntityFrom(connection.config) - - return connectionEntity -} - -export const connectionFrom = (connection: ConnectionEntity): IConnection => { - return { - id: connection.id, - type: connection.type, - config: configFrom(connection.config), - } -} - -const configEntityFrom = (config: BasicConnectionConfig): BaseConfigEntity => { - if (isOpenIdConfig(config)) { - return openIdConfigEntityFrom(config) - } else if (isDidAuthConfig(config)) { - return didAuthConfigEntityFrom(config) - } - - throw new Error('config type not supported') -} diff --git a/packages/data-store/src/entities/contact/ContactEntity.ts b/packages/data-store/src/entities/contact/ContactEntity.ts deleted file mode 100644 index 9d55fe8fb..000000000 --- a/packages/data-store/src/entities/contact/ContactEntity.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { - BaseEntity, - BeforeInsert, - BeforeUpdate, - Column, - CreateDateColumn, - Entity, - FindOptionsWhere, - JoinColumn, - ManyToOne, - OneToMany, - OneToOne, - PrimaryGeneratedColumn, - UpdateDateColumn, -} from 'typeorm' -import { - BasicContactOwner, - BasicOrganization, - BasicPerson, - ContactOwner, - IBasicContact, - IBasicIdentity, - IContact, - ValidationConstraint -} from '../../types' -import { IdentityEntity, identityEntityFrom, identityFrom } from './IdentityEntity' -import { validate, ValidationError } from 'class-validator' -import { ContactTypeEntity, contactTypeEntityFrom, contactTypeFrom } from './ContactTypeEntity' -import { - ContactOwnerEntity, - isOrganization, - isPerson -} from './ContactOwnerEntity' -import { PersonEntity, personEntityFrom, personFrom } from './PersonEntity' -import { OrganizationEntity, organizationEntityFrom, organizationFrom } from './OrganizationEntity' -import { ContactRelationshipEntity, contactRelationshipFrom } from './ContactRelationshipEntity' -import { getConstraint } from '../../utils/ValidatorUtils' - -@Entity('Contact') -export class ContactEntity extends BaseEntity { - @PrimaryGeneratedColumn('uuid') - id!: string - - @Column({ name: 'uri', length: 255 }) - uri?: string - - @OneToMany(() => IdentityEntity, (identity: IdentityEntity) => identity.contact, { - cascade: true, - onDelete: 'CASCADE', - eager: true, - nullable: false, - }) - @JoinColumn({ name: 'identityId' }) - identities!: Array - - @ManyToOne(() => ContactTypeEntity, (contactType: ContactTypeEntity) => contactType.contacts, { - cascade: true, - nullable: false, - eager: true, - }) - @JoinColumn({ name: 'contactTypeId' }) - contactType!: ContactTypeEntity - - @OneToOne(() => ContactOwnerEntity, (owner: PersonEntity | OrganizationEntity) => owner.contact, { - cascade: true, - onDelete: 'CASCADE', - eager: true, - nullable: false, - }) - contactOwner!: ContactOwnerEntity - - @OneToMany(() => ContactRelationshipEntity, (relationship: ContactRelationshipEntity) => relationship.left, { - cascade: true, - onDelete: 'CASCADE', - eager: true, - nullable: false, - }) - @JoinColumn({ name: 'relationshipId' }) - relationships!: Array - - @CreateDateColumn({ name: 'created_at', nullable: false }) - createdAt!: Date - - @UpdateDateColumn({ name: 'last_updated_at', nullable: false }) - lastUpdatedAt!: Date - - @BeforeInsert() - @BeforeUpdate() - async checkUniqueCocNumberAndTenantId(): Promise { - const result: Array = await ContactEntity.find({ - where: { - contactOwner: { - cocNumber: (this.contactOwner).cocNumber, - } as FindOptionsWhere, - contactType: { - tenantId: this.contactType.tenantId, - }, - }, - }) - - if (result?.length > 0) { - return Promise.reject(Error('Coc number already in use')) - } - - return - } - - @BeforeInsert() - @BeforeUpdate() - async validate(): Promise { - const validation: Array = await validate(this) - if (validation.length > 0) { - const constraint: ValidationConstraint | undefined = getConstraint(validation[0]) - if (constraint) { - const message: string = Object.values(constraint!)[0] - return Promise.reject(Error(message)) - } - } - } -} - -export const contactEntityFrom = (contact: IBasicContact): ContactEntity => { - const contactEntity: ContactEntity = new ContactEntity() - contactEntity.uri = contact.uri - contactEntity.identities = contact.identities ? contact.identities.map((identity: IBasicIdentity) => identityEntityFrom(identity)) : [] - contactEntity.contactType = contactTypeEntityFrom(contact.contactType) - contactEntity.contactOwner = contactOwnerEntityFrom(contact.contactOwner) - - return contactEntity -} - -export const contactFrom = (contact: ContactEntity): IContact => { - return { - id: contact.id, - uri: contact.uri, - roles: [...new Set(contact.identities?.flatMap((identity: IdentityEntity) => identity.roles))] ?? [], - identities: contact.identities ? contact.identities.map((identity: IdentityEntity) => identityFrom(identity)) : [], - relationships: contact.relationships - ? contact.relationships.map((relationship: ContactRelationshipEntity) => contactRelationshipFrom(relationship)) - : [], - contactType: contactTypeFrom(contact.contactType), - contactOwner: contactOwnerFrom(contact.contactOwner), - createdAt: contact.createdAt, - lastUpdatedAt: contact.lastUpdatedAt, - } -} - -export const contactOwnerEntityFrom = (owner: BasicContactOwner): ContactOwnerEntity => { - if (isPerson(owner)) { - return personEntityFrom(owner) - } else if (isOrganization(owner)) { - return organizationEntityFrom(owner) - } - - throw new Error('Owner type not supported') -} - -export const contactOwnerFrom = (owner: ContactOwnerEntity): ContactOwner => { - if (isPerson(owner)) { - return personFrom(owner) - } else if (isOrganization(owner)) { - return organizationFrom(owner) - } - - throw new Error('Owner type not supported') -} diff --git a/packages/data-store/src/entities/contact/ContactOwnerEntity.ts b/packages/data-store/src/entities/contact/ContactOwnerEntity.ts deleted file mode 100644 index 18bb16a74..000000000 --- a/packages/data-store/src/entities/contact/ContactOwnerEntity.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { BaseEntity, CreateDateColumn, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn, TableInheritance, UpdateDateColumn } from 'typeorm' -import { ContactEntity } from './ContactEntity' -import { BasicContactOwner, BasicOrganization, BasicPerson } from '../../types' -import { PersonEntity } from './PersonEntity' -import { OrganizationEntity } from './OrganizationEntity' - -@Entity('ContactOwner') -@TableInheritance({ column: { type: 'varchar', name: 'type' } }) -export abstract class ContactOwnerEntity extends BaseEntity { - @PrimaryGeneratedColumn('uuid') - id!: string - - @CreateDateColumn({ name: 'created_at', nullable: false }) - createdAt!: Date - - @UpdateDateColumn({ name: 'last_updated_at', nullable: false }) - lastUpdatedAt!: Date - - @OneToOne(() => ContactEntity, (contact: ContactEntity) => contact.contactOwner, { - onDelete: 'CASCADE', - }) - @JoinColumn({ name: 'contactId' }) - contact!: ContactEntity -} - -export const isPerson = (owner: BasicContactOwner | ContactOwnerEntity): owner is BasicPerson | PersonEntity => - 'firstName' in owner && 'middleName' in owner && 'lastName' in owner - -export const isOrganization = (owner: BasicContactOwner | ContactOwnerEntity): owner is BasicOrganization | OrganizationEntity => 'legalName' in owner diff --git a/packages/data-store/src/entities/contact/ContactRelationshipEntity.ts b/packages/data-store/src/entities/contact/ContactRelationshipEntity.ts deleted file mode 100644 index 2177dccdd..000000000 --- a/packages/data-store/src/entities/contact/ContactRelationshipEntity.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { - Entity, - PrimaryGeneratedColumn, - CreateDateColumn, - UpdateDateColumn, - ManyToOne, - Column, - Index, - BeforeInsert, - BeforeUpdate, -} from 'typeorm' -import { ContactEntity } from './ContactEntity' -import { BasicContactRelationship, IContactRelationship } from '../../types' - -@Entity('ContactRelationship') -@Index('IDX_ContactRelationshipEntity_left_right', ['left', 'right'], { unique: true }) -export class ContactRelationshipEntity { - @PrimaryGeneratedColumn('uuid') - id!: string - - @ManyToOne(() => ContactEntity, { - nullable: false, - onDelete: 'CASCADE', - }) - left!: ContactEntity - - @Column({ name: 'leftId', nullable: false }) - leftId!: string - - @ManyToOne(() => ContactEntity, { - nullable: false, - onDelete: 'CASCADE', - }) - right!: ContactEntity - - @Column({ name: 'rightId', nullable: false }) - rightId!: string - - @CreateDateColumn({ name: 'created_at', nullable: false }) - createdAt!: Date - - @UpdateDateColumn({ name: 'last_updated_at', nullable: false }) - lastUpdatedAt!: Date - - @BeforeInsert() - @BeforeUpdate() - async checkRelationshipSides(): Promise { - if ((this.left?.id ?? this.leftId) === (this.right?.id ?? this.rightId)) { - return Promise.reject(Error('Cannot use the same id for both sides of the relationship')) - } - } -} - -export const contactRelationshipEntityFrom = (relationship: BasicContactRelationship): ContactRelationshipEntity => { - const contactRelationshipEntity: ContactRelationshipEntity = new ContactRelationshipEntity() - contactRelationshipEntity.leftId = relationship.leftId - contactRelationshipEntity.rightId = relationship.rightId - - return contactRelationshipEntity -} - -export const contactRelationshipFrom = (relationship: ContactRelationshipEntity): IContactRelationship => { - return { - id: relationship.id, - leftId: relationship.leftId, - rightId: relationship.rightId, - createdAt: relationship.createdAt, - lastUpdatedAt: relationship.lastUpdatedAt, - } -} diff --git a/packages/data-store/src/entities/contact/CorrelationIdentifierEntity.ts b/packages/data-store/src/entities/contact/CorrelationIdentifierEntity.ts index 2df6ddab3..5bcd4abd6 100644 --- a/packages/data-store/src/entities/contact/CorrelationIdentifierEntity.ts +++ b/packages/data-store/src/entities/contact/CorrelationIdentifierEntity.ts @@ -1,5 +1,5 @@ import { Entity, Column, PrimaryGeneratedColumn, BaseEntity, OneToOne, JoinColumn, BeforeInsert, BeforeUpdate } from 'typeorm' -import { CorrelationIdentifierEnum, BasicCorrelationIdentifier, ICorrelationIdentifier, ValidationConstraint } from '../../types' +import { CorrelationIdentifierEnum, ValidationConstraint } from '../../types' import { IdentityEntity } from './IdentityEntity' import { IsNotEmpty, validate, ValidationError } from 'class-validator' import { getConstraint } from '../../utils/ValidatorUtils' @@ -19,7 +19,7 @@ export class CorrelationIdentifierEntity extends BaseEntity { @OneToOne(() => IdentityEntity, (identity: IdentityEntity) => identity.identifier, { onDelete: 'CASCADE', }) - @JoinColumn({ name: 'identityId' }) + @JoinColumn({ name: 'identity_id' }) identity!: IdentityEntity @BeforeInsert() @@ -35,19 +35,3 @@ export class CorrelationIdentifierEntity extends BaseEntity { } } } - -export const correlationIdentifierEntityFrom = (identifier: BasicCorrelationIdentifier): CorrelationIdentifierEntity => { - const identifierEntity: CorrelationIdentifierEntity = new CorrelationIdentifierEntity() - identifierEntity.type = identifier.type - identifierEntity.correlationId = identifier.correlationId - - return identifierEntity -} - -export const correlationIdentifierFrom = (identifier: CorrelationIdentifierEntity): ICorrelationIdentifier => { - return { - id: identifier.id, - type: identifier.type, - correlationId: identifier.correlationId, - } -} diff --git a/packages/data-store/src/entities/contact/DidAuthConfigEntity.ts b/packages/data-store/src/entities/contact/DidAuthConfigEntity.ts index ff2827c2e..29685ba61 100644 --- a/packages/data-store/src/entities/contact/DidAuthConfigEntity.ts +++ b/packages/data-store/src/entities/contact/DidAuthConfigEntity.ts @@ -1,7 +1,5 @@ -import { ChildEntity, Column, JoinColumn, OneToOne } from 'typeorm' +import { ChildEntity, Column } from 'typeorm' import { BaseConfigEntity } from './BaseConfigEntity' -import { BasicDidAuthConfig } from '../../types' -import { ConnectionEntity } from './ConnectionEntity' @ChildEntity('DidAuthConfig') export class DidAuthConfigEntity extends BaseConfigEntity { @@ -13,20 +11,4 @@ export class DidAuthConfigEntity extends BaseConfigEntity { @Column({ name: 'session_id', length: 255, nullable: false }) sessionId!: string - - // TODO can we move this to the base entity? - @OneToOne(() => ConnectionEntity, (connection: ConnectionEntity) => connection.config, { - onDelete: 'CASCADE', - }) - @JoinColumn({ name: 'connectionId' }) - connection?: ConnectionEntity -} - -export const didAuthConfigEntityFrom = (config: BasicDidAuthConfig): DidAuthConfigEntity => { - const didAuthConfig: DidAuthConfigEntity = new DidAuthConfigEntity() - didAuthConfig.identifier = config.identifier.did - didAuthConfig.redirectUrl = config.redirectUrl - didAuthConfig.sessionId = config.sessionId - - return didAuthConfig } diff --git a/packages/data-store/src/entities/contact/ElectronicAddressEntity.ts b/packages/data-store/src/entities/contact/ElectronicAddressEntity.ts new file mode 100644 index 000000000..d2d60914e --- /dev/null +++ b/packages/data-store/src/entities/contact/ElectronicAddressEntity.ts @@ -0,0 +1,53 @@ +import { IsNotEmpty, validate, ValidationError } from 'class-validator' +import { + Entity, + Column, + PrimaryGeneratedColumn, + BaseEntity, + ManyToOne, + BeforeInsert, + BeforeUpdate, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm' +import { PartyEntity } from './PartyEntity' +import { getConstraint } from '../../utils/ValidatorUtils' +import { ElectronicAddressType, ValidationConstraint } from '../../types' + +@Entity('ElectronicAddress') +export class ElectronicAddressEntity extends BaseEntity { + @PrimaryGeneratedColumn('uuid') + id!: string + + @Column({ name: 'type', length: 255, nullable: false }) + @IsNotEmpty({ message: 'Blank electronic address types are not allowed' }) + type!: ElectronicAddressType + + @Column({ name: 'electronic_address', length: 255, nullable: false }) + @IsNotEmpty({ message: 'Blank electronic addresses are not allowed' }) + electronicAddress!: string + + @ManyToOne(() => PartyEntity, (party: PartyEntity) => party.electronicAddresses, { + onDelete: 'CASCADE', + }) + party!: PartyEntity + + @CreateDateColumn({ name: 'created_at', nullable: false }) + createdAt!: Date + + @UpdateDateColumn({ name: 'last_updated_at', nullable: false }) + lastUpdatedAt!: Date + + @BeforeInsert() + @BeforeUpdate() + async validate(): Promise { + const validation: Array = await validate(this) + if (validation.length > 0) { + const constraint: ValidationConstraint | undefined = getConstraint(validation[0]) + if (constraint) { + const message: string = Object.values(constraint!)[0] + return Promise.reject(Error(message)) + } + } + } +} diff --git a/packages/data-store/src/entities/contact/IdentityEntity.ts b/packages/data-store/src/entities/contact/IdentityEntity.ts index 43765906f..c81dcad19 100644 --- a/packages/data-store/src/entities/contact/IdentityEntity.ts +++ b/packages/data-store/src/entities/contact/IdentityEntity.ts @@ -13,11 +13,11 @@ import { BeforeUpdate, } from 'typeorm' import { IsNotEmpty, validate, ValidationError } from 'class-validator' -import { correlationIdentifierEntityFrom, CorrelationIdentifierEntity, correlationIdentifierFrom } from './CorrelationIdentifierEntity' -import { ConnectionEntity, connectionEntityFrom, connectionFrom } from './ConnectionEntity' -import { IdentityMetadataItemEntity, metadataItemEntityFrom, metadataItemFrom } from './IdentityMetadataItemEntity' -import { BasicMetadataItem, IBasicIdentity, IdentityRoleEnum, IIdentity, ValidationConstraint } from '../../types' -import { ContactEntity } from './ContactEntity' +import { CorrelationIdentifierEntity } from './CorrelationIdentifierEntity' +import { ConnectionEntity } from './ConnectionEntity' +import { IdentityMetadataItemEntity } from './IdentityMetadataItemEntity' +import { IdentityRoleEnum, ValidationConstraint } from '../../types' +import { PartyEntity } from './PartyEntity' import { getConstraint } from '../../utils/ValidatorUtils' @Entity('Identity') @@ -58,7 +58,7 @@ export class IdentityEntity extends BaseEntity { eager: true, nullable: false, }) - @JoinColumn({ name: 'metadataId' }) + @JoinColumn({ name: 'metadata_id' }) metadata!: Array @CreateDateColumn({ name: 'created_at', nullable: false }) @@ -67,13 +67,15 @@ export class IdentityEntity extends BaseEntity { @UpdateDateColumn({ name: 'last_updated_at', nullable: false }) lastUpdatedAt!: Date - @ManyToOne(() => ContactEntity, (contact: ContactEntity) => contact.identities, { + @ManyToOne(() => PartyEntity, (party: PartyEntity) => party.identities, { onDelete: 'CASCADE', }) - contact!: ContactEntity + party!: PartyEntity - @Column({ name: 'contactId', nullable: true }) - contactId!: string + // TODO name should be party_id + // TODO add reverse side column name to owning side party + @Column({ name: 'partyId', nullable: true }) + partyId!: string @BeforeInsert() @BeforeUpdate() @@ -88,27 +90,3 @@ export class IdentityEntity extends BaseEntity { } } } - -export const identityEntityFrom = (args: IBasicIdentity): IdentityEntity => { - const identityEntity: IdentityEntity = new IdentityEntity() - identityEntity.alias = args.alias - identityEntity.roles = args.roles - identityEntity.identifier = correlationIdentifierEntityFrom(args.identifier) - identityEntity.connection = args.connection ? connectionEntityFrom(args.connection) : undefined - identityEntity.metadata = args.metadata ? args.metadata.map((item: BasicMetadataItem) => metadataItemEntityFrom(item)) : [] - - return identityEntity -} - -export const identityFrom = (identity: IdentityEntity): IIdentity => { - return { - id: identity.id, - alias: identity.alias, - roles: identity.roles, - identifier: correlationIdentifierFrom(identity.identifier), - ...(identity.connection && { connection: connectionFrom(identity.connection) }), - metadata: identity.metadata ? identity.metadata.map((item: IdentityMetadataItemEntity) => metadataItemFrom(item)) : [], - createdAt: identity.createdAt, - lastUpdatedAt: identity.createdAt, - } -} diff --git a/packages/data-store/src/entities/contact/IdentityMetadataItemEntity.ts b/packages/data-store/src/entities/contact/IdentityMetadataItemEntity.ts index 187da329d..025c75399 100644 --- a/packages/data-store/src/entities/contact/IdentityMetadataItemEntity.ts +++ b/packages/data-store/src/entities/contact/IdentityMetadataItemEntity.ts @@ -1,5 +1,5 @@ import { Entity, Column, PrimaryGeneratedColumn, BaseEntity, ManyToOne, BeforeInsert, BeforeUpdate } from 'typeorm' -import { BasicMetadataItem, IMetadataItem, ValidationConstraint } from '../../types' +import { ValidationConstraint } from '../../types' import { IdentityEntity } from './IdentityEntity' import { IsNotEmpty, validate, ValidationError } from 'class-validator' import { getConstraint } from '../../utils/ValidatorUtils' @@ -33,19 +33,3 @@ export class IdentityMetadataItemEntity extends BaseEntity { } } } - -export const metadataItemEntityFrom = (item: BasicMetadataItem): IdentityMetadataItemEntity => { - const metadataItem: IdentityMetadataItemEntity = new IdentityMetadataItemEntity() - metadataItem.label = item.label - metadataItem.value = item.value - - return metadataItem -} - -export const metadataItemFrom = (item: IdentityMetadataItemEntity): IMetadataItem => { - return { - id: item.id, - label: item.label, - value: item.value, - } -} diff --git a/packages/data-store/src/entities/contact/NaturalPersonEntity.ts b/packages/data-store/src/entities/contact/NaturalPersonEntity.ts new file mode 100644 index 000000000..b04089bbb --- /dev/null +++ b/packages/data-store/src/entities/contact/NaturalPersonEntity.ts @@ -0,0 +1,38 @@ +import { Column, ChildEntity, BeforeInsert, BeforeUpdate } from 'typeorm' +import { BaseContactEntity } from './BaseContactEntity' +import { ValidationConstraint } from '../../types' +import { validate, IsNotEmpty, ValidationError, Validate } from 'class-validator' +import { IsNonEmptyStringConstraint } from '../validators' +import { getConstraint } from '../../utils/ValidatorUtils' + +@ChildEntity('NaturalPerson') +export class NaturalPersonEntity extends BaseContactEntity { + @Column({ name: 'first_name', length: 255, nullable: false, unique: false }) + @IsNotEmpty({ message: 'Blank first names are not allowed' }) + firstName!: string + + @Column({ name: 'middle_name', length: 255, nullable: true, unique: false }) + @Validate(IsNonEmptyStringConstraint, { message: 'Blank middle names are not allowed' }) + middleName?: string + + @Column({ name: 'last_name', length: 255, nullable: false, unique: false }) + @IsNotEmpty({ message: 'Blank last names are not allowed' }) + lastName!: string + + @Column({ name: 'display_name', length: 255, nullable: false, unique: false }) + @IsNotEmpty({ message: 'Blank display names are not allowed' }) + displayName!: string + + @BeforeInsert() + @BeforeUpdate() + async validate(): Promise { + const validation: Array = await validate(this) + if (validation.length > 0) { + const constraint: ValidationConstraint | undefined = getConstraint(validation[0]) + if (constraint) { + const message: string = Object.values(constraint!)[0] + return Promise.reject(Error(message)) + } + } + } +} diff --git a/packages/data-store/src/entities/contact/OpenIdConfigEntity.ts b/packages/data-store/src/entities/contact/OpenIdConfigEntity.ts index 44ba141bf..07871ed4c 100644 --- a/packages/data-store/src/entities/contact/OpenIdConfigEntity.ts +++ b/packages/data-store/src/entities/contact/OpenIdConfigEntity.ts @@ -1,7 +1,5 @@ -import { ChildEntity, Column, JoinColumn, OneToOne } from 'typeorm' +import { ChildEntity, Column } from 'typeorm' import { BaseConfigEntity } from './BaseConfigEntity' -import { BasicOpenIdConfig } from '../../types' -import { ConnectionEntity } from './ConnectionEntity' @ChildEntity('OpenIdConfig') export class OpenIdConfigEntity extends BaseConfigEntity { @@ -25,24 +23,4 @@ export class OpenIdConfigEntity extends BaseConfigEntity { @Column('text', { name: 'client_auth_method', nullable: false }) clientAuthMethod!: 'basic' | 'post' | undefined - - @OneToOne(() => ConnectionEntity, (connection: ConnectionEntity) => connection.config, { - cascade: ['insert', 'update'], - onDelete: 'CASCADE', - }) - @JoinColumn({ name: 'connectionId' }) - connection?: ConnectionEntity -} - -export const openIdConfigEntityFrom = (config: BasicOpenIdConfig): OpenIdConfigEntity => { - const openIdConfig: OpenIdConfigEntity = new OpenIdConfigEntity() - openIdConfig.clientId = config.clientId - openIdConfig.clientSecret = config.clientSecret - openIdConfig.scopes = config.scopes - openIdConfig.issuer = config.issuer - openIdConfig.redirectUrl = config.redirectUrl - openIdConfig.dangerouslyAllowInsecureHttpRequests = config.dangerouslyAllowInsecureHttpRequests - openIdConfig.clientAuthMethod = config.clientAuthMethod - - return openIdConfig } diff --git a/packages/data-store/src/entities/contact/OrganizationEntity.ts b/packages/data-store/src/entities/contact/OrganizationEntity.ts index e0e856a0d..e20a38ec7 100644 --- a/packages/data-store/src/entities/contact/OrganizationEntity.ts +++ b/packages/data-store/src/entities/contact/OrganizationEntity.ts @@ -1,28 +1,23 @@ import { JoinColumn, OneToOne, Column, ChildEntity, BeforeInsert, BeforeUpdate } from 'typeorm' -import { ContactEntity } from './ContactEntity' -import { ContactOwnerEntity } from './ContactOwnerEntity' -import { BasicOrganization, IOrganization, ValidationConstraint } from '../../types' -import { validate, IsNotEmpty, ValidationError, Validate } from 'class-validator' -import { IsNonEmptyStringConstraint } from '../validators' +import { PartyEntity } from './PartyEntity' +import { BaseContactEntity } from './BaseContactEntity' +import { ValidationConstraint } from '../../types' +import { validate, IsNotEmpty, ValidationError } from 'class-validator' import { getConstraint } from '../../utils/ValidatorUtils' @ChildEntity('Organization') -export class OrganizationEntity extends ContactOwnerEntity { - @Column({ name: 'legalName', length: 255, nullable: false, unique: true }) +export class OrganizationEntity extends BaseContactEntity { + @Column({ name: 'legal_name', length: 255, nullable: false, unique: true }) @IsNotEmpty({ message: 'Blank legal names are not allowed' }) legalName!: string - @Column({ name: 'displayName', length: 255, nullable: false, unique: true }) + @Column({ name: 'display_name', length: 255, nullable: false, unique: false }) @IsNotEmpty({ message: 'Blank display names are not allowed' }) displayName!: string - @Column({ name: 'cocNumber', length: 255, nullable: true, unique: false }) - @Validate(IsNonEmptyStringConstraint, { message: 'Blank coc numbers are not allowed' }) - cocNumber?: string - - @OneToOne(() => ContactEntity) - @JoinColumn({ name: 'contactId' }) - contact!: ContactEntity + @OneToOne(() => PartyEntity) + @JoinColumn({ name: 'contact_id' }) + contact!: PartyEntity @BeforeInsert() @BeforeUpdate() @@ -37,23 +32,3 @@ export class OrganizationEntity extends ContactOwnerEntity { } } } - -export const organizationEntityFrom = (organization: BasicOrganization): OrganizationEntity => { - const organizationEntity: OrganizationEntity = new OrganizationEntity() - organizationEntity.legalName = organization.legalName - organizationEntity.displayName = organization.displayName - organizationEntity.cocNumber = organization.cocNumber - - return organizationEntity -} - -export const organizationFrom = (organization: OrganizationEntity): IOrganization => { - return { - id: organization.id, - legalName: organization.legalName, - displayName: organization.displayName, - cocNumber: organization.cocNumber, - createdAt: organization.createdAt, - lastUpdatedAt: organization.lastUpdatedAt, - } -} diff --git a/packages/data-store/src/entities/contact/PartyEntity.ts b/packages/data-store/src/entities/contact/PartyEntity.ts new file mode 100644 index 000000000..db7adc9de --- /dev/null +++ b/packages/data-store/src/entities/contact/PartyEntity.ts @@ -0,0 +1,111 @@ +import { + BaseEntity, + BeforeInsert, + BeforeUpdate, + Column, + CreateDateColumn, + Entity, + JoinColumn, + ManyToOne, + OneToMany, + OneToOne, + PrimaryGeneratedColumn, + UpdateDateColumn, +} from 'typeorm' +import { ValidationConstraint } from '../../types' +import { IdentityEntity } from './IdentityEntity' +import { validate, ValidationError } from 'class-validator' +import { PartyTypeEntity } from './PartyTypeEntity' +import { BaseContactEntity } from './BaseContactEntity' +import { PartyRelationshipEntity } from './PartyRelationshipEntity' +import { getConstraint } from '../../utils/ValidatorUtils' +import { ElectronicAddressEntity } from './ElectronicAddressEntity' + +@Entity('Party') +export class PartyEntity extends BaseEntity { + @PrimaryGeneratedColumn('uuid') + id!: string + + @Column({ name: 'uri', length: 255 }) + uri?: string + + @OneToMany(() => IdentityEntity, (identity: IdentityEntity) => identity.party, { + cascade: true, + onDelete: 'CASCADE', + eager: true, + nullable: false, + }) + @JoinColumn({ name: 'identity_id' }) + identities!: Array + + @OneToMany(() => ElectronicAddressEntity, (electronicAddress: ElectronicAddressEntity) => electronicAddress.party, { + cascade: true, + onDelete: 'CASCADE', + eager: true, + nullable: false, + }) + @JoinColumn({ name: 'electronic_address_id' }) + electronicAddresses!: Array + + @ManyToOne(() => PartyTypeEntity, (contactType: PartyTypeEntity) => contactType.parties, { + cascade: true, + nullable: false, + eager: true, + }) + @JoinColumn({ name: 'party_type_id' }) + partyType!: PartyTypeEntity + + @OneToOne(() => BaseContactEntity, (contact: BaseContactEntity) => contact.party, { + cascade: true, + onDelete: 'CASCADE', + eager: true, + nullable: false, + }) + contact!: BaseContactEntity + + @OneToMany(() => PartyRelationshipEntity, (relationship: PartyRelationshipEntity) => relationship.left, { + cascade: true, + onDelete: 'CASCADE', + eager: true, + nullable: false, + }) + @JoinColumn({ name: 'relationship_id' }) + relationships!: Array + + @CreateDateColumn({ name: 'created_at', nullable: false }) + createdAt!: Date + + @UpdateDateColumn({ name: 'last_updated_at', nullable: false }) + lastUpdatedAt!: Date + + @BeforeInsert() + @BeforeUpdate() + async checkUniqueTenantId(): Promise { + const result: Array = await PartyEntity.find({ + where: { + partyType: { + tenantId: this.partyType.tenantId, + }, + }, + }) + + if (result?.length > 0) { + return Promise.reject(Error('Tenant id already in use')) + } + + return + } + + @BeforeInsert() + @BeforeUpdate() + async validate(): Promise { + const validation: Array = await validate(this) + if (validation.length > 0) { + const constraint: ValidationConstraint | undefined = getConstraint(validation[0]) + if (constraint) { + const message: string = Object.values(constraint!)[0] + return Promise.reject(Error(message)) + } + } + } +} diff --git a/packages/data-store/src/entities/contact/PartyRelationshipEntity.ts b/packages/data-store/src/entities/contact/PartyRelationshipEntity.ts new file mode 100644 index 000000000..d50946fe0 --- /dev/null +++ b/packages/data-store/src/entities/contact/PartyRelationshipEntity.ts @@ -0,0 +1,54 @@ +import { + Entity, + PrimaryGeneratedColumn, + CreateDateColumn, + UpdateDateColumn, + ManyToOne, + Column, + Index, + BeforeInsert, + BeforeUpdate, + JoinColumn, +} from 'typeorm' +import { PartyEntity } from './PartyEntity' + +@Entity('PartyRelationship') +@Index('IDX_PartyRelationshipEntity_left_right', ['left', 'right'], { unique: true }) +export class PartyRelationshipEntity { + @PrimaryGeneratedColumn('uuid') + id!: string + + @ManyToOne(() => PartyEntity, { + nullable: false, + onDelete: 'CASCADE', + }) + @JoinColumn({ name: 'left_id' }) + left!: PartyEntity + + @Column({ name: 'left_id', nullable: false }) + leftId!: string + + @ManyToOne(() => PartyEntity, { + nullable: false, + onDelete: 'CASCADE', + }) + @JoinColumn({ name: 'right_id' }) + right!: PartyEntity + + @Column({ name: 'right_id', nullable: false }) + rightId!: string + + @CreateDateColumn({ name: 'created_at', nullable: false }) + createdAt!: Date + + @UpdateDateColumn({ name: 'last_updated_at', nullable: false }) + lastUpdatedAt!: Date + + @BeforeInsert() + @BeforeUpdate() + async checkRelationshipSides(): Promise { + if ((this.left?.id ?? this.leftId) === (this.right?.id ?? this.rightId)) { + return Promise.reject(Error('Cannot use the same id for both sides of the relationship')) + } + } +} diff --git a/packages/data-store/src/entities/contact/ContactTypeEntity.ts b/packages/data-store/src/entities/contact/PartyTypeEntity.ts similarity index 50% rename from packages/data-store/src/entities/contact/ContactTypeEntity.ts rename to packages/data-store/src/entities/contact/PartyTypeEntity.ts index 42462a5d3..3de7c9b79 100644 --- a/packages/data-store/src/entities/contact/ContactTypeEntity.ts +++ b/packages/data-store/src/entities/contact/PartyTypeEntity.ts @@ -1,18 +1,18 @@ import { Entity, PrimaryGeneratedColumn, Column, Index, CreateDateColumn, UpdateDateColumn, OneToMany, BeforeInsert, BeforeUpdate } from 'typeorm' -import { ContactEntity } from './ContactEntity' -import { BasicContactType, ContactTypeEnum, IContactType, ValidationConstraint } from '../../types' +import { PartyEntity } from './PartyEntity' +import { PartyTypeEnum, ValidationConstraint } from '../../types' import { IsNotEmpty, Validate, validate, ValidationError } from 'class-validator' import { IsNonEmptyStringConstraint } from '../validators' import { getConstraint } from '../../utils/ValidatorUtils' -@Entity('ContactType') -@Index('IDX_ContactTypeEntity_type_tenantId', ['type', 'tenantId'], { unique: true }) // TODO use name for migrations -export class ContactTypeEntity { +@Entity('PartyType') +@Index('IDX_PartyTypeEntity_type_tenantId', ['type', 'tenantId'], { unique: true }) // TODO use name for migrations +export class PartyTypeEntity { @PrimaryGeneratedColumn('uuid') id!: string - @Column('simple-enum', { name: 'type', enum: ContactTypeEnum, nullable: false, unique: false }) - type!: ContactTypeEnum + @Column('simple-enum', { name: 'type', enum: PartyTypeEnum, nullable: false, unique: false }) + type!: PartyTypeEnum @Column({ name: 'name', length: 255, nullable: false, unique: true }) @IsNotEmpty({ message: 'Blank names are not allowed' }) @@ -22,14 +22,14 @@ export class ContactTypeEntity { @Validate(IsNonEmptyStringConstraint, { message: 'Blank descriptions are not allowed' }) description?: string - @Column({ name: 'tenantId', length: 255, nullable: false, unique: false }) + @Column({ name: 'tenant_id', length: 255, nullable: false, unique: false }) @IsNotEmpty({ message: "Blank tenant id's are not allowed" }) tenantId!: string - @OneToMany(() => ContactEntity, (contact: ContactEntity) => contact.contactType, { + @OneToMany(() => PartyEntity, (party: PartyEntity) => party.partyType, { nullable: false, }) - contacts!: Array + parties!: Array @CreateDateColumn({ name: 'created_at', nullable: false }) createdAt!: Date @@ -50,28 +50,3 @@ export class ContactTypeEntity { } } } - -export const contactTypeEntityFrom = (args: BasicContactType): ContactTypeEntity => { - const contactTypeEntity: ContactTypeEntity = new ContactTypeEntity() - if (args.id) { - contactTypeEntity.id = args.id - } - contactTypeEntity.type = args.type - contactTypeEntity.name = args.name - contactTypeEntity.description = args.description - contactTypeEntity.tenantId = args.tenantId - - return contactTypeEntity -} - -export const contactTypeFrom = (contactType: ContactTypeEntity): IContactType => { - return { - id: contactType.id, - type: contactType.type, - name: contactType.name, - tenantId: contactType.tenantId, - description: contactType.description, - createdAt: contactType.createdAt, - lastUpdatedAt: contactType.lastUpdatedAt, - } -} diff --git a/packages/data-store/src/entities/contact/PersonEntity.ts b/packages/data-store/src/entities/contact/PersonEntity.ts deleted file mode 100644 index 45f2f2501..000000000 --- a/packages/data-store/src/entities/contact/PersonEntity.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { Column, ChildEntity, BeforeInsert, BeforeUpdate } from 'typeorm' -import { ContactOwnerEntity } from './ContactOwnerEntity' -import { BasicPerson, IPerson, ValidationConstraint } from '../../types' -import { validate, IsNotEmpty, ValidationError, Validate } from 'class-validator' -import { IsNonEmptyStringConstraint } from '../validators' -import { getConstraint } from '../../utils/ValidatorUtils' - -@ChildEntity('Person') -export class PersonEntity extends ContactOwnerEntity { - @Column({ name: 'firstName', length: 255, nullable: false, unique: false }) - @IsNotEmpty({ message: 'Blank first names are not allowed' }) - firstName!: string - - @Column({ name: 'middleName', length: 255, nullable: true, unique: false }) - @Validate(IsNonEmptyStringConstraint, { message: 'Blank middle names are not allowed' }) - middleName?: string - - @Column({ name: 'lastName', length: 255, nullable: false, unique: false }) - @IsNotEmpty({ message: 'Blank last names are not allowed' }) - lastName!: string - - @Column({ name: 'displayName', length: 255, nullable: false, unique: true }) - @IsNotEmpty({ message: 'Blank display names are not allowed' }) - displayName!: string - - @BeforeInsert() - @BeforeUpdate() - async validate(): Promise { - const validation: Array = await validate(this) - if (validation.length > 0) { - const constraint: ValidationConstraint | undefined = getConstraint(validation[0]) - if (constraint) { - const message: string = Object.values(constraint!)[0] - return Promise.reject(Error(message)) - } - } - } -} - -export const personEntityFrom = (person: BasicPerson): PersonEntity => { - const personEntity: PersonEntity = new PersonEntity() - personEntity.firstName = person.firstName - personEntity.middleName = person.middleName - personEntity.lastName = person.lastName - personEntity.displayName = person.displayName - - return personEntity -} - -export const personFrom = (person: PersonEntity): IPerson => { - return { - id: person.id, - firstName: person.firstName, - middleName: person.middleName, - lastName: person.lastName, - displayName: person.displayName, - createdAt: person.createdAt, - lastUpdatedAt: person.lastUpdatedAt, - } -} diff --git a/packages/data-store/src/index.ts b/packages/data-store/src/index.ts index 97dc8e202..a84bb6802 100644 --- a/packages/data-store/src/index.ts +++ b/packages/data-store/src/index.ts @@ -1,12 +1,13 @@ import { BaseConfigEntity } from './entities/contact/BaseConfigEntity' import { BaseLocaleBrandingEntity } from './entities/issuanceBranding/BaseLocaleBrandingEntity' -import { ConnectionEntity, connectionEntityFrom } from './entities/contact/ConnectionEntity' -import { ContactEntity, contactEntityFrom } from './entities/contact/ContactEntity' -import { CorrelationIdentifierEntity, correlationIdentifierEntityFrom } from './entities/contact/CorrelationIdentifierEntity' -import { DidAuthConfigEntity, didAuthConfigEntityFrom } from './entities/contact/DidAuthConfigEntity' -import { IdentityEntity, identityEntityFrom } from './entities/contact/IdentityEntity' -import { IdentityMetadataItemEntity, metadataItemEntityFrom } from './entities/contact/IdentityMetadataItemEntity' -import { OpenIdConfigEntity, openIdConfigEntityFrom } from './entities/contact/OpenIdConfigEntity' +import { BaseContactEntity } from './entities/contact/BaseContactEntity' +import { ConnectionEntity } from './entities/contact/ConnectionEntity' +import { PartyEntity } from './entities/contact/PartyEntity' +import { CorrelationIdentifierEntity } from './entities/contact/CorrelationIdentifierEntity' +import { DidAuthConfigEntity } from './entities/contact/DidAuthConfigEntity' +import { IdentityEntity } from './entities/contact/IdentityEntity' +import { IdentityMetadataItemEntity } from './entities/contact/IdentityMetadataItemEntity' +import { OpenIdConfigEntity } from './entities/contact/OpenIdConfigEntity' import { BackgroundAttributesEntity, backgroundAttributesEntityFrom } from './entities/issuanceBranding/BackgroundAttributesEntity' import { CredentialBrandingEntity, credentialBrandingEntityFrom } from './entities/issuanceBranding/CredentialBrandingEntity' import { CredentialLocaleBrandingEntity, credentialLocaleBrandingEntityFrom } from './entities/issuanceBranding/CredentialLocaleBrandingEntity' @@ -15,12 +16,25 @@ import { ImageDimensionsEntity, imageDimensionsEntityFrom } from './entities/iss import { IssuerLocaleBrandingEntity, issuerLocaleBrandingEntityFrom } from './entities/issuanceBranding/IssuerLocaleBrandingEntity' import { IssuerBrandingEntity, issuerBrandingEntityFrom } from './entities/issuanceBranding/IssuerBrandingEntity' import { TextAttributesEntity, textAttributesEntityFrom } from './entities/issuanceBranding/TextAttributesEntity' -import { ContactRelationshipEntity, contactRelationshipEntityFrom } from './entities/contact/ContactRelationshipEntity' -import { ContactTypeEntity, contactTypeEntityFrom } from './entities/contact/ContactTypeEntity' -import { ContactOwnerEntity } from './entities/contact/ContactOwnerEntity' -import { OrganizationEntity, organizationEntityFrom } from './entities/contact/OrganizationEntity' -import { PersonEntity, personEntityFrom } from './entities/contact/PersonEntity' - +import { PartyRelationshipEntity } from './entities/contact/PartyRelationshipEntity' +import { PartyTypeEntity } from './entities/contact/PartyTypeEntity' +import { OrganizationEntity } from './entities/contact/OrganizationEntity' +import { NaturalPersonEntity } from './entities/contact/NaturalPersonEntity' +import { ElectronicAddressEntity } from './entities/contact/ElectronicAddressEntity' +import { + connectionEntityFrom, + correlationIdentifierEntityFrom, + didAuthConfigEntityFrom, + electronicAddressEntityFrom, + identityEntityFrom, + metadataItemEntityFrom, + naturalPersonEntityFrom, + openIdConfigEntityFrom, + organizationEntityFrom, + partyEntityFrom, + partyRelationshipEntityFrom, + partyTypeEntityFrom, +} from './utils/contact/MappingUtils' export { ContactStore } from './contact/ContactStore' export { AbstractContactStore } from './contact/AbstractContactStore' export { AbstractIssuanceBrandingStore } from './issuanceBranding/AbstractIssuanceBrandingStore' @@ -31,17 +45,18 @@ export * from './types' export const DataStoreContactEntities = [ BaseConfigEntity, ConnectionEntity, - ContactEntity, + PartyEntity, IdentityEntity, IdentityMetadataItemEntity, CorrelationIdentifierEntity, DidAuthConfigEntity, OpenIdConfigEntity, - ContactRelationshipEntity, - ContactTypeEntity, - ContactOwnerEntity, + PartyRelationshipEntity, + PartyTypeEntity, + BaseContactEntity, OrganizationEntity, - PersonEntity, + NaturalPersonEntity, + ElectronicAddressEntity, ] export const DataStoreIssuanceBrandingEntities = [ @@ -59,7 +74,7 @@ export const DataStoreIssuanceBrandingEntities = [ export { BaseConfigEntity, ConnectionEntity, - ContactEntity, + PartyEntity, CorrelationIdentifierEntity, DidAuthConfigEntity, IdentityEntity, @@ -74,9 +89,10 @@ export { TextAttributesEntity, CredentialLocaleBrandingEntity, IssuerLocaleBrandingEntity, + ElectronicAddressEntity, metadataItemEntityFrom, connectionEntityFrom, - contactEntityFrom, + partyEntityFrom, correlationIdentifierEntityFrom, identityEntityFrom, didAuthConfigEntityFrom, @@ -89,8 +105,9 @@ export { textAttributesEntityFrom, issuerLocaleBrandingEntityFrom, credentialLocaleBrandingEntityFrom, - contactRelationshipEntityFrom, - contactTypeEntityFrom, + partyRelationshipEntityFrom, + partyTypeEntityFrom, organizationEntityFrom, - personEntityFrom, + naturalPersonEntityFrom, + electronicAddressEntityFrom, } diff --git a/packages/data-store/src/migrations/generic/2-CreateContacts.ts b/packages/data-store/src/migrations/generic/2-CreateContacts.ts index 5d5fa990e..90c913404 100644 --- a/packages/data-store/src/migrations/generic/2-CreateContacts.ts +++ b/packages/data-store/src/migrations/generic/2-CreateContacts.ts @@ -13,8 +13,7 @@ export class CreateContacts1690925872318 implements MigrationInterface { const dbType: DatabaseType = queryRunner.connection.driver.options.type switch (dbType) { - case 'postgres': - { + case 'postgres': { debug('using postgres migration file') const mig: CreateContacts1690925872592 = new CreateContacts1690925872592() await mig.up(queryRunner) @@ -22,8 +21,7 @@ export class CreateContacts1690925872318 implements MigrationInterface { return } case 'sqlite': - case 'react-native': - { + case 'react-native': { debug('using sqlite/react-native migration file') const mig: CreateContacts1690925872693 = new CreateContacts1690925872693() await mig.up(queryRunner) @@ -42,8 +40,7 @@ export class CreateContacts1690925872318 implements MigrationInterface { const dbType: DatabaseType = queryRunner.connection.driver.options.type switch (dbType) { - case 'postgres': - { + case 'postgres': { debug('using postgres migration file') const mig: CreateContacts1690925872592 = new CreateContacts1690925872592() await mig.down(queryRunner) @@ -51,8 +48,7 @@ export class CreateContacts1690925872318 implements MigrationInterface { return } case 'sqlite': - case 'react-native': - { + case 'react-native': { debug('using sqlite/react-native migration file') const mig: CreateContacts1690925872693 = new CreateContacts1690925872693() await mig.down(queryRunner) diff --git a/packages/data-store/src/migrations/generic/index.ts b/packages/data-store/src/migrations/generic/index.ts index 36fbd54f8..cb9034231 100644 --- a/packages/data-store/src/migrations/generic/index.ts +++ b/packages/data-store/src/migrations/generic/index.ts @@ -9,8 +9,4 @@ import { CreateIssuanceBranding1659463079429 } from './1-CreateIssuanceBranding' * * @public */ -export const DataStoreMigrations = [ - CreateContacts1659463079429, - CreateContacts1690925872318, - CreateIssuanceBranding1659463079429 -] +export const DataStoreMigrations = [CreateContacts1659463079429, CreateContacts1690925872318, CreateIssuanceBranding1659463079429] diff --git a/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts b/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts index 1d7e362ab..ccfe15f81 100644 --- a/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts +++ b/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts @@ -5,92 +5,160 @@ export class CreateContacts1690925872693 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise { await queryRunner.query(`DROP INDEX "IDX_BaseConfigEntity_type"`) - await queryRunner.query(`CREATE TABLE "temporary_BaseConfigEntity" ("id" varchar PRIMARY KEY NOT NULL, "client_id" varchar(255), "client_secret" varchar(255), "scopes" text, "issuer" varchar(255), "redirect_url" text, "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "identifier" varchar(255), "session_id" varchar(255), "type" varchar NOT NULL, "connectionId" varchar, CONSTRAINT "REL_BaseConfig_connectionId" UNIQUE ("connectionId"))`) - await queryRunner.query(`INSERT INTO "temporary_BaseConfigEntity"("id", "client_id", "client_secret", "scopes", "issuer", "redirect_url", "dangerously_allow_insecure_http_requests", "client_auth_method", "identifier", "session_id", "type", "connectionId") SELECT "id", "client_id", "client_secret", "scopes", "issuer", "redirect_url", "dangerously_allow_insecure_http_requests", "client_auth_method", "identifier", "session_id", "type", "connectionId" FROM "BaseConfigEntity"`) + await queryRunner.query( + `CREATE TABLE "temporary_BaseConfigEntity" ("id" varchar PRIMARY KEY NOT NULL, "client_id" varchar(255), "client_secret" varchar(255), "scopes" text, "issuer" varchar(255), "redirect_url" text, "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "identifier" varchar(255), "session_id" varchar(255), "type" varchar NOT NULL, "connectionId" varchar, CONSTRAINT "REL_BaseConfig_connectionId" UNIQUE ("connectionId"))` + ) + await queryRunner.query( + `INSERT INTO "temporary_BaseConfigEntity"("id", "client_id", "client_secret", "scopes", "issuer", "redirect_url", "dangerously_allow_insecure_http_requests", "client_auth_method", "identifier", "session_id", "type", "connectionId") SELECT "id", "client_id", "client_secret", "scopes", "issuer", "redirect_url", "dangerously_allow_insecure_http_requests", "client_auth_method", "identifier", "session_id", "type", "connectionId" FROM "BaseConfigEntity"` + ) await queryRunner.query(`DROP TABLE "BaseConfigEntity"`) await queryRunner.query(`ALTER TABLE "temporary_BaseConfigEntity" RENAME TO "BaseConfigEntity"`) await queryRunner.query(`CREATE INDEX "IDX_BaseConfigEntity_type" ON "BaseConfigEntity" ("type")`) - await queryRunner.query(`CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identityId" varchar, CONSTRAINT "REL_CorrelationIdentifier_identityId" UNIQUE ("identityId"), CONSTRAINT "UQ_Correlation_id" UNIQUE ("correlation_id"))`) - await queryRunner.query(`INSERT INTO "temporary_CorrelationIdentifier"("id", "type", "correlation_id", "identityId") SELECT "id", "type", "correlation_id", "identityId" FROM "CorrelationIdentifier"`) + await queryRunner.query( + `CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identityId" varchar, CONSTRAINT "REL_CorrelationIdentifier_identityId" UNIQUE ("identityId"), CONSTRAINT "UQ_Correlation_id" UNIQUE ("correlation_id"))` + ) + await queryRunner.query( + `INSERT INTO "temporary_CorrelationIdentifier"("id", "type", "correlation_id", "identityId") SELECT "id", "type", "correlation_id", "identityId" FROM "CorrelationIdentifier"` + ) await queryRunner.query(`DROP TABLE "CorrelationIdentifier"`) await queryRunner.query(`ALTER TABLE "temporary_CorrelationIdentifier" RENAME TO "CorrelationIdentifier"`) - await queryRunner.query(`CREATE TABLE "temporary_IdentityMetadata" ("id" varchar PRIMARY KEY NOT NULL, "label" varchar(255) NOT NULL, "value" varchar(255) NOT NULL, "identityId" varchar)`) - await queryRunner.query(`INSERT INTO "temporary_IdentityMetadata"("id", "label", "value", "identityId") SELECT "id", "label", "value", "identityId" FROM "IdentityMetadata"`) + await queryRunner.query( + `CREATE TABLE "temporary_IdentityMetadata" ("id" varchar PRIMARY KEY NOT NULL, "label" varchar(255) NOT NULL, "value" varchar(255) NOT NULL, "identityId" varchar)` + ) + await queryRunner.query( + `INSERT INTO "temporary_IdentityMetadata"("id", "label", "value", "identityId") SELECT "id", "label", "value", "identityId" FROM "IdentityMetadata"` + ) await queryRunner.query(`DROP TABLE "IdentityMetadata"`) await queryRunner.query(`ALTER TABLE "temporary_IdentityMetadata" RENAME TO "IdentityMetadata"`) - await queryRunner.query(`CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Alias" UNIQUE ("alias"))`) - await queryRunner.query(`INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"`) + await queryRunner.query( + `CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Alias" UNIQUE ("alias"))` + ) + await queryRunner.query( + `INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"` + ) await queryRunner.query(`DROP TABLE "Identity"`) await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) - await queryRunner.query(`CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identityId" varchar, CONSTRAINT "REL_Connection_identityId" UNIQUE ("identityId"))`) + await queryRunner.query( + `CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identityId" varchar, CONSTRAINT "REL_Connection_identityId" UNIQUE ("identityId"))` + ) await queryRunner.query(`INSERT INTO "temporary_Connection"("id", "type", "identityId") SELECT "id", "type", "identityId" FROM "Connection"`) await queryRunner.query(`DROP TABLE "Connection"`) await queryRunner.query(`ALTER TABLE "temporary_Connection" RENAME TO "Connection"`) await queryRunner.query(`DROP INDEX "IDX_BaseConfigEntity_type"`) - await queryRunner.query(`CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Alias" UNIQUE ("alias"))`) - await queryRunner.query(`INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"`) + await queryRunner.query( + `CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Alias" UNIQUE ("alias"))` + ) + await queryRunner.query( + `INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"` + ) await queryRunner.query(`DROP TABLE "Identity"`) await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) - await queryRunner.query(`CREATE TABLE "ContactType" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('person','organization') ) NOT NULL, "name" varchar(255) NOT NULL, "description" varchar(255), "tenantId" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "UQ_2229e0d8c1e6817efcc982a6dde" UNIQUE ("name"))`) + await queryRunner.query( + `CREATE TABLE "ContactType" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('person','organization') ) NOT NULL, "name" varchar(255) NOT NULL, "description" varchar(255), "tenantId" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "UQ_2229e0d8c1e6817efcc982a6dde" UNIQUE ("name"))` + ) await queryRunner.query(`CREATE UNIQUE INDEX "IDX_1a1fa2aa0a56649427e427a41f" ON "ContactType" ("type", "tenantId")`) - await queryRunner.query(`CREATE TABLE "ContactOwner" ("id" varchar PRIMARY KEY NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "firstName" varchar(255), "middleName" varchar(255), "lastName" varchar(255), "displayName" varchar(255), "legalName" varchar(255), "cocNumber" varchar(255), "type" varchar NOT NULL, "contactId" varchar, CONSTRAINT "UQ_9177af8a51a2a0598d3a8c68e1e" UNIQUE ("displayName"), CONSTRAINT "UQ_91bf22d2597ff429ece6ae807aa" UNIQUE ("legalName"), CONSTRAINT "UQ_9177af8a51a2a0598d3a8c68e1e" UNIQUE ("displayName"), CONSTRAINT "REL_26ce21b29da1426fa1198b947e" UNIQUE ("contactId"))`) + await queryRunner.query( + `CREATE TABLE "ContactOwner" ("id" varchar PRIMARY KEY NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "firstName" varchar(255), "middleName" varchar(255), "lastName" varchar(255), "displayName" varchar(255), "legalName" varchar(255), "type" varchar NOT NULL, "contactId" varchar, CONSTRAINT "UQ_9177af8a51a2a0598d3a8c68e1e" UNIQUE ("displayName"), CONSTRAINT "UQ_91bf22d2597ff429ece6ae807aa" UNIQUE ("legalName"), CONSTRAINT "UQ_9177af8a51a2a0598d3a8c68e1e" UNIQUE ("displayName"), CONSTRAINT "REL_26ce21b29da1426fa1198b947e" UNIQUE ("contactId"))` + ) await queryRunner.query(`CREATE INDEX "IDX_e50c368daf85e7ae54585b0f7b" ON "ContactOwner" ("type")`) - await queryRunner.query(`CREATE TABLE "ContactRelationship" ("id" varchar PRIMARY KEY NOT NULL, "leftId" varchar NOT NULL, "rightId" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')))`) + await queryRunner.query( + `CREATE TABLE "ContactRelationship" ("id" varchar PRIMARY KEY NOT NULL, "leftId" varchar NOT NULL, "rightId" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')))` + ) await queryRunner.query(`CREATE UNIQUE INDEX "IDX_ContactRelationshipEntity_left_right" ON "ContactRelationship" ("leftId", "rightId")`) - await queryRunner.query(`CREATE TABLE "temporary_Contact" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')))`) - await queryRunner.query(`INSERT INTO "temporary_Contact"("id", "uri", "created_at", "last_updated_at") SELECT "id", "uri", "created_at", "last_updated_at" FROM "Contact"`) + await queryRunner.query( + `CREATE TABLE "temporary_Contact" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')))` + ) + await queryRunner.query( + `INSERT INTO "temporary_Contact"("id", "uri", "created_at", "last_updated_at") SELECT "id", "uri", "created_at", "last_updated_at" FROM "Contact"` + ) await queryRunner.query(`DROP TABLE "Contact"`) await queryRunner.query(`ALTER TABLE "temporary_Contact" RENAME TO "Contact"`) - await queryRunner.query(`CREATE TABLE "temporary_Contact" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactTypeId" varchar NOT NULL)`) - await queryRunner.query(`INSERT INTO "temporary_Contact"("id", "uri", "created_at", "last_updated_at") SELECT "id", "uri", "created_at", "last_updated_at" FROM "Contact"`) + await queryRunner.query( + `CREATE TABLE "temporary_Contact" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactTypeId" varchar NOT NULL)` + ) + await queryRunner.query( + `INSERT INTO "temporary_Contact"("id", "uri", "created_at", "last_updated_at") SELECT "id", "uri", "created_at", "last_updated_at" FROM "Contact"` + ) await queryRunner.query(`DROP TABLE "Contact"`) await queryRunner.query(`ALTER TABLE "temporary_Contact" RENAME TO "Contact"`) - await queryRunner.query(`CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Alias" UNIQUE ("alias"))`) - await queryRunner.query(`INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"`) + await queryRunner.query( + `CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Alias" UNIQUE ("alias"))` + ) + await queryRunner.query( + `INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"` + ) await queryRunner.query(`DROP TABLE "Identity"`) await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) await queryRunner.query(`CREATE INDEX "IDX_228953a09ee91bbac6e28b7345" ON "BaseConfigEntity" ("type")`) await queryRunner.query(`DROP INDEX "IDX_228953a09ee91bbac6e28b7345"`) - await queryRunner.query(`CREATE TABLE "temporary_BaseConfigEntity" ("id" varchar PRIMARY KEY NOT NULL, "client_id" varchar(255), "client_secret" varchar(255), "scopes" text, "issuer" varchar(255), "redirect_url" text, "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "identifier" varchar(255), "session_id" varchar(255), "type" varchar NOT NULL, "connectionId" varchar, CONSTRAINT "REL_BaseConfig_connectionId" UNIQUE ("connectionId"), CONSTRAINT "FK_0ab3b33e0a87e1706025e63d8a9" FOREIGN KEY ("connectionId") REFERENCES "Connection" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) - await queryRunner.query(`INSERT INTO "temporary_BaseConfigEntity"("id", "client_id", "client_secret", "scopes", "issuer", "redirect_url", "dangerously_allow_insecure_http_requests", "client_auth_method", "identifier", "session_id", "type", "connectionId") SELECT "id", "client_id", "client_secret", "scopes", "issuer", "redirect_url", "dangerously_allow_insecure_http_requests", "client_auth_method", "identifier", "session_id", "type", "connectionId" FROM "BaseConfigEntity"`) + await queryRunner.query( + `CREATE TABLE "temporary_BaseConfigEntity" ("id" varchar PRIMARY KEY NOT NULL, "client_id" varchar(255), "client_secret" varchar(255), "scopes" text, "issuer" varchar(255), "redirect_url" text, "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "identifier" varchar(255), "session_id" varchar(255), "type" varchar NOT NULL, "connectionId" varchar, CONSTRAINT "REL_BaseConfig_connectionId" UNIQUE ("connectionId"), CONSTRAINT "FK_0ab3b33e0a87e1706025e63d8a9" FOREIGN KEY ("connectionId") REFERENCES "Connection" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + ) + await queryRunner.query( + `INSERT INTO "temporary_BaseConfigEntity"("id", "client_id", "client_secret", "scopes", "issuer", "redirect_url", "dangerously_allow_insecure_http_requests", "client_auth_method", "identifier", "session_id", "type", "connectionId") SELECT "id", "client_id", "client_secret", "scopes", "issuer", "redirect_url", "dangerously_allow_insecure_http_requests", "client_auth_method", "identifier", "session_id", "type", "connectionId" FROM "BaseConfigEntity"` + ) await queryRunner.query(`DROP TABLE "BaseConfigEntity"`) await queryRunner.query(`ALTER TABLE "temporary_BaseConfigEntity" RENAME TO "BaseConfigEntity"`) await queryRunner.query(`CREATE INDEX "IDX_228953a09ee91bbac6e28b7345" ON "BaseConfigEntity" ("type")`) - await queryRunner.query(`CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identityId" varchar, CONSTRAINT "REL_CorrelationIdentifier_identityId" UNIQUE ("identityId"), CONSTRAINT "UQ_Correlation_id" UNIQUE ("correlation_id"), CONSTRAINT "FK_28945c1d57c5feee1d5d1f54510" FOREIGN KEY ("identityId") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) - await queryRunner.query(`INSERT INTO "temporary_CorrelationIdentifier"("id", "type", "correlation_id", "identityId") SELECT "id", "type", "correlation_id", "identityId" FROM "CorrelationIdentifier"`) + await queryRunner.query( + `CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identityId" varchar, CONSTRAINT "REL_CorrelationIdentifier_identityId" UNIQUE ("identityId"), CONSTRAINT "UQ_Correlation_id" UNIQUE ("correlation_id"), CONSTRAINT "FK_28945c1d57c5feee1d5d1f54510" FOREIGN KEY ("identityId") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + ) + await queryRunner.query( + `INSERT INTO "temporary_CorrelationIdentifier"("id", "type", "correlation_id", "identityId") SELECT "id", "type", "correlation_id", "identityId" FROM "CorrelationIdentifier"` + ) await queryRunner.query(`DROP TABLE "CorrelationIdentifier"`) await queryRunner.query(`ALTER TABLE "temporary_CorrelationIdentifier" RENAME TO "CorrelationIdentifier"`) - await queryRunner.query(`CREATE TABLE "temporary_IdentityMetadata" ("id" varchar PRIMARY KEY NOT NULL, "label" varchar(255) NOT NULL, "value" varchar(255) NOT NULL, "identityId" varchar, CONSTRAINT "FK_e22568cc3d201c0131b87186117" FOREIGN KEY ("identityId") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) - await queryRunner.query(`INSERT INTO "temporary_IdentityMetadata"("id", "label", "value", "identityId") SELECT "id", "label", "value", "identityId" FROM "IdentityMetadata"`) + await queryRunner.query( + `CREATE TABLE "temporary_IdentityMetadata" ("id" varchar PRIMARY KEY NOT NULL, "label" varchar(255) NOT NULL, "value" varchar(255) NOT NULL, "identityId" varchar, CONSTRAINT "FK_e22568cc3d201c0131b87186117" FOREIGN KEY ("identityId") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + ) + await queryRunner.query( + `INSERT INTO "temporary_IdentityMetadata"("id", "label", "value", "identityId") SELECT "id", "label", "value", "identityId" FROM "IdentityMetadata"` + ) await queryRunner.query(`DROP TABLE "IdentityMetadata"`) await queryRunner.query(`ALTER TABLE "temporary_IdentityMetadata" RENAME TO "IdentityMetadata"`) await queryRunner.query(`DROP INDEX "IDX_e50c368daf85e7ae54585b0f7b"`) - await queryRunner.query(`CREATE TABLE "temporary_ContactOwner" ("id" varchar PRIMARY KEY NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "firstName" varchar(255), "middleName" varchar(255), "lastName" varchar(255), "displayName" varchar(255), "legalName" varchar(255), "cocNumber" varchar(255), "type" varchar NOT NULL, "contactId" varchar, CONSTRAINT "UQ_9177af8a51a2a0598d3a8c68e1e" UNIQUE ("displayName"), CONSTRAINT "UQ_91bf22d2597ff429ece6ae807aa" UNIQUE ("legalName"), CONSTRAINT "UQ_9177af8a51a2a0598d3a8c68e1e" UNIQUE ("displayName"), CONSTRAINT "REL_26ce21b29da1426fa1198b947e" UNIQUE ("contactId"), CONSTRAINT "FK_26ce21b29da1426fa1198b947e1" FOREIGN KEY ("contactId") REFERENCES "Contact" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) - await queryRunner.query(`INSERT INTO "temporary_ContactOwner"("id", "created_at", "last_updated_at", "firstName", "middleName", "lastName", "displayName", "legalName", "cocNumber", "type", "contactId") SELECT "id", "created_at", "last_updated_at", "firstName", "middleName", "lastName", "displayName", "legalName", "cocNumber", "type", "contactId" FROM "ContactOwner"`) + await queryRunner.query( + `CREATE TABLE "temporary_ContactOwner" ("id" varchar PRIMARY KEY NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "firstName" varchar(255), "middleName" varchar(255), "lastName" varchar(255), "displayName" varchar(255), "legalName" varchar(255), "type" varchar NOT NULL, "contactId" varchar, CONSTRAINT "UQ_9177af8a51a2a0598d3a8c68e1e" UNIQUE ("displayName"), CONSTRAINT "UQ_91bf22d2597ff429ece6ae807aa" UNIQUE ("legalName"), CONSTRAINT "UQ_9177af8a51a2a0598d3a8c68e1e" UNIQUE ("displayName"), CONSTRAINT "REL_26ce21b29da1426fa1198b947e" UNIQUE ("contactId"), CONSTRAINT "FK_26ce21b29da1426fa1198b947e1" FOREIGN KEY ("contactId") REFERENCES "Contact" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + ) + await queryRunner.query( + `INSERT INTO "temporary_ContactOwner"("id", "created_at", "last_updated_at", "firstName", "middleName", "lastName", "displayName", "legalName", "type", "contactId") SELECT "id", "created_at", "last_updated_at", "firstName", "middleName", "lastName", "displayName", "legalName", "type", "contactId" FROM "ContactOwner"` + ) await queryRunner.query(`DROP TABLE "ContactOwner"`) await queryRunner.query(`ALTER TABLE "temporary_ContactOwner" RENAME TO "ContactOwner"`) await queryRunner.query(`CREATE INDEX "IDX_e50c368daf85e7ae54585b0f7b" ON "ContactOwner" ("type")`) await queryRunner.query(`DROP INDEX "IDX_ContactRelationshipEntity_left_right"`) - await queryRunner.query(`CREATE TABLE "temporary_ContactRelationship" ("id" varchar PRIMARY KEY NOT NULL, "leftId" varchar NOT NULL, "rightId" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "FK_24a7bc0595cc5da51c91e1bee62" FOREIGN KEY ("leftId") REFERENCES "Contact" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "FK_e673c9f78f3c7670a75c0ea7710" FOREIGN KEY ("rightId") REFERENCES "Contact" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) - await queryRunner.query(`INSERT INTO "temporary_ContactRelationship"("id", "leftId", "rightId", "created_at", "last_updated_at") SELECT "id", "leftId", "rightId", "created_at", "last_updated_at" FROM "ContactRelationship"`) + await queryRunner.query( + `CREATE TABLE "temporary_ContactRelationship" ("id" varchar PRIMARY KEY NOT NULL, "leftId" varchar NOT NULL, "rightId" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "FK_24a7bc0595cc5da51c91e1bee62" FOREIGN KEY ("leftId") REFERENCES "Contact" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "FK_e673c9f78f3c7670a75c0ea7710" FOREIGN KEY ("rightId") REFERENCES "Contact" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + ) + await queryRunner.query( + `INSERT INTO "temporary_ContactRelationship"("id", "leftId", "rightId", "created_at", "last_updated_at") SELECT "id", "leftId", "rightId", "created_at", "last_updated_at" FROM "ContactRelationship"` + ) await queryRunner.query(`DROP TABLE "ContactRelationship"`) await queryRunner.query(`ALTER TABLE "temporary_ContactRelationship" RENAME TO "ContactRelationship"`) await queryRunner.query(`CREATE UNIQUE INDEX "IDX_ContactRelationshipEntity_left_right" ON "ContactRelationship" ("leftId", "rightId")`) - await queryRunner.query(`CREATE TABLE "temporary_Contact" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactTypeId" varchar NOT NULL, CONSTRAINT "FK_a992c5cdc48d0bc105d0338f982" FOREIGN KEY ("contactTypeId") REFERENCES "ContactType" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`) - await queryRunner.query(`INSERT INTO "temporary_Contact"("id", "uri", "created_at", "last_updated_at", "contactTypeId") SELECT "id", "uri", "created_at", "last_updated_at", "contactTypeId" FROM "Contact"`) + await queryRunner.query( + `CREATE TABLE "temporary_Contact" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactTypeId" varchar NOT NULL, CONSTRAINT "FK_a992c5cdc48d0bc105d0338f982" FOREIGN KEY ("contactTypeId") REFERENCES "ContactType" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)` + ) + await queryRunner.query( + `INSERT INTO "temporary_Contact"("id", "uri", "created_at", "last_updated_at", "contactTypeId") SELECT "id", "uri", "created_at", "last_updated_at", "contactTypeId" FROM "Contact"` + ) await queryRunner.query(`DROP TABLE "Contact"`) await queryRunner.query(`ALTER TABLE "temporary_Contact" RENAME TO "Contact"`) - await queryRunner.query(`CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Alias" UNIQUE ("alias"), CONSTRAINT "FK_70ac2a54e2041b7914613204e3d" FOREIGN KEY ("contactId") REFERENCES "Contact" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) - await queryRunner.query(`INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"`) + await queryRunner.query( + `CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Alias" UNIQUE ("alias"), CONSTRAINT "FK_70ac2a54e2041b7914613204e3d" FOREIGN KEY ("contactId") REFERENCES "Contact" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + ) + await queryRunner.query( + `INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"` + ) await queryRunner.query(`DROP TABLE "Identity"`) await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) - await queryRunner.query(`CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identityId" varchar, CONSTRAINT "REL_Connection_identityId" UNIQUE ("identityId"), CONSTRAINT "FK_fff3668c112a6863bb8c37519a0" FOREIGN KEY ("identityId") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) + await queryRunner.query( + `CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identityId" varchar, CONSTRAINT "REL_Connection_identityId" UNIQUE ("identityId"), CONSTRAINT "FK_fff3668c112a6863bb8c37519a0" FOREIGN KEY ("identityId") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + ) await queryRunner.query(`INSERT INTO "temporary_Connection"("id", "type", "identityId") SELECT "id", "type", "identityId" FROM "Connection"`) await queryRunner.query(`DROP TABLE "Connection"`) await queryRunner.query(`ALTER TABLE "temporary_Connection" RENAME TO "Connection"`) } - public async down(queryRunner: QueryRunner): Promise { - - } + public async down(queryRunner: QueryRunner): Promise {} } diff --git a/packages/data-store/src/types/contact/IAbstractContactStore.ts b/packages/data-store/src/types/contact/IAbstractContactStore.ts index 8dcfd9a1a..76e1cb323 100644 --- a/packages/data-store/src/types/contact/IAbstractContactStore.ts +++ b/packages/data-store/src/types/contact/IAbstractContactStore.ts @@ -1,107 +1,108 @@ import { - BasicContactType, - BasicContactOwner, - IBasicIdentity, - IContact, - IIdentity, - IPartialContact, - IPartialIdentity, - ContactTypeEnum, - IContactType, - IContactRelationship, - IPartialContactRelationship, - IPartialContactType, + NonPersistedPartyType, + NonPersistedContact, + NonPersistedIdentity, + Party, + Identity, + PartialParty, + PartialIdentity, + PartyTypeEnum, + PartyType, + PartyRelationship, + PartialPartyRelationship, + PartialPartyType, NonPersistedElectronicAddress } from './contact' -export type FindContactArgs = Array -export type FindIdentityArgs = Array -export type FindContactTypeArgs = Array -export type FindRelationshipArgs = Array +export type FindPartyArgs = Array +export type FindIdentityArgs = Array +export type FindPartyTypeArgs = Array +export type FindRelationshipArgs = Array -export interface IGetContactArgs { - contactId: string +export type GetPartyArgs = { + partyId: string } -export interface IGetContactsArgs { - filter?: FindContactArgs +export type GetPartiesArgs = { + filter?: FindPartyArgs } -export interface IAddContactArgs { +export type AddPartyArgs = { uri?: string - contactType: BasicContactType - contactOwner: BasicContactOwner - identities?: Array + partyType: NonPersistedPartyType + contact: NonPersistedContact + identities?: Array + electronicAddresses?: Array } -export interface IUpdateContactArgs { - contact: Omit +export type UpdatePartyArgs = { + party: Omit } -export interface IRemoveContactArgs { - contactId: string +export type RemovePartyArgs = { + partyId: string } -export interface IGetIdentityArgs { +export type GetIdentityArgs = { identityId: string } -export interface IGetIdentitiesArgs { +export type GetIdentitiesArgs = { filter?: FindIdentityArgs } -export interface IAddIdentityArgs { - contactId: string - identity: IBasicIdentity +export type AddIdentityArgs = { + partyId: string + identity: NonPersistedIdentity } -export interface IUpdateIdentityArgs { - identity: IIdentity +export type UpdateIdentityArgs = { + identity: Identity } -export interface IRemoveIdentityArgs { +export type RemoveIdentityArgs = { identityId: string } -export interface IRemoveRelationshipArgs { +export type RemoveRelationshipArgs = { relationshipId: string } -export interface IAddRelationshipArgs { +export type AddRelationshipArgs = { leftId: string rightId: string } -export interface IGetRelationshipArgs { +export type GetRelationshipArgs = { relationshipId: string } -export interface IGetRelationshipsArgs { +export type GetRelationshipsArgs = { filter: FindRelationshipArgs } -export interface IUpdateRelationshipArgs { - relationship: Omit +export type UpdateRelationshipArgs = { + relationship: Omit } -export interface IAddContactTypeArgs { - type: ContactTypeEnum +export type AddPartyTypeArgs = { + type: PartyTypeEnum name: string tenantId: string description?: string } -export interface IGetContactTypeArgs { - contactTypeId: string +export type GetPartyTypeArgs = { + partyTypeId: string } -export interface IGetContactTypesArgs { - filter?: FindContactTypeArgs +export type GetPartyTypesArgs = { + filter?: FindPartyTypeArgs } -export interface IUpdateContactTypeArgs { - contactType: Omit +export type UpdatePartyTypeArgs = { + partyType: Omit } -export interface IRemoveContactTypeArgs { - contactTypeId: string +export type RemovePartyTypeArgs = { + partyTypeId: string } diff --git a/packages/data-store/src/types/contact/contact.ts b/packages/data-store/src/types/contact/contact.ts index e1cf55899..1024ddf9d 100644 --- a/packages/data-store/src/types/contact/contact.ts +++ b/packages/data-store/src/types/contact/contact.ts @@ -1,102 +1,87 @@ import { IIdentifier } from '@veramo/core' -export enum IdentityRoleEnum { - ISSUER = 'issuer', - VERIFIER = 'verifier', - HOLDER = 'holder', -} - -export enum ConnectionTypeEnum { - OPENID_CONNECT = 'OIDC', - SIOPv2 = 'SIOPv2', - SIOPv2_OpenID4VP = 'SIOPv2+OpenID4VP', -} - -export enum CorrelationIdentifierEnum { - DID = 'did', - URL = 'url', -} - -export interface IContact { +export type Party = { id: string uri?: string roles: Array - identities: Array - contactOwner: ContactOwner - contactType: IContactType - relationships: Array + identities: Array + electronicAddresses: Array + contact: Contact + partyType: PartyType + relationships: Array createdAt: Date lastUpdatedAt: Date } -export interface IBasicContact { - uri?: string - identities?: Array - contactOwner: BasicContactOwner - contactType: BasicContactType - relationships?: Array -} -export interface IPartialContact extends Partial> { - identities?: IPartialIdentity - contactOwner?: PartialContactOwner - contactType?: IPartialContactType - relationships?: IPartialContactRelationship -} - -export interface IIdentity { +export type NonPersistedParty = Omit< + Party, + 'id' | 'identities' | 'electronicAddresses' | 'contact' | 'roles' | 'partyType' | 'relationships' | 'createdAt' | 'lastUpdatedAt' +> & { + identities?: Array + electronicAddresses?: Array + contact: NonPersistedContact + partyType: NonPersistedPartyType + relationships?: Array +} +export type PartialParty = Partial> & { + identities?: PartialIdentity + electronicAddresses?: PartialElectronicAddress + contact?: PartialContact + partyType?: PartialPartyType + relationships?: PartialPartyRelationship +} + +export type Identity = { id: string alias: string roles: Array - identifier: ICorrelationIdentifier - connection?: IConnection - metadata?: Array + identifier: CorrelationIdentifier + connection?: Connection + metadata?: Array createdAt: Date lastUpdatedAt: Date } -export interface IBasicIdentity { - alias: string - roles: Array - identifier: BasicCorrelationIdentifier - connection?: IBasicConnection - metadata?: Array +export type NonPersistedIdentity = Omit & { + identifier: NonPersistedCorrelationIdentifier + connection?: NonPersistedConnection + metadata?: Array } -export interface IPartialIdentity extends Partial> { - identifier?: IPartialCorrelationIdentifier - connection?: IPartialConnection - metadata?: IPartialMetadataItem - roles?: IdentityRoleEnum //FindOperator - contactId?: string +export type PartialIdentity = Partial> & { + identifier?: PartialCorrelationIdentifier + connection?: PartialConnection + metadata?: PartialMetadataItem + roles?: IdentityRoleEnum + partyId?: string } -export interface IMetadataItem { +export type MetadataItem = { id: string label: string value: string } -export declare type BasicMetadataItem = Omit -export interface IPartialMetadataItem extends Partial {} +export type NonPersistedMetadataItem = Omit +export type PartialMetadataItem = Partial -export interface ICorrelationIdentifier { +export type CorrelationIdentifier = { id: string type: CorrelationIdentifierEnum correlationId: string } -export declare type BasicCorrelationIdentifier = Omit -export interface IPartialCorrelationIdentifier extends Partial {} +export type NonPersistedCorrelationIdentifier = Omit +export type PartialCorrelationIdentifier = Partial -export interface IConnection { +export type Connection = { id: string type: ConnectionTypeEnum config: ConnectionConfig } -export interface IBasicConnection { - type: ConnectionTypeEnum - config: BasicConnectionConfig +export type NonPersistedConnection = Omit & { + config: NonPersistedConnectionConfig } -export interface IPartialConnection extends Partial> { +export type PartialConnection = Partial> & { config: PartialConnectionConfig } -export interface IOpenIdConfig { +export type OpenIdConfig = { id: string clientId: string clientSecret: string @@ -106,31 +91,26 @@ export interface IOpenIdConfig { dangerouslyAllowInsecureHttpRequests: boolean clientAuthMethod: 'basic' | 'post' | undefined } -export declare type BasicOpenIdConfig = Omit -export interface IPartialOpenIdConfig extends Partial {} +export type NonPersistedOpenIdConfig = Omit +export type PartialOpenIdConfig = Partial -export interface IDidAuthConfig { +export type DidAuthConfig = { id: string identifier: IIdentifier stateId: string redirectUrl: string sessionId: string } -export declare type BasicDidAuthConfig = Omit -export interface IPartialDidAuthConfig extends Partial> { - identifier: Partial // TODO +export type NonPersistedDidAuthConfig = Omit +export type PartialDidAuthConfig = Partial> & { + identifier: Partial // TODO, we need to create partials for sub types in IIdentifier } -export declare type ConnectionConfig = IOpenIdConfig | IDidAuthConfig -export declare type BasicConnectionConfig = BasicDidAuthConfig | BasicOpenIdConfig -export declare type PartialConnectionConfig = IPartialOpenIdConfig | IPartialDidAuthConfig - -export enum ContactTypeEnum { - PERSON = 'person', - ORGANIZATION = 'organization', -} +export type ConnectionConfig = OpenIdConfig | DidAuthConfig +export type NonPersistedConnectionConfig = NonPersistedDidAuthConfig | NonPersistedOpenIdConfig +export type PartialConnectionConfig = PartialOpenIdConfig | PartialDidAuthConfig -export interface IPerson { +export type NaturalPerson = { id: string firstName: string lastName: string @@ -139,44 +119,77 @@ export interface IPerson { createdAt: Date lastUpdatedAt: Date } -export declare type BasicPerson = Omit -export interface IPartialPerson extends Partial {} +export type NonPersistedNaturalPerson = Omit +export type PartialNaturalPerson = Partial -export interface IOrganization { +export type Organization = { id: string legalName: string displayName: string - cocNumber?: string createdAt: Date lastUpdatedAt: Date } -export declare type BasicOrganization = Omit -export interface IPartialOrganization extends Partial {} +export type NonPersistedOrganization = Omit +export type PartialOrganization = Partial -export declare type ContactOwner = IPerson | IOrganization -export declare type BasicContactOwner = BasicPerson | BasicOrganization -export declare type PartialContactOwner = IPartialPerson | IPartialOrganization +export type Contact = NaturalPerson | Organization +export type NonPersistedContact = NonPersistedNaturalPerson | NonPersistedOrganization +export type PartialContact = PartialNaturalPerson | PartialOrganization -export interface IContactType { +export type PartyType = { id: string - type: ContactTypeEnum + type: PartyTypeEnum name: string tenantId: string description?: string createdAt: Date lastUpdatedAt: Date } -export interface BasicContactType extends Omit { +export type NonPersistedPartyType = Omit & { id?: string } -export interface IPartialContactType extends Partial {} +export type PartialPartyType = Partial -export interface IContactRelationship { +export type PartyRelationship = { id: string leftId: string rightId: string createdAt: Date lastUpdatedAt: Date } -export declare type BasicContactRelationship = Omit -export interface IPartialContactRelationship extends Partial {} +export type NonPersistedPartyRelationship = Omit +export type PartialPartyRelationship = Partial + +export type ElectronicAddress = { + id: string + type: ElectronicAddressType + electronicAddress: string + createdAt: Date + lastUpdatedAt: Date +} +export type NonPersistedElectronicAddress = Omit +export type PartialElectronicAddress = Partial + +export type ElectronicAddressType = 'email' + +export enum IdentityRoleEnum { + ISSUER = 'issuer', + VERIFIER = 'verifier', + HOLDER = 'holder', +} + +export enum ConnectionTypeEnum { + OPENID_CONNECT = 'OIDC', + SIOPv2 = 'SIOPv2', + SIOPv2_OpenID4VP = 'SIOPv2+OpenID4VP', +} + +export enum CorrelationIdentifierEnum { + DID = 'did', + URL = 'url', +} + +export enum PartyTypeEnum { + NATURAL_PERSON = 'naturalPerson', + ORGANIZATION = 'organization', +} diff --git a/packages/data-store/src/utils/contact/MappingUtils.ts b/packages/data-store/src/utils/contact/MappingUtils.ts new file mode 100644 index 000000000..1a4baa101 --- /dev/null +++ b/packages/data-store/src/utils/contact/MappingUtils.ts @@ -0,0 +1,344 @@ +import { + Connection, + ConnectionConfig, + Contact, + CorrelationIdentifier, + DidAuthConfig, + ElectronicAddress, + Identity, + MetadataItem, + NaturalPerson, + NonPersistedConnection, + NonPersistedConnectionConfig, + NonPersistedContact, + NonPersistedCorrelationIdentifier, + NonPersistedDidAuthConfig, + NonPersistedElectronicAddress, + NonPersistedIdentity, + NonPersistedMetadataItem, + NonPersistedNaturalPerson, + NonPersistedOpenIdConfig, + NonPersistedOrganization, + NonPersistedParty, + NonPersistedPartyRelationship, + NonPersistedPartyType, + OpenIdConfig, + Organization, + Party, + PartyRelationship, + PartyType, +} from '../../types' +import { PartyEntity } from '../../entities/contact/PartyEntity' +import { IdentityEntity } from '../../entities/contact/IdentityEntity' +import { ElectronicAddressEntity } from '../../entities/contact/ElectronicAddressEntity' +import { PartyRelationshipEntity } from '../../entities/contact/PartyRelationshipEntity' +import { BaseContactEntity } from '../../entities/contact/BaseContactEntity' +import { NaturalPersonEntity } from '../../entities/contact/NaturalPersonEntity' +import { OrganizationEntity } from '../../entities/contact/OrganizationEntity' +import { ConnectionEntity } from '../../entities/contact/ConnectionEntity' +import { BaseConfigEntity } from '../../entities/contact/BaseConfigEntity' +import { CorrelationIdentifierEntity } from '../../entities/contact/CorrelationIdentifierEntity' +import { DidAuthConfigEntity } from '../../entities/contact/DidAuthConfigEntity' +import { IdentityMetadataItemEntity } from '../../entities/contact/IdentityMetadataItemEntity' +import { OpenIdConfigEntity } from '../../entities/contact/OpenIdConfigEntity' +import { PartyTypeEntity } from '../../entities/contact/PartyTypeEntity' + +export const partyEntityFrom = (party: NonPersistedParty): PartyEntity => { + const partyEntity: PartyEntity = new PartyEntity() + partyEntity.uri = party.uri + partyEntity.identities = party.identities ? party.identities.map((identity: NonPersistedIdentity) => identityEntityFrom(identity)) : [] + partyEntity.electronicAddresses = party.electronicAddresses + ? party.electronicAddresses.map((electronicAddress: NonPersistedElectronicAddress) => electronicAddressEntityFrom(electronicAddress)) + : [] + partyEntity.partyType = partyTypeEntityFrom(party.partyType) + partyEntity.contact = contactEntityFrom(party.contact) + + return partyEntity +} + +export const partyFrom = (party: PartyEntity): Party => { + return { + id: party.id, + uri: party.uri, + roles: [...new Set(party.identities?.flatMap((identity: IdentityEntity) => identity.roles))] ?? [], + identities: party.identities ? party.identities.map((identity: IdentityEntity) => identityFrom(identity)) : [], + electronicAddresses: party.electronicAddresses + ? party.electronicAddresses.map((electronicAddress: ElectronicAddressEntity) => electronicAddressFrom(electronicAddress)) + : [], + relationships: party.relationships ? party.relationships.map((relationship: PartyRelationshipEntity) => partyRelationshipFrom(relationship)) : [], + partyType: partyTypeFrom(party.partyType), + contact: contactFrom(party.contact), + createdAt: party.createdAt, + lastUpdatedAt: party.lastUpdatedAt, + } +} + +export const contactEntityFrom = (contact: NonPersistedContact): BaseContactEntity => { + if (isNaturalPerson(contact)) { + return naturalPersonEntityFrom(contact) + } else if (isOrganization(contact)) { + return organizationEntityFrom(contact) + } + + throw new Error('Contact not supported') +} + +export const contactFrom = (contact: BaseContactEntity): Contact => { + if (isNaturalPerson(contact)) { + return naturalPersonFrom(contact) + } else if (isOrganization(contact)) { + return organizationFrom(contact) + } + + throw new Error('Contact not supported') +} + +export const isNaturalPerson = (contact: NonPersistedContact | BaseContactEntity): contact is NonPersistedNaturalPerson | NaturalPersonEntity => + 'firstName' in contact && 'lastName' in contact + +export const isOrganization = (contact: NonPersistedContact | BaseContactEntity): contact is NonPersistedOrganization | OrganizationEntity => + 'legalName' in contact + +export const connectionEntityFrom = (connection: NonPersistedConnection): ConnectionEntity => { + const connectionEntity: ConnectionEntity = new ConnectionEntity() + connectionEntity.type = connection.type + connectionEntity.config = configEntityFrom(connection.config) + + return connectionEntity +} + +export const connectionFrom = (connection: ConnectionEntity): Connection => { + return { + id: connection.id, + type: connection.type, + config: configFrom(connection.config), + } +} + +const configEntityFrom = (config: NonPersistedConnectionConfig): BaseConfigEntity => { + if (isOpenIdConfig(config)) { + return openIdConfigEntityFrom(config) + } else if (isDidAuthConfig(config)) { + return didAuthConfigEntityFrom(config) + } + + throw new Error('config type not supported') +} + +export const correlationIdentifierEntityFrom = (identifier: NonPersistedCorrelationIdentifier): CorrelationIdentifierEntity => { + const identifierEntity: CorrelationIdentifierEntity = new CorrelationIdentifierEntity() + identifierEntity.type = identifier.type + identifierEntity.correlationId = identifier.correlationId + + return identifierEntity +} + +export const correlationIdentifierFrom = (identifier: CorrelationIdentifierEntity): CorrelationIdentifier => { + return { + id: identifier.id, + type: identifier.type, + correlationId: identifier.correlationId, + } +} + +export const didAuthConfigEntityFrom = (config: NonPersistedDidAuthConfig): DidAuthConfigEntity => { + const didAuthConfig: DidAuthConfigEntity = new DidAuthConfigEntity() + didAuthConfig.identifier = config.identifier.did + didAuthConfig.redirectUrl = config.redirectUrl + didAuthConfig.sessionId = config.sessionId + + return didAuthConfig +} + +export const electronicAddressEntityFrom = (electronicAddress: NonPersistedElectronicAddress): ElectronicAddressEntity => { + const electronicAddressEntity: ElectronicAddressEntity = new ElectronicAddressEntity() + electronicAddressEntity.type = electronicAddress.type + electronicAddressEntity.electronicAddress = electronicAddress.electronicAddress + + return electronicAddressEntity +} + +export const electronicAddressFrom = (electronicAddress: ElectronicAddressEntity): ElectronicAddress => { + return { + id: electronicAddress.id, + type: electronicAddress.type, + electronicAddress: electronicAddress.electronicAddress, + createdAt: electronicAddress.createdAt, + lastUpdatedAt: electronicAddress.lastUpdatedAt, + } +} + +export const identityEntityFrom = (args: NonPersistedIdentity): IdentityEntity => { + const identityEntity: IdentityEntity = new IdentityEntity() + identityEntity.alias = args.alias + identityEntity.roles = args.roles + identityEntity.identifier = correlationIdentifierEntityFrom(args.identifier) + identityEntity.connection = args.connection ? connectionEntityFrom(args.connection) : undefined + identityEntity.metadata = args.metadata ? args.metadata.map((item: NonPersistedMetadataItem) => metadataItemEntityFrom(item)) : [] + + return identityEntity +} + +export const identityFrom = (identity: IdentityEntity): Identity => { + return { + id: identity.id, + alias: identity.alias, + roles: identity.roles, + identifier: correlationIdentifierFrom(identity.identifier), + ...(identity.connection && { connection: connectionFrom(identity.connection) }), + metadata: identity.metadata ? identity.metadata.map((item: IdentityMetadataItemEntity) => metadataItemFrom(item)) : [], + createdAt: identity.createdAt, + lastUpdatedAt: identity.createdAt, + } +} + +export const metadataItemEntityFrom = (item: NonPersistedMetadataItem): IdentityMetadataItemEntity => { + const metadataItemEntity: IdentityMetadataItemEntity = new IdentityMetadataItemEntity() + metadataItemEntity.label = item.label + metadataItemEntity.value = item.value + + return metadataItemEntity +} + +export const metadataItemFrom = (item: IdentityMetadataItemEntity): MetadataItem => { + return { + id: item.id, + label: item.label, + value: item.value, + } +} + +export const naturalPersonEntityFrom = (naturalPerson: NonPersistedNaturalPerson): NaturalPersonEntity => { + const naturalPersonEntity: NaturalPersonEntity = new NaturalPersonEntity() + naturalPersonEntity.firstName = naturalPerson.firstName + naturalPersonEntity.middleName = naturalPerson.middleName + naturalPersonEntity.lastName = naturalPerson.lastName + naturalPersonEntity.displayName = naturalPerson.displayName + + return naturalPersonEntity +} + +export const naturalPersonFrom = (naturalPerson: NaturalPersonEntity): NaturalPerson => { + return { + id: naturalPerson.id, + firstName: naturalPerson.firstName, + middleName: naturalPerson.middleName, + lastName: naturalPerson.lastName, + displayName: naturalPerson.displayName, + createdAt: naturalPerson.createdAt, + lastUpdatedAt: naturalPerson.lastUpdatedAt, + } +} + +export const openIdConfigEntityFrom = (config: NonPersistedOpenIdConfig): OpenIdConfigEntity => { + const openIdConfig: OpenIdConfigEntity = new OpenIdConfigEntity() + openIdConfig.clientId = config.clientId + openIdConfig.clientSecret = config.clientSecret + openIdConfig.scopes = config.scopes + openIdConfig.issuer = config.issuer + openIdConfig.redirectUrl = config.redirectUrl + openIdConfig.dangerouslyAllowInsecureHttpRequests = config.dangerouslyAllowInsecureHttpRequests + openIdConfig.clientAuthMethod = config.clientAuthMethod + + return openIdConfig +} + +export const organizationEntityFrom = (organization: NonPersistedOrganization): OrganizationEntity => { + const organizationEntity: OrganizationEntity = new OrganizationEntity() + organizationEntity.legalName = organization.legalName + organizationEntity.displayName = organization.displayName + + return organizationEntity +} + +export const organizationFrom = (organization: OrganizationEntity): Organization => { + return { + id: organization.id, + legalName: organization.legalName, + displayName: organization.displayName, + createdAt: organization.createdAt, + lastUpdatedAt: organization.lastUpdatedAt, + } +} + +export const partyRelationshipEntityFrom = (relationship: NonPersistedPartyRelationship): PartyRelationshipEntity => { + const partyRelationshipEntity: PartyRelationshipEntity = new PartyRelationshipEntity() + partyRelationshipEntity.leftId = relationship.leftId + partyRelationshipEntity.rightId = relationship.rightId + + return partyRelationshipEntity +} + +export const partyRelationshipFrom = (relationship: PartyRelationshipEntity): PartyRelationship => { + return { + id: relationship.id, + leftId: relationship.leftId, + rightId: relationship.rightId, + createdAt: relationship.createdAt, + lastUpdatedAt: relationship.lastUpdatedAt, + } +} + +export const partyTypeEntityFrom = (args: NonPersistedPartyType): PartyTypeEntity => { + const partyTypeEntity: PartyTypeEntity = new PartyTypeEntity() + if (args.id) { + partyTypeEntity.id = args.id + } + partyTypeEntity.type = args.type + partyTypeEntity.name = args.name + partyTypeEntity.description = args.description + partyTypeEntity.tenantId = args.tenantId + + return partyTypeEntity +} + +export const partyTypeFrom = (partyType: PartyTypeEntity): PartyType => { + return { + id: partyType.id, + type: partyType.type, + name: partyType.name, + tenantId: partyType.tenantId, + description: partyType.description, + createdAt: partyType.createdAt, + lastUpdatedAt: partyType.lastUpdatedAt, + } +} + +export const configFrom = (config: BaseConfigEntity): ConnectionConfig => { + if (isOpenIdConfig(config)) { + return openIdConfigFrom(config) + } else if (isDidAuthConfig(config)) { + return didAuthConfigFrom(config) + } + + throw new Error('config type not supported') +} + +export const openIdConfigFrom = (config: OpenIdConfigEntity): OpenIdConfig => { + return { + id: config.id, + clientId: config.clientId, + clientSecret: config.clientSecret, + scopes: config.scopes, + issuer: config.issuer, + redirectUrl: config.redirectUrl, + dangerouslyAllowInsecureHttpRequests: config.dangerouslyAllowInsecureHttpRequests, + clientAuthMethod: config.clientAuthMethod, + } +} + +export const didAuthConfigFrom = (config: DidAuthConfigEntity): DidAuthConfig => { + return { + id: config.id, + identifier: { did: config.identifier, provider: '', keys: [], services: [] }, + stateId: '', // FIXME + redirectUrl: config.redirectUrl, + sessionId: config.sessionId, + } +} + +export const isOpenIdConfig = (config: NonPersistedConnectionConfig | BaseConfigEntity): config is OpenIdConfig | OpenIdConfigEntity => + 'clientSecret' in config && 'issuer' in config && 'redirectUrl' in config + +export const isDidAuthConfig = (config: NonPersistedConnectionConfig | BaseConfigEntity): config is DidAuthConfig | DidAuthConfigEntity => + 'identifier' in config && 'redirectUrl' in config && 'sessionId' in config diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 92db2ab8a..b4383b9f3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '6.0' +lockfileVersion: '6.1' settings: autoInstallPeers: true @@ -187,8 +187,8 @@ importers: packages/contact-manager: dependencies: '@sphereon/ssi-sdk.data-store': - specifier: workspace:* - version: link:../data-store + specifier: file://C:\ssi-sdk\packages\data-store\sphereon-ssi-sdk.data-store-0.23.0-bram.tgz + version: file:packages/data-store/sphereon-ssi-sdk.data-store-0.23.0-bram.tgz(ts-node@10.9.1) cross-fetch: specifier: ^3.1.5 version: 3.1.5 @@ -19086,6 +19086,38 @@ packages: optionalDependencies: commander: 9.5.0 + file:packages/data-store/sphereon-ssi-sdk.data-store-0.23.0-bram.tgz(ts-node@10.9.1): + resolution: {integrity: sha512-arZo36c1KeLyoFxzLYCu0uOqdypcsznGgy4vrS5AvfmDMMtwaAd2qrssk8SQQuDFpLq6SEuplRZ1H0I3gZqJeQ==, tarball: file:packages/data-store/sphereon-ssi-sdk.data-store-0.23.0-bram.tgz} + id: file:packages/data-store/sphereon-ssi-sdk.data-store-0.23.0-bram.tgz + name: '@sphereon/ssi-sdk.data-store' + version: 0.23.0-bram + dependencies: + '@sphereon/ssi-types': link:packages/ssi-types + '@veramo/core': 4.2.0(patch_hash=c5oempznsz4br5w3tcuk2i2mau) + class-validator: 0.14.0 + debug: 4.3.4 + typeorm: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + transitivePeerDependencies: + - '@google-cloud/spanner' + - '@sap/hana-client' + - better-sqlite3 + - hdb-pool + - ioredis + - mongodb + - mssql + - mysql2 + - oracledb + - pg + - pg-native + - pg-query-stream + - redis + - sql.js + - sqlite3 + - supports-color + - ts-node + - typeorm-aurora-data-api-driver + dev: false + github.com/uport-project/EcdsaSecp256k1RecoverySignature2020/ab0db52de6f4e6663ef271a48009ba26e688ef9b: resolution: {tarball: https://codeload.github.com/uport-project/EcdsaSecp256k1RecoverySignature2020/tar.gz/ab0db52de6f4e6663ef271a48009ba26e688ef9b} name: '@veramo-community/lds-ecdsa-secp256k1-recovery2020' From 8e379549ab2c6a267f8efbd58ce308978a784c51 Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Wed, 30 Aug 2023 14:03:11 +0200 Subject: [PATCH 10/35] DPP-1 cleanup --- packages/contact-manager/src/agent/ContactManager.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/packages/contact-manager/src/agent/ContactManager.ts b/packages/contact-manager/src/agent/ContactManager.ts index 8be365d6f..b8ac7b718 100644 --- a/packages/contact-manager/src/agent/ContactManager.ts +++ b/packages/contact-manager/src/agent/ContactManager.ts @@ -83,14 +83,6 @@ export class ContactManager implements IAgentPlugin { ? { firstName: args.firstName, middleName: args.middleName, lastName: args.lastName, displayName: args.displayName} : { legalName: args.legalName, displayName: args.displayName } - - // export type AddPartyArgs = { - // uri?: string - // partyType: NonPersistedPartyType - // contact: NonPersistedContact - // identities?: Array - // } - // TODO add electronic addresses return this.store.addParty({ uri: args.uri, partyType: args.contactType, From a939ff5b7a4362c8463465b47f235b7ba96f0e1f Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Mon, 4 Sep 2023 09:46:32 +0200 Subject: [PATCH 11/35] DPP-1 sqlite up migrations --- .../src/__tests__/contact.entities.test.ts | 4278 +++++++++-------- .../src/entities/contact/IdentityEntity.ts | 2 +- .../entities/contact/OrganizationEntity.ts | 4 +- .../src/entities/contact/PartyEntity.ts | 4 +- .../src/migrations/generic/index.ts | 4 +- .../sqlite/1690925872693-CreateContacts.ts | 362 +- 6 files changed, 2370 insertions(+), 2284 deletions(-) diff --git a/packages/data-store/src/__tests__/contact.entities.test.ts b/packages/data-store/src/__tests__/contact.entities.test.ts index 689f82b6b..846d609a1 100644 --- a/packages/data-store/src/__tests__/contact.entities.test.ts +++ b/packages/data-store/src/__tests__/contact.entities.test.ts @@ -1,70 +1,58 @@ -import { DataSource, FindOptionsWhere } from 'typeorm' +import { DataSource, + // FindOptionsWhere +} from 'typeorm' import { DataStoreContactEntities, - // , DataStoreMigrations + DataStoreMigrations } from '../index' -import { NaturalPersonEntity } from '../entities/contact/NaturalPersonEntity' -import { OrganizationEntity } from '../entities/contact/OrganizationEntity' -import { PartyRelationshipEntity } from '../entities/contact/PartyRelationshipEntity' -import { PartyTypeEntity } from '../entities/contact/PartyTypeEntity' +//import { NaturalPersonEntity } from '../entities/contact/NaturalPersonEntity' +// import { OrganizationEntity } from '../entities/contact/OrganizationEntity' +// import { PartyRelationshipEntity } from '../entities/contact/PartyRelationshipEntity' +// import { PartyTypeEntity } from '../entities/contact/PartyTypeEntity' import { PartyEntity } from '../entities/contact/PartyEntity' -import { IdentityEntity } from '../entities/contact/IdentityEntity' -import { OpenIdConfigEntity } from '../entities/contact/OpenIdConfigEntity' -import { DidAuthConfigEntity } from '../entities/contact/DidAuthConfigEntity' -import { ConnectionEntity } from '../entities/contact/ConnectionEntity' -import { CorrelationIdentifierEntity } from '../entities/contact/CorrelationIdentifierEntity' -import { IdentityMetadataItemEntity } from '../entities/contact/IdentityMetadataItemEntity' -import { BaseContactEntity } from '../entities/contact/BaseContactEntity' +// import { IdentityEntity } from '../entities/contact/IdentityEntity' +// import { OpenIdConfigEntity } from '../entities/contact/OpenIdConfigEntity' +// import { DidAuthConfigEntity } from '../entities/contact/DidAuthConfigEntity' +// import { ConnectionEntity } from '../entities/contact/ConnectionEntity' +// import { CorrelationIdentifierEntity } from '../entities/contact/CorrelationIdentifierEntity' +// import { IdentityMetadataItemEntity } from '../entities/contact/IdentityMetadataItemEntity' +// import { BaseContactEntity } from '../entities/contact/BaseContactEntity' import { NonPersistedParty, PartyTypeEnum, - NaturalPerson, - Organization, - IdentityRoleEnum, - CorrelationIdentifierEnum, - ConnectionTypeEnum, - NonPersistedPartyType, - NonPersistedOrganization, - NonPersistedNaturalPerson, - NonPersistedConnection, - NonPersistedIdentity, - NonPersistedDidAuthConfig, - NonPersistedOpenIdConfig, + //NaturalPerson, + // Organization, + // IdentityRoleEnum, + // CorrelationIdentifierEnum, + // ConnectionTypeEnum, + // NonPersistedPartyType, + // NonPersistedOrganization, + // NonPersistedNaturalPerson, + // NonPersistedConnection, + // NonPersistedIdentity, + // NonPersistedDidAuthConfig, + // NonPersistedOpenIdConfig, } from '../types' import { - connectionEntityFrom, - didAuthConfigEntityFrom, - identityEntityFrom, - naturalPersonEntityFrom, - openIdConfigEntityFrom, - organizationEntityFrom, + // connectionEntityFrom, + // didAuthConfigEntityFrom, + // identityEntityFrom, + // naturalPersonEntityFrom, + // openIdConfigEntityFrom, + // organizationEntityFrom, partyEntityFrom, - partyRelationshipEntityFrom, - partyTypeEntityFrom, + // partyRelationshipEntityFrom, + // partyTypeEntityFrom, } from '../utils/contact/MappingUtils' describe('Database entities tests', (): void => { let dbConnection: DataSource - beforeEach(async (): Promise => { - dbConnection = await new DataSource({ - type: 'sqlite', - database: ':memory:', - logging: 'all', - migrationsRun: false, - // migrations: DataStoreMigrations, - synchronize: true, //false - entities: DataStoreContactEntities, - }).initialize() - // await dbConnection.runMigrations() - // expect(await dbConnection.showMigrations()).toBeFalsy() - }) - // beforeEach(async (): Promise => { // dbConnection = await new DataSource({ // type: 'sqlite', - // database: './database.sqlite', + // database: ':memory:', // logging: 'all', // migrationsRun: false, // // migrations: DataStoreMigrations, @@ -78,221 +66,235 @@ describe('Database entities tests', (): void => { // beforeEach(async (): Promise => { // dbConnection = await new DataSource({ // type: 'sqlite', - // database: ':memory:',//'./database.sqlite', + // database: './database.sqlite', // logging: 'all', // migrationsRun: false, - // migrations: DataStoreMigrations, - // synchronize: false, //false + // // migrations: DataStoreMigrations, + // synchronize: true, //false // entities: DataStoreContactEntities, // }).initialize() - // await dbConnection.runMigrations() - // expect(await dbConnection.showMigrations()).toBeFalsy() + // // await dbConnection.runMigrations() + // // expect(await dbConnection.showMigrations()).toBeFalsy() // }) - afterEach(async (): Promise => { - await (await dbConnection).destroy() - }) - - it('Should save person party to database', async (): Promise => { - const party: NonPersistedParty = { - uri: 'example.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contact: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const partyEntity: PartyEntity = partyEntityFrom(party) - await dbConnection.getRepository(PartyEntity).save(partyEntity, { - transaction: true, - }) - - const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - where: { id: partyEntity.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.identities?.length).toEqual(0) - expect(fromDb?.uri).toEqual(party.uri) - expect(fromDb?.partyType).toBeDefined() - expect(fromDb?.partyType.type).toEqual(party.partyType.type) - expect(fromDb?.partyType.tenantId).toEqual(party.partyType.tenantId) - expect(fromDb?.partyType.name).toEqual(party.partyType.name) - expect(fromDb?.contact).toBeDefined() - expect((fromDb?.contact).firstName).toEqual((party.contact).firstName) - expect((fromDb?.contact).middleName).toEqual((party.contact).middleName) - expect((fromDb?.contact).lastName).toEqual((party.contact).lastName) - expect((fromDb?.contact).displayName).toEqual((party.contact).displayName) - }) - - it('Should save organization party to database', async (): Promise => { - const party: NonPersistedParty = { - uri: 'example.com', - partyType: { - type: PartyTypeEnum.ORGANIZATION, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contact: { - legalName: 'example_legal_name', - displayName: 'example_display_name', - }, - } - - const partyEntity: PartyEntity = partyEntityFrom(party) - await dbConnection.getRepository(PartyEntity).save(partyEntity, { - transaction: true, - }) - - const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - where: { id: partyEntity.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.identities?.length).toEqual(0) - expect(fromDb?.uri).toEqual(party.uri) - expect(fromDb?.partyType).toBeDefined() - expect(fromDb?.partyType.type).toEqual(party.partyType.type) - expect(fromDb?.partyType.tenantId).toEqual(party.partyType.tenantId) - expect(fromDb?.partyType.name).toEqual(party.partyType.name) - expect(fromDb?.contact).toBeDefined() - expect((fromDb?.contact).legalName).toEqual((party.contact).legalName) - expect((fromDb?.contact).displayName).toEqual((party.contact).displayName) - }) - - it('Should result in party relationship for the owner side only', async (): Promise => { - const party1: NonPersistedParty = { - uri: 'example1.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name1', - }, - contact: { - firstName: 'example_first_name1', - middleName: 'example_middle_name1', - lastName: 'example_last_name1', - displayName: 'example_display_name1', - }, - } - - const partyEntity1: PartyEntity = partyEntityFrom(party1) - const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { - transaction: true, - }) - - const party2: NonPersistedParty = { - uri: 'example2.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - name: 'example_name2', - }, - contact: { - firstName: 'example_first_name2', - middleName: 'example_middle_name2', - lastName: 'example_last_name2', - displayName: 'example_display_name2', - }, - } - - const partyEntity2: PartyEntity = partyEntityFrom(party2) - const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { - transaction: true, - }) - - const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ - leftId: savedParty1.id, - rightId: savedParty2.id, - }) - - await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { - transaction: true, - }) - - const fromDb1: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - where: { id: savedParty1.id }, - }) - - const fromDb2: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - where: { id: savedParty2.id }, - }) - - expect(fromDb1).toBeDefined() - expect(fromDb1?.relationships.length).toEqual(1) - expect(fromDb2).toBeDefined() - expect(fromDb2?.relationships.length).toEqual(0) - }) - - it('should throw error when saving person party with blank first name', async (): Promise => { - const party: NonPersistedParty = { - uri: 'example.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contact: { - firstName: '', - middleName: 'example_middle_name1', - lastName: 'example_last_name1', - displayName: 'example_display_name1', - }, - } - - const partyEntity: PartyEntity = partyEntityFrom(party) - - await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank first names are not allowed') + beforeEach(async (): Promise => { + dbConnection = await new DataSource({ + type: 'sqlite', + database: './database.sqlite', + logging: 'all', + migrationsRun: false, + migrations: DataStoreMigrations, + synchronize: false, //false + entities: DataStoreContactEntities, + }).initialize() + await dbConnection.runMigrations() + expect(await dbConnection.showMigrations()).toBeFalsy() }) - it('should throw error when saving person party with blank middle name', async (): Promise => { - const party: NonPersistedParty = { - uri: 'example.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contact: { - firstName: 'example_first_name', - middleName: '', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const partyEntity: PartyEntity = partyEntityFrom(party) - - await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank middle names are not allowed') + afterEach(async (): Promise => { + await (await dbConnection).destroy() }) - it('should throw error when saving person party with blank last name', async (): Promise => { - const party: NonPersistedParty = { - uri: 'example.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contact: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: '', - displayName: 'example_display_name', - }, - } - - const partyEntity: PartyEntity = partyEntityFrom(party) + // it('Should save person party to database', async (): Promise => { + // const party: NonPersistedParty = { + // uri: 'example.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contact: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const partyEntity: PartyEntity = partyEntityFrom(party) + // await dbConnection.getRepository(PartyEntity).save(partyEntity, { + // transaction: true, + // }) + // + // const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + // where: { id: partyEntity.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.identities?.length).toEqual(0) + // expect(fromDb?.uri).toEqual(party.uri) + // expect(fromDb?.partyType).toBeDefined() + // expect(fromDb?.partyType.type).toEqual(party.partyType.type) + // expect(fromDb?.partyType.tenantId).toEqual(party.partyType.tenantId) + // expect(fromDb?.partyType.name).toEqual(party.partyType.name) + // expect(fromDb?.contact).toBeDefined() + // expect((fromDb?.contact).firstName).toEqual((party.contact).firstName) + // expect((fromDb?.contact).middleName).toEqual((party.contact).middleName) + // expect((fromDb?.contact).lastName).toEqual((party.contact).lastName) + // expect((fromDb?.contact).displayName).toEqual((party.contact).displayName) + // }) - await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank last names are not allowed') - }) + // it('Should save organization party to database', async (): Promise => { + // const party: NonPersistedParty = { + // uri: 'example.com', + // partyType: { + // type: PartyTypeEnum.ORGANIZATION, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contact: { + // legalName: 'example_legal_name', + // displayName: 'example_display_name', + // }, + // } + // + // const partyEntity: PartyEntity = partyEntityFrom(party) + // await dbConnection.getRepository(PartyEntity).save(partyEntity, { + // transaction: true, + // }) + // + // const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + // where: { id: partyEntity.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.identities?.length).toEqual(0) + // expect(fromDb?.uri).toEqual(party.uri) + // expect(fromDb?.partyType).toBeDefined() + // expect(fromDb?.partyType.type).toEqual(party.partyType.type) + // expect(fromDb?.partyType.tenantId).toEqual(party.partyType.tenantId) + // expect(fromDb?.partyType.name).toEqual(party.partyType.name) + // expect(fromDb?.contact).toBeDefined() + // expect((fromDb?.contact).legalName).toEqual((party.contact).legalName) + // expect((fromDb?.contact).displayName).toEqual((party.contact).displayName) + // }) + // + // it('Should result in party relationship for the owner side only', async (): Promise => { + // const party1: NonPersistedParty = { + // uri: 'example1.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name1', + // }, + // contact: { + // firstName: 'example_first_name1', + // middleName: 'example_middle_name1', + // lastName: 'example_last_name1', + // displayName: 'example_display_name1', + // }, + // } + // + // const partyEntity1: PartyEntity = partyEntityFrom(party1) + // const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { + // transaction: true, + // }) + // + // const party2: NonPersistedParty = { + // uri: 'example2.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + // name: 'example_name2', + // }, + // contact: { + // firstName: 'example_first_name2', + // middleName: 'example_middle_name2', + // lastName: 'example_last_name2', + // displayName: 'example_display_name2', + // }, + // } + // + // const partyEntity2: PartyEntity = partyEntityFrom(party2) + // const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { + // transaction: true, + // }) + // + // const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ + // leftId: savedParty1.id, + // rightId: savedParty2.id, + // }) + // + // await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { + // transaction: true, + // }) + // + // const fromDb1: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + // where: { id: savedParty1.id }, + // }) + // + // const fromDb2: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + // where: { id: savedParty2.id }, + // }) + // + // expect(fromDb1).toBeDefined() + // expect(fromDb1?.relationships.length).toEqual(1) + // expect(fromDb2).toBeDefined() + // expect(fromDb2?.relationships.length).toEqual(0) + // }) + // + // it('should throw error when saving person party with blank first name', async (): Promise => { + // const party: NonPersistedParty = { + // uri: 'example.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contact: { + // firstName: '', + // middleName: 'example_middle_name1', + // lastName: 'example_last_name1', + // displayName: 'example_display_name1', + // }, + // } + // + // const partyEntity: PartyEntity = partyEntityFrom(party) + // + // await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank first names are not allowed') + // }) + // + // it('should throw error when saving person party with blank middle name', async (): Promise => { + // const party: NonPersistedParty = { + // uri: 'example.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contact: { + // firstName: 'example_first_name', + // middleName: '', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const partyEntity: PartyEntity = partyEntityFrom(party) + // + // await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank middle names are not allowed') + // }) + // + // it('should throw error when saving person party with blank last name', async (): Promise => { + // const party: NonPersistedParty = { + // uri: 'example.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contact: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: '', + // displayName: 'example_display_name', + // }, + // } + // + // const partyEntity: PartyEntity = partyEntityFrom(party) + // + // await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank last names are not allowed') + // }) it('should throw error when saving person party with blank display name', async (): Promise => { const party: NonPersistedParty = { @@ -315,1890 +317,1890 @@ describe('Database entities tests', (): void => { await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank display names are not allowed') }) - it('should throw error when saving organization party with blank legal name', async (): Promise => { - const party: NonPersistedParty = { - uri: 'example.com', - partyType: { - type: PartyTypeEnum.ORGANIZATION, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contact: { - legalName: '', - displayName: 'example_legal_name', - }, - } - - const partyEntity: PartyEntity = partyEntityFrom(party) - - await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank legal names are not allowed') - }) - - it('should throw error when saving organization party with blank display name', async (): Promise => { - const party: NonPersistedParty = { - uri: 'example.com', - partyType: { - type: PartyTypeEnum.ORGANIZATION, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contact: { - legalName: 'example_first_name', - displayName: '', - }, - } - - const partyEntity: PartyEntity = partyEntityFrom(party) - - await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank display names are not allowed') - }) - - it('should throw error when saving party with blank party type name', async (): Promise => { - const party: NonPersistedParty = { - uri: 'example.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: '', - }, - contact: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const partyEntity: PartyEntity = partyEntityFrom(party) - - await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank names are not allowed') - }) - - it('should throw error when saving party with blank party type description', async (): Promise => { - const party: NonPersistedParty = { - uri: 'example.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - description: '', - }, - contact: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const partyEntity: PartyEntity = partyEntityFrom(party) - - await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank descriptions are not allowed') - }) - - it('should throw error when saving party with blank party type tenant id', async (): Promise => { - const party: NonPersistedParty = { - uri: 'example.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '', - name: 'example_name', - }, - contact: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const partyEntity: PartyEntity = partyEntityFrom(party) - - await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError("Blank tenant id's are not allowed") - }) - - it('Should enforce unique alias for an identity', async (): Promise => { - const alias = 'non_unique_alias' - const identity1: NonPersistedIdentity = { - alias, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId: 'unique_correlationId1', - }, - } - const identity1Entity: IdentityEntity = identityEntityFrom(identity1) - await dbConnection.getRepository(IdentityEntity).save(identity1Entity) - - const identity2: NonPersistedIdentity = { - alias: alias, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId: 'unique_correlationId2', - }, - } - const identity2Entity: IdentityEntity = identityEntityFrom(identity2) - await expect(dbConnection.getRepository(IdentityEntity).save(identity2Entity)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: Identity.alias' - ) - }) - - it('Should enforce unique correlationId for a identity', async (): Promise => { - const correlationId = 'non_unique_correlationId' - const identity1: NonPersistedIdentity = { - alias: 'unique_alias1', - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId, - }, - } - const identity1Entity: IdentityEntity = identityEntityFrom(identity1) - await dbConnection.getRepository(IdentityEntity).save(identity1Entity) - - const identity2: NonPersistedIdentity = { - alias: 'unique_alias2', - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId, - }, - } - const identity2Entity: IdentityEntity = identityEntityFrom(identity2) - await expect(dbConnection.getRepository(IdentityEntity).save(identity2Entity)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: CorrelationIdentifier.correlation_id' - ) - }) - - it('Should save identity to database', async (): Promise => { - const correlationId = 'example_did' - const identity: NonPersistedIdentity = { - alias: correlationId, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId, - }, - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - - await dbConnection.getRepository(IdentityEntity).save(identityEntity) - - const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ - where: { - identifier: { - correlationId, - }, - }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.connection).toBeNull() - expect(fromDb?.identifier).toBeDefined() - expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) - expect(fromDb?.identifier.type).toEqual(identity.identifier.type) - }) - - it('should throw error when saving identity with blank alias', async (): Promise => { - const identity: NonPersistedIdentity = { - alias: '', - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId: 'example_did', - }, - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - - await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank aliases are not allowed') - }) - - it('should throw error when saving identity with blank correlation id', async (): Promise => { - const identity: NonPersistedIdentity = { - alias: 'example_did', - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId: '', - }, - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - - await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank correlation ids are not allowed') - }) - - it('should throw error when saving identity with blank metadata label', async (): Promise => { - const correlationId = 'example_did' - const identity: NonPersistedIdentity = { - alias: correlationId, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId, - }, - metadata: [ - { - label: '', - value: 'example_value', - }, - ], - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - - await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank metadata labels are not allowed') - }) - - it('should throw error when saving identity with blank metadata value', async (): Promise => { - const correlationId = 'example_did' - const identity: NonPersistedIdentity = { - alias: correlationId, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId, - }, - metadata: [ - { - label: 'example_label', - value: '', - }, - ], - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - - await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank metadata values are not allowed') - }) - - it('Should save identity with openid connection to database', async (): Promise => { - const correlationId = 'example.com' - const identity: NonPersistedIdentity = { - alias: correlationId, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.URL, - correlationId, - }, - connection: { - type: ConnectionTypeEnum.OPENID_CONNECT, - config: { - clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', - clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', - scopes: ['auth'], - issuer: 'https://example.com/app-test', - redirectUrl: 'app:/callback', - dangerouslyAllowInsecureHttpRequests: true, - clientAuthMethod: 'post', - }, - }, - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - - await dbConnection.getRepository(IdentityEntity).save(identityEntity) - - const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ - where: { - identifier: { - correlationId, - }, - }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.connection).toBeDefined() - expect(fromDb?.identifier).toBeDefined() - expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) - expect(fromDb?.identifier.type).toEqual(identity.identifier.type) - expect(fromDb?.connection?.type).toEqual(identity.connection?.type) - expect(fromDb?.connection?.config).toBeDefined() - expect((fromDb?.connection?.config).clientId).toEqual((identity.connection?.config).clientId) - }) - - it('Should save identity with didauth connection to database', async (): Promise => { - const correlationId = 'example.com' - const identity: NonPersistedIdentity = { - alias: correlationId, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.URL, - correlationId, - }, - connection: { - type: ConnectionTypeEnum.SIOPv2, - config: { - identifier: { - did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - provider: 'test_provider', - keys: [], - services: [], - }, - redirectUrl: 'https://example.com', - stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', - sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - }, - }, - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - - await dbConnection.getRepository(IdentityEntity).save(identityEntity) - - const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ - where: { - identifier: { - correlationId, - }, - }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.connection).toBeDefined() - expect(fromDb?.identifier).toBeDefined() - expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) - expect(fromDb?.identifier.type).toEqual(identity.identifier.type) - expect(fromDb?.connection?.type).toEqual(identity.connection?.type) - expect(fromDb?.connection?.config).toBeDefined() - expect((fromDb?.connection?.config).identifier).toEqual( - (identity.connection?.config).identifier.did - ) - }) - - it('Should save connection with openid config to database', async (): Promise => { - const connection: NonPersistedConnection = { - type: ConnectionTypeEnum.OPENID_CONNECT, - config: { - clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', - clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', - scopes: ['auth'], - issuer: 'https://example.com/app-test', - redirectUrl: 'app:/callback', - dangerouslyAllowInsecureHttpRequests: true, - clientAuthMethod: 'post', - }, - } - const connectionEntity: ConnectionEntity = connectionEntityFrom(connection) - await dbConnection.getRepository(ConnectionEntity).save(connectionEntity, { - transaction: true, - }) - - const fromDb: ConnectionEntity | null = await dbConnection.getRepository(ConnectionEntity).findOne({ - where: { type: connection.type }, - }) - - expect(fromDb).toBeDefined() - - const fromDbConfig: OpenIdConfigEntity | null = await dbConnection.getRepository(OpenIdConfigEntity).findOne({ - where: { id: fromDb?.id }, - }) - - expect(fromDbConfig).toBeDefined() - expect(fromDb?.type).toEqual(connection.type) - expect(fromDb?.config).toBeDefined() - expect((fromDb?.config).clientId).toEqual((connection.config).clientId) - }) - - it('Should save connection with didauth config to database', async (): Promise => { - const connection: NonPersistedConnection = { - type: ConnectionTypeEnum.SIOPv2, - config: { - identifier: { - did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - provider: 'test_provider', - keys: [], - services: [], - }, - redirectUrl: 'https://example.com', - stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', - sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - }, - } - const connectionEntity: ConnectionEntity = connectionEntityFrom(connection) - await dbConnection.getRepository(ConnectionEntity).save(connectionEntity, { - transaction: true, - }) - - const fromDb: ConnectionEntity | null = await dbConnection.getRepository(ConnectionEntity).findOne({ - where: { type: connection.type }, - }) - - expect(fromDb).toBeDefined() - - const fromDbConfig: DidAuthConfigEntity | null = await dbConnection.getRepository(DidAuthConfigEntity).findOne({ - where: { id: fromDb?.id }, - }) - - expect(fromDbConfig).toBeDefined() - expect(fromDb?.type).toEqual(connection.type) - expect(fromDb?.config).toBeDefined() - expect((fromDb?.config).identifier).toEqual((connection.config).identifier.did) - }) - - it('Should save openid config to database', async (): Promise => { - const clientId = '138d7bf8-c930-4c6e-b928-97d3a4928b01' - const config: NonPersistedOpenIdConfig = { - clientId, - clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', - scopes: ['auth'], - issuer: 'https://example.com/app-test', - redirectUrl: 'app:/callback', - dangerouslyAllowInsecureHttpRequests: true, - clientAuthMethod: 'post', - } - - const configEntity: OpenIdConfigEntity = openIdConfigEntityFrom(config) - await dbConnection.getRepository(OpenIdConfigEntity).save(configEntity, { - transaction: true, - }) - - const fromDb: OpenIdConfigEntity | null = await dbConnection.getRepository(OpenIdConfigEntity).findOne({ - where: { clientId: config.clientId }, - }) - - expect(fromDb).toBeDefined() - expect((fromDb).clientId).toEqual(config.clientId) - }) - - it('Should save didauth config to database', async (): Promise => { - const sessionId = 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01' - const config: NonPersistedDidAuthConfig = { - identifier: { - did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - provider: 'test_provider', - keys: [], - services: [], - }, - redirectUrl: 'https://example.com', - stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', - sessionId, - } - - const configEntity: DidAuthConfigEntity = didAuthConfigEntityFrom(config) - await dbConnection.getRepository(DidAuthConfigEntity).save(configEntity, { - transaction: true, - }) - - const fromDb: DidAuthConfigEntity | null = await dbConnection.getRepository(DidAuthConfigEntity).findOne({ - where: { sessionId: config.sessionId }, - }) - - expect(fromDb).toBeDefined() - expect((fromDb).identifier).toEqual(config.identifier.did) - }) - - it('Should delete party and all child relations', async (): Promise => { - const party1: NonPersistedParty = { - uri: 'example.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name1', - }, - contact: { - firstName: 'example_first_name1', - middleName: 'example_middle_name1', - lastName: 'example_last_name1', - displayName: 'example_display_name1', - }, - } - - const partyEntity1: PartyEntity = partyEntityFrom(party1) - const savedParty1: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity1) - - expect(savedParty1).toBeDefined() - - const party2: NonPersistedParty = { - uri: 'example.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - name: 'example_name2', - }, - contact: { - firstName: 'example_first_name2', - middleName: 'example_middle_name2', - lastName: 'example_last_name2', - displayName: 'example_display_name2', - }, - } - - const partyEntity2: PartyEntity = partyEntityFrom(party2) - const savedParty2: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity2) - - expect(savedParty2).toBeDefined() - - const correlationId = 'relation_example.com' - const identity: NonPersistedIdentity = { - alias: correlationId, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.URL, - correlationId, - }, - connection: { - type: ConnectionTypeEnum.OPENID_CONNECT, - config: { - clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', - clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', - scopes: ['auth'], - issuer: 'https://example.com/app-test', - redirectUrl: 'app:/callback', - dangerouslyAllowInsecureHttpRequests: true, - clientAuthMethod: 'post', - }, - }, - metadata: [ - { - label: 'example_label', - value: 'example_value', - }, - ], - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - identityEntity.party = savedParty1 - - const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) - - expect(savedIdentity).toBeDefined() - - const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ - leftId: savedParty1.id, - rightId: savedParty2.id, - }) - - const savedRelationship: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { - transaction: true, - }) - - expect(savedRelationship).toBeDefined() - - expect( - await dbConnection.getRepository(PartyEntity).findOne({ - where: { id: savedParty1.id }, - }) - ).toBeDefined() - - await dbConnection.getRepository(PartyEntity).delete({ id: savedParty1.id }) - - // check party - await expect( - await dbConnection.getRepository(PartyEntity).findOne({ - where: { id: savedParty1.id }, - }) - ).toBeNull() - - // check identity - expect( - await dbConnection.getRepository(IdentityEntity).findOne({ - where: { id: savedParty1.id }, - }) - ).toBeNull() - - // check identity identifier - expect( - await dbConnection.getRepository(CorrelationIdentifierEntity).findOne({ - where: { id: savedIdentity.identifier.id }, - }) - ).toBeNull() - - // check identity connection - expect( - await dbConnection.getRepository(ConnectionEntity).findOne({ - where: { id: savedIdentity.connection!.id }, - }) - ).toBeNull() - - // check connection config - expect( - await dbConnection.getRepository(OpenIdConfigEntity).findOne({ - where: { id: savedIdentity.connection!.config.id }, - }) - ).toBeNull() - - // check identity metadata - expect( - await dbConnection.getRepository(IdentityMetadataItemEntity).findOne({ - where: { id: savedIdentity.metadata![0].id }, - }) - ).toBeNull() - - // check contact - expect( - await dbConnection.getRepository(BaseContactEntity).findOne({ - where: { id: savedParty1.contact.id }, - }) - ).toBeNull() - - // check party type - expect( - await dbConnection.getRepository(PartyTypeEntity).findOne({ - where: { id: savedParty1.partyType.id }, - }) - ).toBeDefined() - - // check relation - expect( - await dbConnection.getRepository(PartyRelationshipEntity).findOne({ - where: { id: savedRelationship.id }, - }) - ).toBeNull() - }) - - it('Should delete identity and all child relations', async (): Promise => { - const party: NonPersistedParty = { - uri: 'example.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contact: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const partyEntity: PartyEntity = partyEntityFrom(party) - const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) - - expect(savedParty).toBeDefined() - - const correlationId = 'relation_example.com' - const identity: NonPersistedIdentity = { - alias: correlationId, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.URL, - correlationId, - }, - connection: { - type: ConnectionTypeEnum.SIOPv2, - config: { - identifier: { - did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - provider: 'test_provider', - keys: [], - services: [], - }, - redirectUrl: 'https://example.com', - stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', - sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - }, - }, - metadata: [ - { - label: 'example_label', - value: 'example_value', - }, - ], - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - identityEntity.party = savedParty - - const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) - - expect( - await dbConnection.getRepository(PartyEntity).findOne({ - where: { id: savedParty.id }, - }) - ).toBeDefined() - - await dbConnection.getRepository(IdentityEntity).delete({ id: savedIdentity.id }) - - // check identity - expect( - await dbConnection.getRepository(IdentityEntity).findOne({ - where: { alias: correlationId }, - }) - ).toBeNull() - - // check identity identifier - expect( - await dbConnection.getRepository(CorrelationIdentifierEntity).findOne({ - where: { id: savedIdentity.identifier.id }, - }) - ).toBeNull() - - // check identity connection - expect( - await dbConnection.getRepository(ConnectionEntity).findOne({ - where: { id: savedIdentity.connection!.id }, - }) - ).toBeNull() - - // check connection config - expect( - await dbConnection.getRepository(OpenIdConfigEntity).findOne({ - where: { id: savedIdentity.connection!.config.id }, - }) - ).toBeNull() - - // check identity metadata - expect( - await dbConnection.getRepository(IdentityMetadataItemEntity).findOne({ - where: { id: savedIdentity.metadata![0].id }, - }) - ).toBeNull() - }) - - it('Should not delete party when deleting identity', async (): Promise => { - const party: NonPersistedParty = { - uri: 'example.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contact: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const partyEntity: PartyEntity = partyEntityFrom(party) - const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) - - expect(savedParty).toBeDefined() - - const correlationId = 'relation_example.com' - const identity: NonPersistedIdentity = { - alias: correlationId, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.URL, - correlationId, - }, - connection: { - type: ConnectionTypeEnum.SIOPv2, - config: { - identifier: { - did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - provider: 'test_provider', - keys: [], - services: [], - }, - redirectUrl: 'https://example.com', - stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', - sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - }, - }, - metadata: [ - { - label: 'example_label', - value: 'example_value', - }, - ], - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - identityEntity.party = savedParty - - const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) - - expect(savedIdentity).toBeDefined() - - await dbConnection.getRepository(IdentityEntity).delete({ id: savedIdentity.id }) - - // check identity - expect( - await dbConnection.getRepository(IdentityEntity).findOne({ - where: { id: savedIdentity.id }, - }) - ).toBeNull() - - // check party - expect( - await dbConnection.getRepository(PartyEntity).findOne({ - where: { id: savedParty.id }, - }) - ).toBeDefined() - }) - - it('Should set creation date when saving party', async (): Promise => { - const party: NonPersistedParty = { - uri: 'example.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contact: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const partyEntity: PartyEntity = partyEntityFrom(party) - const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) - - const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - where: { id: savedParty.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.createdAt).toBeDefined() - }) - - it('Should not update creation date when updating party', async (): Promise => { - const party: NonPersistedParty = { - uri: 'example.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contact: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const partyEntity: PartyEntity = partyEntityFrom(party) - const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) - - expect(savedParty).toBeDefined() - - const newContactFirstName = 'new_first_name' - await dbConnection.getRepository(PartyEntity).save({ - ...savedParty, - contact: { - ...savedParty.contact, - firstName: newContactFirstName, - }, - }) - - const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - where: { id: savedParty.id }, - }) - - expect(fromDb).toBeDefined() - expect((fromDb?.contact).firstName).toEqual(newContactFirstName) - expect(fromDb?.createdAt).toEqual(savedParty?.createdAt) - }) - - it('Should set creation date when saving identity', async (): Promise => { - const correlationId = 'example_did' - const identity: NonPersistedIdentity = { - alias: correlationId, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId, - }, - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - await dbConnection.getRepository(IdentityEntity).save(identityEntity) - - const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ - where: { - identifier: { - correlationId, - }, - }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.createdAt).toBeDefined() - }) - - it('Should not update creation date when saving identity', async (): Promise => { - const correlationId = 'example_did' - const identity: NonPersistedIdentity = { - alias: correlationId, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId, - }, - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) - const newCorrelationId = 'new_example_did' - await dbConnection - .getRepository(IdentityEntity) - .save({ ...savedIdentity, identifier: { ...savedIdentity.identifier, correlationId: newCorrelationId } }) - - const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ - where: { - identifier: { - correlationId: newCorrelationId, - }, - }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.createdAt).toEqual(savedIdentity?.createdAt) - }) - - it('Should set last updated date when saving party', async (): Promise => { - const party: NonPersistedParty = { - uri: 'example.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contact: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const partyEntity: PartyEntity = partyEntityFrom(party) - const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) - - const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - where: { id: savedParty.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.lastUpdatedAt).toBeDefined() - }) - - it('Should update last updated date when updating party', async (): Promise => { - const party: NonPersistedParty = { - uri: 'example.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contact: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const partyEntity: PartyEntity = partyEntityFrom(party) - const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) - expect(savedParty).toBeDefined() - - // waiting here to get a different timestamp - await new Promise((resolve) => setTimeout(resolve, 2000)) - - const newContactFirstName = 'new_first_name' - await dbConnection.getRepository(PartyEntity).save({ - ...savedParty, - // FIXME there is still an issue when updating nested objects, the parent does not update - // https://github.com/typeorm/typeorm/issues/5378 - uri: 'new uri', // TODO remove this to trigger the bug - contact: { - ...savedParty.contact, - firstName: newContactFirstName, - }, - }) - - const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - where: { id: savedParty.id }, - }) - - expect(fromDb).toBeDefined() - expect((fromDb?.contact).firstName).toEqual(newContactFirstName) - expect(fromDb?.lastUpdatedAt).not.toEqual(savedParty?.lastUpdatedAt) - }) - - it('Should set last updated date when saving party type', async (): Promise => { - const partyType: NonPersistedPartyType = { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - } - - const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) - const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) - - const fromDb: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).findOne({ - where: { id: savedPartyType.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.lastUpdatedAt).toBeDefined() - }) - - it('Should set last creation date when saving party type', async (): Promise => { - const partyType: NonPersistedPartyType = { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - } - - const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) - const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) - - const fromDb: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).findOne({ - where: { id: savedPartyType.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.createdAt).toBeDefined() - }) - - it('Should set last updated date when saving identity', async (): Promise => { - const correlationId = 'example_did' - const identity: NonPersistedIdentity = { - alias: correlationId, - roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - identifier: { - type: CorrelationIdentifierEnum.DID, - correlationId, - }, - } - - const identityEntity: IdentityEntity = identityEntityFrom(identity) - await dbConnection.getRepository(IdentityEntity).save(identityEntity) - - const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ - where: { - identifier: { - correlationId, - }, - }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.lastUpdatedAt).toBeDefined() - }) - - it('Should enforce unique type and tenant id combination when saving party type', async (): Promise => { - const tenantId = 'non_unique_value' - const name = 'non_unique_value' - const partyType1: NonPersistedPartyType = { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId, - name, - } - - const partyTypeEntity1: PartyTypeEntity = partyTypeEntityFrom(partyType1) - const savedPartyType1: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity1) - - expect(savedPartyType1).toBeDefined() - - const partyType2: NonPersistedPartyType = { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId, - name, - } - - const partyTypeEntity2: PartyTypeEntity = partyTypeEntityFrom(partyType2) - await expect(dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity2)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: PartyType.type, PartyType.tenant_id' - ) - }) - - it('Should enforce unique name when saving party type', async (): Promise => { - const name = 'non_unique_value' - const partyType1: NonPersistedPartyType = { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name, - } - - const partyTypeEntity1: PartyTypeEntity = partyTypeEntityFrom(partyType1) - const savedPartyType1: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity1) - - expect(savedPartyType1).toBeDefined() - - const partyType2: NonPersistedPartyType = { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - name, - } - - const partyTypeEntity2: PartyTypeEntity = partyTypeEntityFrom(partyType2) - await expect(dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity2)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: PartyType.name' - ) - }) - - it('Should enforce unique legal name when saving organization', async (): Promise => { - const legalName = 'non_unique_value' - const organization1: NonPersistedOrganization = { - legalName, - displayName: 'example_display_name', - } - - const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) - const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { - transaction: true, - }) - - expect(savedOrganization1).toBeDefined() - - const organization2: NonPersistedOrganization = { - legalName, - displayName: 'example_display_name', - } - - const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) - await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: BaseContact.legal_name' - ) - }) - - it('Should enforce unique legal name when saving organization', async (): Promise => { - const legalName = 'example_legal_name' - const organization1: NonPersistedOrganization = { - legalName, - displayName: 'example_display_name', - } - - const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) - const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { - transaction: true, - }) - - expect(savedOrganization1).toBeDefined() - - const organization2: NonPersistedOrganization = { - legalName, - displayName: 'example_display_name', - } - - const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) - await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: BaseContact.legal_name' - ) - }) - - it('Should save party relationship to database', async (): Promise => { - const party1: NonPersistedParty = { - uri: 'example1.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name1', - }, - contact: { - firstName: 'example_first_name1', - middleName: 'example_middle_name1', - lastName: 'example_last_name1', - displayName: 'example_display_name1', - }, - } - - const partyEntity1: PartyEntity = partyEntityFrom(party1) - const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { - transaction: true, - }) - - expect(savedParty1).toBeDefined() - - const party2: NonPersistedParty = { - uri: 'example2.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - name: 'example_name2', - }, - contact: { - firstName: 'example_first_name2', - middleName: 'example_middle_name2', - lastName: 'example_last_name2', - displayName: 'example_display_name2', - }, - } - - const partyEntity2: PartyEntity = partyEntityFrom(party2) - const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { - transaction: true, - }) - - expect(savedParty2).toBeDefined() - - const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ - leftId: savedParty1.id, - rightId: savedParty2.id, - }) - - await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { - transaction: true, - }) - - // TODO check the relation field - const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - where: { id: partyEntity1.id }, - }) - - expect(fromDb).toBeDefined() - }) - - it('Should set last updated date when saving party relationship', async (): Promise => { - const party1: NonPersistedParty = { - uri: 'example1.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name1', - }, - contact: { - firstName: 'example_first_name1', - middleName: 'example_middle_name1', - lastName: 'example_last_name1', - displayName: 'example_display_name1', - }, - } - - const partyEntity1: PartyEntity = partyEntityFrom(party1) - const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { - transaction: true, - }) - - const party2: NonPersistedParty = { - uri: 'example2.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - name: 'example_name2', - }, - contact: { - firstName: 'example_first_name2', - middleName: 'example_middle_name2', - lastName: 'example_last_name2', - displayName: 'example_display_name2', - }, - } - - const partyEntity2: PartyEntity = partyEntityFrom(party2) - const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { - transaction: true, - }) - - const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ - leftId: savedParty1.id, - rightId: savedParty2.id, - }) - - await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { - transaction: true, - }) - - const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - where: { id: partyEntity1.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.lastUpdatedAt).toBeDefined() - }) - - it('Should set creation date when saving party relationship', async (): Promise => { - const party1: NonPersistedParty = { - uri: 'example1.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name1', - }, - contact: { - firstName: 'example_first_name1', - middleName: 'example_middle_name1', - lastName: 'example_last_name1', - displayName: 'example_display_name1', - }, - } - - const partyEntity1: PartyEntity = partyEntityFrom(party1) - const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { - transaction: true, - }) - - const party2: NonPersistedParty = { - uri: 'example2.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - name: 'example_name2', - }, - contact: { - firstName: 'example_first_name2', - middleName: 'example_middle_name2', - lastName: 'example_last_name2', - displayName: 'example_display_name2', - }, - } - - const partyEntity2: PartyEntity = partyEntityFrom(party2) - const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { - transaction: true, - }) - - const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ - leftId: savedParty1.id, - rightId: savedParty2.id, - }) - - await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { - transaction: true, - }) - - const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - where: { id: partyEntity1.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.createdAt).toBeDefined() - }) - - it('Should save bidirectional party relationships to database', async (): Promise => { - const party1: NonPersistedParty = { - uri: 'example1.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name1', - }, - contact: { - firstName: 'example_first_name1', - middleName: 'example_middle_name1', - lastName: 'example_last_name1', - displayName: 'example_display_name1', - }, - } - - const partyEntity1: PartyEntity = partyEntityFrom(party1) - const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { - transaction: true, - }) - - expect(savedParty1).toBeDefined() - - const party2: NonPersistedParty = { - uri: 'example2.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - name: 'example_name2', - }, - contact: { - firstName: 'example_first_name2', - middleName: 'example_middle_name2', - lastName: 'example_last_name2', - displayName: 'example_display_name2', - }, - } - - const partyEntity2: PartyEntity = partyEntityFrom(party2) - const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { - transaction: true, - }) - - expect(savedParty2).toBeDefined() - - const relationship1: PartyRelationshipEntity = partyRelationshipEntityFrom({ - leftId: savedParty1.id, - rightId: savedParty2.id, - }) - - const savedRelationship1: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship1, { - transaction: true, - }) - - expect(savedRelationship1).toBeDefined() - - const relationship2: PartyRelationshipEntity = partyRelationshipEntityFrom({ - leftId: savedParty2.id, - rightId: savedParty1.id, - }) - - const savedRelationship2: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship2, { - transaction: true, - }) - - expect(savedRelationship2).toBeDefined() - - const fromDb: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).findOne({ - where: { id: savedRelationship2.id }, - }) - - expect(fromDb).toBeDefined() - }) - - it('Should enforce unique owner combination for party relationship', async (): Promise => { - const party1: NonPersistedParty = { - uri: 'example1.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name1', - }, - contact: { - firstName: 'example_first_name1', - middleName: 'example_middle_name1', - lastName: 'example_last_name1', - displayName: 'example_display_name1', - }, - } - - const partyEntity1: PartyEntity = partyEntityFrom(party1) - const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { - transaction: true, - }) - - expect(savedParty1).toBeDefined() - - const party2: NonPersistedParty = { - uri: 'example2.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - name: 'example_name2', - }, - contact: { - firstName: 'example_first_name2', - middleName: 'example_middle_name2', - lastName: 'example_last_name2', - displayName: 'example_display_name2', - }, - } - - const partyEntity2: PartyEntity = partyEntityFrom(party2) - const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { - transaction: true, - }) - - expect(savedParty2).toBeDefined() - - const relationship1: PartyRelationshipEntity = partyRelationshipEntityFrom({ - leftId: savedParty1.id, - rightId: savedParty2.id, - }) - - const savedRelationship1: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship1, { - transaction: true, - }) - - expect(savedRelationship1).toBeDefined() - - const relationship2: PartyRelationshipEntity = partyRelationshipEntityFrom({ - leftId: savedParty1.id, - rightId: savedParty2.id, - }) - - await expect(dbConnection.getRepository(PartyRelationshipEntity).save(relationship2)).rejects.toThrowError( - 'SQLITE_CONSTRAINT: UNIQUE constraint failed: PartyRelationship.left_id, PartyRelationship.right_id' - ) - }) - - it('Should save party type to database', async (): Promise => { - const partyType: NonPersistedPartyType = { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - } - - const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) - const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) - - const fromDb: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).findOne({ - where: { id: savedPartyType.id }, - }) - - expect(fromDb).toBeDefined() - }) - - it('Should save person to database', async (): Promise => { - const person: NonPersistedNaturalPerson = { - firstName: 'example_first_name', - lastName: 'lastName2', - displayName: 'displayName', - } - - const personEntity: NaturalPersonEntity = naturalPersonEntityFrom(person) - const savedPerson: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).save(personEntity, { - transaction: true, - }) - - const fromDb: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).findOne({ - where: { id: savedPerson.id }, - }) - - expect(fromDb).toBeDefined() - }) - - it('Should set last updated date when saving person', async (): Promise => { - const person: NonPersistedNaturalPerson = { - firstName: 'example_first_name', - lastName: 'lastName2', - displayName: 'displayName', - } - - const personEntity: NaturalPersonEntity = naturalPersonEntityFrom(person) - const savedPerson: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).save(personEntity, { - transaction: true, - }) - - const fromDb: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).findOne({ - where: { id: savedPerson.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.lastUpdatedAt).toBeDefined() - }) - - it('Should set creation date when saving person', async (): Promise => { - const person: NonPersistedNaturalPerson = { - firstName: 'example_first_name', - lastName: 'lastName2', - displayName: 'displayName', - } - - const personEntity: NaturalPersonEntity = naturalPersonEntityFrom(person) - const savedPerson: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).save(personEntity, { - transaction: true, - }) - - const fromDb: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).findOne({ - where: { id: savedPerson.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.createdAt).toBeDefined() - }) - - it('Should save organization to database', async (): Promise => { - const organization: NonPersistedOrganization = { - legalName: 'example_legal_name', - displayName: 'example_display_name', - } - - const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) - const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { - transaction: true, - }) - - const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ - where: { id: savedOrganization.id }, - }) - - expect(fromDb).toBeDefined() - }) - - it('Should set last updated date when saving organization', async (): Promise => { - const organization: NonPersistedOrganization = { - legalName: 'example_legal_name', - displayName: 'example_display_name', - } - - const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) - const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { - transaction: true, - }) - - const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ - where: { id: savedOrganization.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.lastUpdatedAt).toBeDefined() - }) - - it('Should set creation date when saving organization', async (): Promise => { - const organization: NonPersistedOrganization = { - legalName: 'example_legal_name', - displayName: 'example_display_name', - } - - const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) - const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { - transaction: true, - }) - - const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ - where: { id: savedOrganization.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.createdAt).toBeDefined() - }) - - it('Should get party based on person information', async (): Promise => { - const firstName = 'example_first_name' - const party: NonPersistedParty = { - uri: 'example.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contact: { - firstName, - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const partyEntity: PartyEntity = partyEntityFrom(party) - await dbConnection.getRepository(PartyEntity).save(partyEntity, { - transaction: true, - }) - - const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - where: { - contact: { - firstName, - } as FindOptionsWhere, //NaturalPersonEntity | OrganizationEntity - }, - }) - - expect(fromDb).toBeDefined() - }) - - it('Should get party based on organization information', async (): Promise => { - const legalName = 'example_legal_name' - const party: NonPersistedParty = { - uri: 'example.com', - partyType: { - type: PartyTypeEnum.ORGANIZATION, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contact: { - legalName, - displayName: 'example_display_name', - }, - } - - const partyEntity: PartyEntity = partyEntityFrom(party) - await dbConnection.getRepository(PartyEntity).save(partyEntity, { - transaction: true, - }) - - const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - where: { - contact: { - legalName, - } as FindOptionsWhere, //NaturalPersonEntity | OrganizationEntity - }, - }) - - expect(fromDb).toBeDefined() - }) - - it("Should enforce unique party id's for relationship sides", async (): Promise => { - const party: NonPersistedParty = { - uri: 'example.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contact: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const partyEntity: PartyEntity = partyEntityFrom(party) - const savedParty: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity, { - transaction: true, - }) - - expect(savedParty).toBeDefined() - - const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ - leftId: savedParty.id, - rightId: savedParty.id, - }) - - await expect(dbConnection.getRepository(PartyRelationshipEntity).save(relationship)).rejects.toThrowError( - 'Cannot use the same id for both sides of the relationship' - ) - }) - - it('Should delete party relationship', async (): Promise => { - const party1: NonPersistedParty = { - uri: 'example1.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name1', - }, - contact: { - firstName: 'example_first_name1', - middleName: 'example_middle_name1', - lastName: 'example_last_name1', - displayName: 'example_display_name1', - }, - } - - const partyEntity1: PartyEntity = partyEntityFrom(party1) - const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { - transaction: true, - }) - - expect(savedParty1).toBeDefined() - - const party2: NonPersistedParty = { - uri: 'example2.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - name: 'example_name2', - }, - contact: { - firstName: 'example_first_name2', - middleName: 'example_middle_name2', - lastName: 'example_last_name2', - displayName: 'example_display_name2', - }, - } - - const partyEntity2: PartyEntity = partyEntityFrom(party2) - const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { - transaction: true, - }) - - expect(savedParty2).toBeDefined() - - const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ - leftId: savedParty1.id, - rightId: savedParty2.id, - }) - - const savedRelationship: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { - transaction: true, - }) - - expect(savedRelationship).toBeDefined() - - await dbConnection.getRepository(PartyRelationshipEntity).delete({ id: savedRelationship.id }) - - await expect( - await dbConnection.getRepository(PartyRelationshipEntity).findOne({ - where: { id: savedRelationship.id }, - }) - ).toBeNull() - }) - - it('Should delete party type', async (): Promise => { - const partyType: NonPersistedPartyType = { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - } - - const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) - const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) - - expect(savedPartyType).toBeDefined() - - await dbConnection.getRepository(PartyTypeEntity).delete({ id: savedPartyType.id }) - - await expect( - await dbConnection.getRepository(PartyTypeEntity).findOne({ - where: { id: savedPartyType.id }, - }) - ).toBeNull() - }) - - it('Should not be able to remove party type when used by parties', async (): Promise => { - const party: NonPersistedParty = { - uri: 'example.com', - partyType: { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - }, - contact: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const partyEntity: PartyEntity = partyEntityFrom(party) - const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity, { - transaction: true, - }) - - expect(savedParty).toBeDefined() - - await expect(dbConnection.getRepository(PartyTypeEntity).delete({ id: savedParty.partyType.id })).rejects.toThrowError( - 'FOREIGN KEY constraint failed' - ) - }) - - it('Should save party with existing party type', async (): Promise => { - const partyType: NonPersistedPartyType = { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - } - - const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) - const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) - - const party: NonPersistedParty = { - uri: 'example.com', - partyType: savedPartyType, - contact: { - firstName: 'example_first_name', - middleName: 'example_middle_name', - lastName: 'example_last_name', - displayName: 'example_display_name', - }, - } - - const partyEntity: PartyEntity = partyEntityFrom(party) - partyEntity.partyType = savedPartyType - await dbConnection.getRepository(PartyEntity).save(partyEntity, { - transaction: true, - }) - - const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - where: { id: partyEntity.id }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.partyType).toBeDefined() - expect(fromDb?.partyType.id).toEqual(savedPartyType.id) - expect(fromDb?.partyType.type).toEqual(savedPartyType.type) - expect(fromDb?.partyType.tenantId).toEqual(savedPartyType.tenantId) - expect(fromDb?.partyType.name).toEqual(savedPartyType.name) - }) - - it('Should not update creation date when saving party type', async (): Promise => { - const partyType: NonPersistedPartyType = { - type: PartyTypeEnum.NATURAL_PERSON, - tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - name: 'example_name', - } - - const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) - const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) - await dbConnection.getRepository(PartyTypeEntity).save({ ...savedPartyType, type: PartyTypeEnum.ORGANIZATION }) - - const fromDb: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).findOne({ - where: { - type: PartyTypeEnum.ORGANIZATION, - }, - }) - - expect(fromDb).toBeDefined() - expect(fromDb?.createdAt).toEqual(savedPartyType?.createdAt) - }) + // it('should throw error when saving organization party with blank legal name', async (): Promise => { + // const party: NonPersistedParty = { + // uri: 'example.com', + // partyType: { + // type: PartyTypeEnum.ORGANIZATION, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contact: { + // legalName: '', + // displayName: 'example_legal_name', + // }, + // } + // + // const partyEntity: PartyEntity = partyEntityFrom(party) + // + // await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank legal names are not allowed') + // }) + // + // it('should throw error when saving organization party with blank display name', async (): Promise => { + // const party: NonPersistedParty = { + // uri: 'example.com', + // partyType: { + // type: PartyTypeEnum.ORGANIZATION, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contact: { + // legalName: 'example_first_name', + // displayName: '', + // }, + // } + // + // const partyEntity: PartyEntity = partyEntityFrom(party) + // + // await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank display names are not allowed') + // }) + // + // it('should throw error when saving party with blank party type name', async (): Promise => { + // const party: NonPersistedParty = { + // uri: 'example.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: '', + // }, + // contact: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const partyEntity: PartyEntity = partyEntityFrom(party) + // + // await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank names are not allowed') + // }) + // + // it('should throw error when saving party with blank party type description', async (): Promise => { + // const party: NonPersistedParty = { + // uri: 'example.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // description: '', + // }, + // contact: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const partyEntity: PartyEntity = partyEntityFrom(party) + // + // await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank descriptions are not allowed') + // }) + // + // it('should throw error when saving party with blank party type tenant id', async (): Promise => { + // const party: NonPersistedParty = { + // uri: 'example.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '', + // name: 'example_name', + // }, + // contact: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const partyEntity: PartyEntity = partyEntityFrom(party) + // + // await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError("Blank tenant id's are not allowed") + // }) + // + // it('Should enforce unique alias for an identity', async (): Promise => { + // const alias = 'non_unique_alias' + // const identity1: NonPersistedIdentity = { + // alias, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId: 'unique_correlationId1', + // }, + // } + // const identity1Entity: IdentityEntity = identityEntityFrom(identity1) + // await dbConnection.getRepository(IdentityEntity).save(identity1Entity) + // + // const identity2: NonPersistedIdentity = { + // alias: alias, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId: 'unique_correlationId2', + // }, + // } + // const identity2Entity: IdentityEntity = identityEntityFrom(identity2) + // await expect(dbConnection.getRepository(IdentityEntity).save(identity2Entity)).rejects.toThrowError( + // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: Identity.alias' + // ) + // }) + // + // it('Should enforce unique correlationId for a identity', async (): Promise => { + // const correlationId = 'non_unique_correlationId' + // const identity1: NonPersistedIdentity = { + // alias: 'unique_alias1', + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId, + // }, + // } + // const identity1Entity: IdentityEntity = identityEntityFrom(identity1) + // await dbConnection.getRepository(IdentityEntity).save(identity1Entity) + // + // const identity2: NonPersistedIdentity = { + // alias: 'unique_alias2', + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId, + // }, + // } + // const identity2Entity: IdentityEntity = identityEntityFrom(identity2) + // await expect(dbConnection.getRepository(IdentityEntity).save(identity2Entity)).rejects.toThrowError( + // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: CorrelationIdentifier.correlation_id' + // ) + // }) + // + // it('Should save identity to database', async (): Promise => { + // const correlationId = 'example_did' + // const identity: NonPersistedIdentity = { + // alias: correlationId, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId, + // }, + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // + // await dbConnection.getRepository(IdentityEntity).save(identityEntity) + // + // const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ + // where: { + // identifier: { + // correlationId, + // }, + // }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.connection).toBeNull() + // expect(fromDb?.identifier).toBeDefined() + // expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) + // expect(fromDb?.identifier.type).toEqual(identity.identifier.type) + // }) + // + // it('should throw error when saving identity with blank alias', async (): Promise => { + // const identity: NonPersistedIdentity = { + // alias: '', + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId: 'example_did', + // }, + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // + // await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank aliases are not allowed') + // }) + // + // it('should throw error when saving identity with blank correlation id', async (): Promise => { + // const identity: NonPersistedIdentity = { + // alias: 'example_did', + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId: '', + // }, + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // + // await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank correlation ids are not allowed') + // }) + // + // it('should throw error when saving identity with blank metadata label', async (): Promise => { + // const correlationId = 'example_did' + // const identity: NonPersistedIdentity = { + // alias: correlationId, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId, + // }, + // metadata: [ + // { + // label: '', + // value: 'example_value', + // }, + // ], + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // + // await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank metadata labels are not allowed') + // }) + // + // it('should throw error when saving identity with blank metadata value', async (): Promise => { + // const correlationId = 'example_did' + // const identity: NonPersistedIdentity = { + // alias: correlationId, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId, + // }, + // metadata: [ + // { + // label: 'example_label', + // value: '', + // }, + // ], + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // + // await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank metadata values are not allowed') + // }) + // + // it('Should save identity with openid connection to database', async (): Promise => { + // const correlationId = 'example.com' + // const identity: NonPersistedIdentity = { + // alias: correlationId, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.URL, + // correlationId, + // }, + // connection: { + // type: ConnectionTypeEnum.OPENID_CONNECT, + // config: { + // clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', + // clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', + // scopes: ['auth'], + // issuer: 'https://example.com/app-test', + // redirectUrl: 'app:/callback', + // dangerouslyAllowInsecureHttpRequests: true, + // clientAuthMethod: 'post', + // }, + // }, + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // + // await dbConnection.getRepository(IdentityEntity).save(identityEntity) + // + // const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ + // where: { + // identifier: { + // correlationId, + // }, + // }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.connection).toBeDefined() + // expect(fromDb?.identifier).toBeDefined() + // expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) + // expect(fromDb?.identifier.type).toEqual(identity.identifier.type) + // expect(fromDb?.connection?.type).toEqual(identity.connection?.type) + // expect(fromDb?.connection?.config).toBeDefined() + // expect((fromDb?.connection?.config).clientId).toEqual((identity.connection?.config).clientId) + // }) + // + // it('Should save identity with didauth connection to database', async (): Promise => { + // const correlationId = 'example.com' + // const identity: NonPersistedIdentity = { + // alias: correlationId, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.URL, + // correlationId, + // }, + // connection: { + // type: ConnectionTypeEnum.SIOPv2, + // config: { + // identifier: { + // did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + // provider: 'test_provider', + // keys: [], + // services: [], + // }, + // redirectUrl: 'https://example.com', + // stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', + // sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + // }, + // }, + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // + // await dbConnection.getRepository(IdentityEntity).save(identityEntity) + // + // const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ + // where: { + // identifier: { + // correlationId, + // }, + // }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.connection).toBeDefined() + // expect(fromDb?.identifier).toBeDefined() + // expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) + // expect(fromDb?.identifier.type).toEqual(identity.identifier.type) + // expect(fromDb?.connection?.type).toEqual(identity.connection?.type) + // expect(fromDb?.connection?.config).toBeDefined() + // expect((fromDb?.connection?.config).identifier).toEqual( + // (identity.connection?.config).identifier.did + // ) + // }) + // + // it('Should save connection with openid config to database', async (): Promise => { + // const connection: NonPersistedConnection = { + // type: ConnectionTypeEnum.OPENID_CONNECT, + // config: { + // clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', + // clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', + // scopes: ['auth'], + // issuer: 'https://example.com/app-test', + // redirectUrl: 'app:/callback', + // dangerouslyAllowInsecureHttpRequests: true, + // clientAuthMethod: 'post', + // }, + // } + // const connectionEntity: ConnectionEntity = connectionEntityFrom(connection) + // await dbConnection.getRepository(ConnectionEntity).save(connectionEntity, { + // transaction: true, + // }) + // + // const fromDb: ConnectionEntity | null = await dbConnection.getRepository(ConnectionEntity).findOne({ + // where: { type: connection.type }, + // }) + // + // expect(fromDb).toBeDefined() + // + // const fromDbConfig: OpenIdConfigEntity | null = await dbConnection.getRepository(OpenIdConfigEntity).findOne({ + // where: { id: fromDb?.id }, + // }) + // + // expect(fromDbConfig).toBeDefined() + // expect(fromDb?.type).toEqual(connection.type) + // expect(fromDb?.config).toBeDefined() + // expect((fromDb?.config).clientId).toEqual((connection.config).clientId) + // }) + // + // it('Should save connection with didauth config to database', async (): Promise => { + // const connection: NonPersistedConnection = { + // type: ConnectionTypeEnum.SIOPv2, + // config: { + // identifier: { + // did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + // provider: 'test_provider', + // keys: [], + // services: [], + // }, + // redirectUrl: 'https://example.com', + // stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', + // sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + // }, + // } + // const connectionEntity: ConnectionEntity = connectionEntityFrom(connection) + // await dbConnection.getRepository(ConnectionEntity).save(connectionEntity, { + // transaction: true, + // }) + // + // const fromDb: ConnectionEntity | null = await dbConnection.getRepository(ConnectionEntity).findOne({ + // where: { type: connection.type }, + // }) + // + // expect(fromDb).toBeDefined() + // + // const fromDbConfig: DidAuthConfigEntity | null = await dbConnection.getRepository(DidAuthConfigEntity).findOne({ + // where: { id: fromDb?.id }, + // }) + // + // expect(fromDbConfig).toBeDefined() + // expect(fromDb?.type).toEqual(connection.type) + // expect(fromDb?.config).toBeDefined() + // expect((fromDb?.config).identifier).toEqual((connection.config).identifier.did) + // }) + // + // it('Should save openid config to database', async (): Promise => { + // const clientId = '138d7bf8-c930-4c6e-b928-97d3a4928b01' + // const config: NonPersistedOpenIdConfig = { + // clientId, + // clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', + // scopes: ['auth'], + // issuer: 'https://example.com/app-test', + // redirectUrl: 'app:/callback', + // dangerouslyAllowInsecureHttpRequests: true, + // clientAuthMethod: 'post', + // } + // + // const configEntity: OpenIdConfigEntity = openIdConfigEntityFrom(config) + // await dbConnection.getRepository(OpenIdConfigEntity).save(configEntity, { + // transaction: true, + // }) + // + // const fromDb: OpenIdConfigEntity | null = await dbConnection.getRepository(OpenIdConfigEntity).findOne({ + // where: { clientId: config.clientId }, + // }) + // + // expect(fromDb).toBeDefined() + // expect((fromDb).clientId).toEqual(config.clientId) + // }) + // + // it('Should save didauth config to database', async (): Promise => { + // const sessionId = 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01' + // const config: NonPersistedDidAuthConfig = { + // identifier: { + // did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + // provider: 'test_provider', + // keys: [], + // services: [], + // }, + // redirectUrl: 'https://example.com', + // stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', + // sessionId, + // } + // + // const configEntity: DidAuthConfigEntity = didAuthConfigEntityFrom(config) + // await dbConnection.getRepository(DidAuthConfigEntity).save(configEntity, { + // transaction: true, + // }) + // + // const fromDb: DidAuthConfigEntity | null = await dbConnection.getRepository(DidAuthConfigEntity).findOne({ + // where: { sessionId: config.sessionId }, + // }) + // + // expect(fromDb).toBeDefined() + // expect((fromDb).identifier).toEqual(config.identifier.did) + // }) + // + // it('Should delete party and all child relations', async (): Promise => { + // const party1: NonPersistedParty = { + // uri: 'example.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name1', + // }, + // contact: { + // firstName: 'example_first_name1', + // middleName: 'example_middle_name1', + // lastName: 'example_last_name1', + // displayName: 'example_display_name1', + // }, + // } + // + // const partyEntity1: PartyEntity = partyEntityFrom(party1) + // const savedParty1: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity1) + // + // expect(savedParty1).toBeDefined() + // + // const party2: NonPersistedParty = { + // uri: 'example.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + // name: 'example_name2', + // }, + // contact: { + // firstName: 'example_first_name2', + // middleName: 'example_middle_name2', + // lastName: 'example_last_name2', + // displayName: 'example_display_name2', + // }, + // } + // + // const partyEntity2: PartyEntity = partyEntityFrom(party2) + // const savedParty2: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity2) + // + // expect(savedParty2).toBeDefined() + // + // const correlationId = 'relation_example.com' + // const identity: NonPersistedIdentity = { + // alias: correlationId, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.URL, + // correlationId, + // }, + // connection: { + // type: ConnectionTypeEnum.OPENID_CONNECT, + // config: { + // clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', + // clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', + // scopes: ['auth'], + // issuer: 'https://example.com/app-test', + // redirectUrl: 'app:/callback', + // dangerouslyAllowInsecureHttpRequests: true, + // clientAuthMethod: 'post', + // }, + // }, + // metadata: [ + // { + // label: 'example_label', + // value: 'example_value', + // }, + // ], + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // identityEntity.party = savedParty1 + // + // const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) + // + // expect(savedIdentity).toBeDefined() + // + // const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ + // leftId: savedParty1.id, + // rightId: savedParty2.id, + // }) + // + // const savedRelationship: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { + // transaction: true, + // }) + // + // expect(savedRelationship).toBeDefined() + // + // expect( + // await dbConnection.getRepository(PartyEntity).findOne({ + // where: { id: savedParty1.id }, + // }) + // ).toBeDefined() + // + // await dbConnection.getRepository(PartyEntity).delete({ id: savedParty1.id }) + // + // // check party + // await expect( + // await dbConnection.getRepository(PartyEntity).findOne({ + // where: { id: savedParty1.id }, + // }) + // ).toBeNull() + // + // // check identity + // expect( + // await dbConnection.getRepository(IdentityEntity).findOne({ + // where: { id: savedParty1.id }, + // }) + // ).toBeNull() + // + // // check identity identifier + // expect( + // await dbConnection.getRepository(CorrelationIdentifierEntity).findOne({ + // where: { id: savedIdentity.identifier.id }, + // }) + // ).toBeNull() + // + // // check identity connection + // expect( + // await dbConnection.getRepository(ConnectionEntity).findOne({ + // where: { id: savedIdentity.connection!.id }, + // }) + // ).toBeNull() + // + // // check connection config + // expect( + // await dbConnection.getRepository(OpenIdConfigEntity).findOne({ + // where: { id: savedIdentity.connection!.config.id }, + // }) + // ).toBeNull() + // + // // check identity metadata + // expect( + // await dbConnection.getRepository(IdentityMetadataItemEntity).findOne({ + // where: { id: savedIdentity.metadata![0].id }, + // }) + // ).toBeNull() + // + // // check contact + // expect( + // await dbConnection.getRepository(BaseContactEntity).findOne({ + // where: { id: savedParty1.contact.id }, + // }) + // ).toBeNull() + // + // // check party type + // expect( + // await dbConnection.getRepository(PartyTypeEntity).findOne({ + // where: { id: savedParty1.partyType.id }, + // }) + // ).toBeDefined() + // + // // check relation + // expect( + // await dbConnection.getRepository(PartyRelationshipEntity).findOne({ + // where: { id: savedRelationship.id }, + // }) + // ).toBeNull() + // }) + // + // it('Should delete identity and all child relations', async (): Promise => { + // const party: NonPersistedParty = { + // uri: 'example.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contact: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const partyEntity: PartyEntity = partyEntityFrom(party) + // const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) + // + // expect(savedParty).toBeDefined() + // + // const correlationId = 'relation_example.com' + // const identity: NonPersistedIdentity = { + // alias: correlationId, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.URL, + // correlationId, + // }, + // connection: { + // type: ConnectionTypeEnum.SIOPv2, + // config: { + // identifier: { + // did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + // provider: 'test_provider', + // keys: [], + // services: [], + // }, + // redirectUrl: 'https://example.com', + // stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', + // sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + // }, + // }, + // metadata: [ + // { + // label: 'example_label', + // value: 'example_value', + // }, + // ], + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // identityEntity.party = savedParty + // + // const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) + // + // expect( + // await dbConnection.getRepository(PartyEntity).findOne({ + // where: { id: savedParty.id }, + // }) + // ).toBeDefined() + // + // await dbConnection.getRepository(IdentityEntity).delete({ id: savedIdentity.id }) + // + // // check identity + // expect( + // await dbConnection.getRepository(IdentityEntity).findOne({ + // where: { alias: correlationId }, + // }) + // ).toBeNull() + // + // // check identity identifier + // expect( + // await dbConnection.getRepository(CorrelationIdentifierEntity).findOne({ + // where: { id: savedIdentity.identifier.id }, + // }) + // ).toBeNull() + // + // // check identity connection + // expect( + // await dbConnection.getRepository(ConnectionEntity).findOne({ + // where: { id: savedIdentity.connection!.id }, + // }) + // ).toBeNull() + // + // // check connection config + // expect( + // await dbConnection.getRepository(OpenIdConfigEntity).findOne({ + // where: { id: savedIdentity.connection!.config.id }, + // }) + // ).toBeNull() + // + // // check identity metadata + // expect( + // await dbConnection.getRepository(IdentityMetadataItemEntity).findOne({ + // where: { id: savedIdentity.metadata![0].id }, + // }) + // ).toBeNull() + // }) + // + // it('Should not delete party when deleting identity', async (): Promise => { + // const party: NonPersistedParty = { + // uri: 'example.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contact: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const partyEntity: PartyEntity = partyEntityFrom(party) + // const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) + // + // expect(savedParty).toBeDefined() + // + // const correlationId = 'relation_example.com' + // const identity: NonPersistedIdentity = { + // alias: correlationId, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.URL, + // correlationId, + // }, + // connection: { + // type: ConnectionTypeEnum.SIOPv2, + // config: { + // identifier: { + // did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + // provider: 'test_provider', + // keys: [], + // services: [], + // }, + // redirectUrl: 'https://example.com', + // stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', + // sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + // }, + // }, + // metadata: [ + // { + // label: 'example_label', + // value: 'example_value', + // }, + // ], + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // identityEntity.party = savedParty + // + // const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) + // + // expect(savedIdentity).toBeDefined() + // + // await dbConnection.getRepository(IdentityEntity).delete({ id: savedIdentity.id }) + // + // // check identity + // expect( + // await dbConnection.getRepository(IdentityEntity).findOne({ + // where: { id: savedIdentity.id }, + // }) + // ).toBeNull() + // + // // check party + // expect( + // await dbConnection.getRepository(PartyEntity).findOne({ + // where: { id: savedParty.id }, + // }) + // ).toBeDefined() + // }) + // + // it('Should set creation date when saving party', async (): Promise => { + // const party: NonPersistedParty = { + // uri: 'example.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contact: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const partyEntity: PartyEntity = partyEntityFrom(party) + // const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) + // + // const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + // where: { id: savedParty.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.createdAt).toBeDefined() + // }) + // + // it('Should not update creation date when updating party', async (): Promise => { + // const party: NonPersistedParty = { + // uri: 'example.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contact: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const partyEntity: PartyEntity = partyEntityFrom(party) + // const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) + // + // expect(savedParty).toBeDefined() + // + // const newContactFirstName = 'new_first_name' + // await dbConnection.getRepository(PartyEntity).save({ + // ...savedParty, + // contact: { + // ...savedParty.contact, + // firstName: newContactFirstName, + // }, + // }) + // + // const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + // where: { id: savedParty.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect((fromDb?.contact).firstName).toEqual(newContactFirstName) + // expect(fromDb?.createdAt).toEqual(savedParty?.createdAt) + // }) + // + // it('Should set creation date when saving identity', async (): Promise => { + // const correlationId = 'example_did' + // const identity: NonPersistedIdentity = { + // alias: correlationId, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId, + // }, + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // await dbConnection.getRepository(IdentityEntity).save(identityEntity) + // + // const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ + // where: { + // identifier: { + // correlationId, + // }, + // }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.createdAt).toBeDefined() + // }) + // + // it('Should not update creation date when saving identity', async (): Promise => { + // const correlationId = 'example_did' + // const identity: NonPersistedIdentity = { + // alias: correlationId, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId, + // }, + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) + // const newCorrelationId = 'new_example_did' + // await dbConnection + // .getRepository(IdentityEntity) + // .save({ ...savedIdentity, identifier: { ...savedIdentity.identifier, correlationId: newCorrelationId } }) + // + // const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ + // where: { + // identifier: { + // correlationId: newCorrelationId, + // }, + // }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.createdAt).toEqual(savedIdentity?.createdAt) + // }) + // + // it('Should set last updated date when saving party', async (): Promise => { + // const party: NonPersistedParty = { + // uri: 'example.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contact: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const partyEntity: PartyEntity = partyEntityFrom(party) + // const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) + // + // const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + // where: { id: savedParty.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.lastUpdatedAt).toBeDefined() + // }) + // + // it('Should update last updated date when updating party', async (): Promise => { + // const party: NonPersistedParty = { + // uri: 'example.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contact: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const partyEntity: PartyEntity = partyEntityFrom(party) + // const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) + // expect(savedParty).toBeDefined() + // + // // waiting here to get a different timestamp + // await new Promise((resolve) => setTimeout(resolve, 2000)) + // + // const newContactFirstName = 'new_first_name' + // await dbConnection.getRepository(PartyEntity).save({ + // ...savedParty, + // // FIXME there is still an issue when updating nested objects, the parent does not update + // // https://github.com/typeorm/typeorm/issues/5378 + // uri: 'new uri', // TODO remove this to trigger the bug + // contact: { + // ...savedParty.contact, + // firstName: newContactFirstName, + // }, + // }) + // + // const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + // where: { id: savedParty.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect((fromDb?.contact).firstName).toEqual(newContactFirstName) + // expect(fromDb?.lastUpdatedAt).not.toEqual(savedParty?.lastUpdatedAt) + // }) + // + // it('Should set last updated date when saving party type', async (): Promise => { + // const partyType: NonPersistedPartyType = { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // } + // + // const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) + // const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) + // + // const fromDb: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).findOne({ + // where: { id: savedPartyType.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.lastUpdatedAt).toBeDefined() + // }) + // + // it('Should set last creation date when saving party type', async (): Promise => { + // const partyType: NonPersistedPartyType = { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // } + // + // const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) + // const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) + // + // const fromDb: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).findOne({ + // where: { id: savedPartyType.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.createdAt).toBeDefined() + // }) + // + // it('Should set last updated date when saving identity', async (): Promise => { + // const correlationId = 'example_did' + // const identity: NonPersistedIdentity = { + // alias: correlationId, + // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + // identifier: { + // type: CorrelationIdentifierEnum.DID, + // correlationId, + // }, + // } + // + // const identityEntity: IdentityEntity = identityEntityFrom(identity) + // await dbConnection.getRepository(IdentityEntity).save(identityEntity) + // + // const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ + // where: { + // identifier: { + // correlationId, + // }, + // }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.lastUpdatedAt).toBeDefined() + // }) + // + // it('Should enforce unique type and tenant id combination when saving party type', async (): Promise => { + // const tenantId = 'non_unique_value' + // const name = 'non_unique_value' + // const partyType1: NonPersistedPartyType = { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId, + // name, + // } + // + // const partyTypeEntity1: PartyTypeEntity = partyTypeEntityFrom(partyType1) + // const savedPartyType1: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity1) + // + // expect(savedPartyType1).toBeDefined() + // + // const partyType2: NonPersistedPartyType = { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId, + // name, + // } + // + // const partyTypeEntity2: PartyTypeEntity = partyTypeEntityFrom(partyType2) + // await expect(dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity2)).rejects.toThrowError( + // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: PartyType.type, PartyType.tenant_id' + // ) + // }) + // + // it('Should enforce unique name when saving party type', async (): Promise => { + // const name = 'non_unique_value' + // const partyType1: NonPersistedPartyType = { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name, + // } + // + // const partyTypeEntity1: PartyTypeEntity = partyTypeEntityFrom(partyType1) + // const savedPartyType1: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity1) + // + // expect(savedPartyType1).toBeDefined() + // + // const partyType2: NonPersistedPartyType = { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + // name, + // } + // + // const partyTypeEntity2: PartyTypeEntity = partyTypeEntityFrom(partyType2) + // await expect(dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity2)).rejects.toThrowError( + // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: PartyType.name' + // ) + // }) + // + // it('Should enforce unique legal name when saving organization', async (): Promise => { + // const legalName = 'non_unique_value' + // const organization1: NonPersistedOrganization = { + // legalName, + // displayName: 'example_display_name', + // } + // + // const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) + // const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { + // transaction: true, + // }) + // + // expect(savedOrganization1).toBeDefined() + // + // const organization2: NonPersistedOrganization = { + // legalName, + // displayName: 'example_display_name', + // } + // + // const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) + // await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( + // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: BaseContact.legal_name' + // ) + // }) + // + // it('Should enforce unique legal name when saving organization', async (): Promise => { + // const legalName = 'example_legal_name' + // const organization1: NonPersistedOrganization = { + // legalName, + // displayName: 'example_display_name', + // } + // + // const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) + // const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { + // transaction: true, + // }) + // + // expect(savedOrganization1).toBeDefined() + // + // const organization2: NonPersistedOrganization = { + // legalName, + // displayName: 'example_display_name', + // } + // + // const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) + // await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( + // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: BaseContact.legal_name' + // ) + // }) + // + // it('Should save party relationship to database', async (): Promise => { + // const party1: NonPersistedParty = { + // uri: 'example1.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name1', + // }, + // contact: { + // firstName: 'example_first_name1', + // middleName: 'example_middle_name1', + // lastName: 'example_last_name1', + // displayName: 'example_display_name1', + // }, + // } + // + // const partyEntity1: PartyEntity = partyEntityFrom(party1) + // const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { + // transaction: true, + // }) + // + // expect(savedParty1).toBeDefined() + // + // const party2: NonPersistedParty = { + // uri: 'example2.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + // name: 'example_name2', + // }, + // contact: { + // firstName: 'example_first_name2', + // middleName: 'example_middle_name2', + // lastName: 'example_last_name2', + // displayName: 'example_display_name2', + // }, + // } + // + // const partyEntity2: PartyEntity = partyEntityFrom(party2) + // const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { + // transaction: true, + // }) + // + // expect(savedParty2).toBeDefined() + // + // const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ + // leftId: savedParty1.id, + // rightId: savedParty2.id, + // }) + // + // await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { + // transaction: true, + // }) + // + // // TODO check the relation field + // const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + // where: { id: partyEntity1.id }, + // }) + // + // expect(fromDb).toBeDefined() + // }) + // + // it('Should set last updated date when saving party relationship', async (): Promise => { + // const party1: NonPersistedParty = { + // uri: 'example1.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name1', + // }, + // contact: { + // firstName: 'example_first_name1', + // middleName: 'example_middle_name1', + // lastName: 'example_last_name1', + // displayName: 'example_display_name1', + // }, + // } + // + // const partyEntity1: PartyEntity = partyEntityFrom(party1) + // const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { + // transaction: true, + // }) + // + // const party2: NonPersistedParty = { + // uri: 'example2.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + // name: 'example_name2', + // }, + // contact: { + // firstName: 'example_first_name2', + // middleName: 'example_middle_name2', + // lastName: 'example_last_name2', + // displayName: 'example_display_name2', + // }, + // } + // + // const partyEntity2: PartyEntity = partyEntityFrom(party2) + // const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { + // transaction: true, + // }) + // + // const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ + // leftId: savedParty1.id, + // rightId: savedParty2.id, + // }) + // + // await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { + // transaction: true, + // }) + // + // const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + // where: { id: partyEntity1.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.lastUpdatedAt).toBeDefined() + // }) + // + // it('Should set creation date when saving party relationship', async (): Promise => { + // const party1: NonPersistedParty = { + // uri: 'example1.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name1', + // }, + // contact: { + // firstName: 'example_first_name1', + // middleName: 'example_middle_name1', + // lastName: 'example_last_name1', + // displayName: 'example_display_name1', + // }, + // } + // + // const partyEntity1: PartyEntity = partyEntityFrom(party1) + // const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { + // transaction: true, + // }) + // + // const party2: NonPersistedParty = { + // uri: 'example2.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + // name: 'example_name2', + // }, + // contact: { + // firstName: 'example_first_name2', + // middleName: 'example_middle_name2', + // lastName: 'example_last_name2', + // displayName: 'example_display_name2', + // }, + // } + // + // const partyEntity2: PartyEntity = partyEntityFrom(party2) + // const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { + // transaction: true, + // }) + // + // const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ + // leftId: savedParty1.id, + // rightId: savedParty2.id, + // }) + // + // await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { + // transaction: true, + // }) + // + // const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + // where: { id: partyEntity1.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.createdAt).toBeDefined() + // }) + // + // it('Should save bidirectional party relationships to database', async (): Promise => { + // const party1: NonPersistedParty = { + // uri: 'example1.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name1', + // }, + // contact: { + // firstName: 'example_first_name1', + // middleName: 'example_middle_name1', + // lastName: 'example_last_name1', + // displayName: 'example_display_name1', + // }, + // } + // + // const partyEntity1: PartyEntity = partyEntityFrom(party1) + // const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { + // transaction: true, + // }) + // + // expect(savedParty1).toBeDefined() + // + // const party2: NonPersistedParty = { + // uri: 'example2.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + // name: 'example_name2', + // }, + // contact: { + // firstName: 'example_first_name2', + // middleName: 'example_middle_name2', + // lastName: 'example_last_name2', + // displayName: 'example_display_name2', + // }, + // } + // + // const partyEntity2: PartyEntity = partyEntityFrom(party2) + // const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { + // transaction: true, + // }) + // + // expect(savedParty2).toBeDefined() + // + // const relationship1: PartyRelationshipEntity = partyRelationshipEntityFrom({ + // leftId: savedParty1.id, + // rightId: savedParty2.id, + // }) + // + // const savedRelationship1: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship1, { + // transaction: true, + // }) + // + // expect(savedRelationship1).toBeDefined() + // + // const relationship2: PartyRelationshipEntity = partyRelationshipEntityFrom({ + // leftId: savedParty2.id, + // rightId: savedParty1.id, + // }) + // + // const savedRelationship2: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship2, { + // transaction: true, + // }) + // + // expect(savedRelationship2).toBeDefined() + // + // const fromDb: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).findOne({ + // where: { id: savedRelationship2.id }, + // }) + // + // expect(fromDb).toBeDefined() + // }) + // + // it('Should enforce unique owner combination for party relationship', async (): Promise => { + // const party1: NonPersistedParty = { + // uri: 'example1.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name1', + // }, + // contact: { + // firstName: 'example_first_name1', + // middleName: 'example_middle_name1', + // lastName: 'example_last_name1', + // displayName: 'example_display_name1', + // }, + // } + // + // const partyEntity1: PartyEntity = partyEntityFrom(party1) + // const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { + // transaction: true, + // }) + // + // expect(savedParty1).toBeDefined() + // + // const party2: NonPersistedParty = { + // uri: 'example2.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + // name: 'example_name2', + // }, + // contact: { + // firstName: 'example_first_name2', + // middleName: 'example_middle_name2', + // lastName: 'example_last_name2', + // displayName: 'example_display_name2', + // }, + // } + // + // const partyEntity2: PartyEntity = partyEntityFrom(party2) + // const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { + // transaction: true, + // }) + // + // expect(savedParty2).toBeDefined() + // + // const relationship1: PartyRelationshipEntity = partyRelationshipEntityFrom({ + // leftId: savedParty1.id, + // rightId: savedParty2.id, + // }) + // + // const savedRelationship1: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship1, { + // transaction: true, + // }) + // + // expect(savedRelationship1).toBeDefined() + // + // const relationship2: PartyRelationshipEntity = partyRelationshipEntityFrom({ + // leftId: savedParty1.id, + // rightId: savedParty2.id, + // }) + // + // await expect(dbConnection.getRepository(PartyRelationshipEntity).save(relationship2)).rejects.toThrowError( + // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: PartyRelationship.left_id, PartyRelationship.right_id' + // ) + // }) + // + // it('Should save party type to database', async (): Promise => { + // const partyType: NonPersistedPartyType = { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // } + // + // const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) + // const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) + // + // const fromDb: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).findOne({ + // where: { id: savedPartyType.id }, + // }) + // + // expect(fromDb).toBeDefined() + // }) + // + // it('Should save person to database', async (): Promise => { + // const person: NonPersistedNaturalPerson = { + // firstName: 'example_first_name', + // lastName: 'lastName2', + // displayName: 'displayName', + // } + // + // const personEntity: NaturalPersonEntity = naturalPersonEntityFrom(person) + // const savedPerson: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).save(personEntity, { + // transaction: true, + // }) + // + // const fromDb: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).findOne({ + // where: { id: savedPerson.id }, + // }) + // + // expect(fromDb).toBeDefined() + // }) + // + // it('Should set last updated date when saving person', async (): Promise => { + // const person: NonPersistedNaturalPerson = { + // firstName: 'example_first_name', + // lastName: 'lastName2', + // displayName: 'displayName', + // } + // + // const personEntity: NaturalPersonEntity = naturalPersonEntityFrom(person) + // const savedPerson: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).save(personEntity, { + // transaction: true, + // }) + // + // const fromDb: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).findOne({ + // where: { id: savedPerson.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.lastUpdatedAt).toBeDefined() + // }) + // + // it('Should set creation date when saving person', async (): Promise => { + // const person: NonPersistedNaturalPerson = { + // firstName: 'example_first_name', + // lastName: 'lastName2', + // displayName: 'displayName', + // } + // + // const personEntity: NaturalPersonEntity = naturalPersonEntityFrom(person) + // const savedPerson: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).save(personEntity, { + // transaction: true, + // }) + // + // const fromDb: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).findOne({ + // where: { id: savedPerson.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.createdAt).toBeDefined() + // }) + // + // it('Should save organization to database', async (): Promise => { + // const organization: NonPersistedOrganization = { + // legalName: 'example_legal_name', + // displayName: 'example_display_name', + // } + // + // const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) + // const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { + // transaction: true, + // }) + // + // const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ + // where: { id: savedOrganization.id }, + // }) + // + // expect(fromDb).toBeDefined() + // }) + // + // it('Should set last updated date when saving organization', async (): Promise => { + // const organization: NonPersistedOrganization = { + // legalName: 'example_legal_name', + // displayName: 'example_display_name', + // } + // + // const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) + // const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { + // transaction: true, + // }) + // + // const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ + // where: { id: savedOrganization.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.lastUpdatedAt).toBeDefined() + // }) + // + // it('Should set creation date when saving organization', async (): Promise => { + // const organization: NonPersistedOrganization = { + // legalName: 'example_legal_name', + // displayName: 'example_display_name', + // } + // + // const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) + // const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { + // transaction: true, + // }) + // + // const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ + // where: { id: savedOrganization.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.createdAt).toBeDefined() + // }) + // + // it('Should get party based on person information', async (): Promise => { + // const firstName = 'example_first_name' + // const party: NonPersistedParty = { + // uri: 'example.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contact: { + // firstName, + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const partyEntity: PartyEntity = partyEntityFrom(party) + // await dbConnection.getRepository(PartyEntity).save(partyEntity, { + // transaction: true, + // }) + // + // const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + // where: { + // contact: { + // firstName, + // } as FindOptionsWhere, //NaturalPersonEntity | OrganizationEntity + // }, + // }) + // + // expect(fromDb).toBeDefined() + // }) + // + // it('Should get party based on organization information', async (): Promise => { + // const legalName = 'example_legal_name' + // const party: NonPersistedParty = { + // uri: 'example.com', + // partyType: { + // type: PartyTypeEnum.ORGANIZATION, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contact: { + // legalName, + // displayName: 'example_display_name', + // }, + // } + // + // const partyEntity: PartyEntity = partyEntityFrom(party) + // await dbConnection.getRepository(PartyEntity).save(partyEntity, { + // transaction: true, + // }) + // + // const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + // where: { + // contact: { + // legalName, + // } as FindOptionsWhere, //NaturalPersonEntity | OrganizationEntity + // }, + // }) + // + // expect(fromDb).toBeDefined() + // }) + // + // it("Should enforce unique party id's for relationship sides", async (): Promise => { + // const party: NonPersistedParty = { + // uri: 'example.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contact: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const partyEntity: PartyEntity = partyEntityFrom(party) + // const savedParty: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity, { + // transaction: true, + // }) + // + // expect(savedParty).toBeDefined() + // + // const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ + // leftId: savedParty.id, + // rightId: savedParty.id, + // }) + // + // await expect(dbConnection.getRepository(PartyRelationshipEntity).save(relationship)).rejects.toThrowError( + // 'Cannot use the same id for both sides of the relationship' + // ) + // }) + // + // it('Should delete party relationship', async (): Promise => { + // const party1: NonPersistedParty = { + // uri: 'example1.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name1', + // }, + // contact: { + // firstName: 'example_first_name1', + // middleName: 'example_middle_name1', + // lastName: 'example_last_name1', + // displayName: 'example_display_name1', + // }, + // } + // + // const partyEntity1: PartyEntity = partyEntityFrom(party1) + // const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { + // transaction: true, + // }) + // + // expect(savedParty1).toBeDefined() + // + // const party2: NonPersistedParty = { + // uri: 'example2.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + // name: 'example_name2', + // }, + // contact: { + // firstName: 'example_first_name2', + // middleName: 'example_middle_name2', + // lastName: 'example_last_name2', + // displayName: 'example_display_name2', + // }, + // } + // + // const partyEntity2: PartyEntity = partyEntityFrom(party2) + // const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { + // transaction: true, + // }) + // + // expect(savedParty2).toBeDefined() + // + // const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ + // leftId: savedParty1.id, + // rightId: savedParty2.id, + // }) + // + // const savedRelationship: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { + // transaction: true, + // }) + // + // expect(savedRelationship).toBeDefined() + // + // await dbConnection.getRepository(PartyRelationshipEntity).delete({ id: savedRelationship.id }) + // + // await expect( + // await dbConnection.getRepository(PartyRelationshipEntity).findOne({ + // where: { id: savedRelationship.id }, + // }) + // ).toBeNull() + // }) + // + // it('Should delete party type', async (): Promise => { + // const partyType: NonPersistedPartyType = { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // } + // + // const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) + // const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) + // + // expect(savedPartyType).toBeDefined() + // + // await dbConnection.getRepository(PartyTypeEntity).delete({ id: savedPartyType.id }) + // + // await expect( + // await dbConnection.getRepository(PartyTypeEntity).findOne({ + // where: { id: savedPartyType.id }, + // }) + // ).toBeNull() + // }) + // + // it('Should not be able to remove party type when used by parties', async (): Promise => { + // const party: NonPersistedParty = { + // uri: 'example.com', + // partyType: { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // }, + // contact: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const partyEntity: PartyEntity = partyEntityFrom(party) + // const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity, { + // transaction: true, + // }) + // + // expect(savedParty).toBeDefined() + // + // await expect(dbConnection.getRepository(PartyTypeEntity).delete({ id: savedParty.partyType.id })).rejects.toThrowError( + // 'FOREIGN KEY constraint failed' + // ) + // }) + // + // it('Should save party with existing party type', async (): Promise => { + // const partyType: NonPersistedPartyType = { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // } + // + // const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) + // const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) + // + // const party: NonPersistedParty = { + // uri: 'example.com', + // partyType: savedPartyType, + // contact: { + // firstName: 'example_first_name', + // middleName: 'example_middle_name', + // lastName: 'example_last_name', + // displayName: 'example_display_name', + // }, + // } + // + // const partyEntity: PartyEntity = partyEntityFrom(party) + // partyEntity.partyType = savedPartyType + // await dbConnection.getRepository(PartyEntity).save(partyEntity, { + // transaction: true, + // }) + // + // const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + // where: { id: partyEntity.id }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.partyType).toBeDefined() + // expect(fromDb?.partyType.id).toEqual(savedPartyType.id) + // expect(fromDb?.partyType.type).toEqual(savedPartyType.type) + // expect(fromDb?.partyType.tenantId).toEqual(savedPartyType.tenantId) + // expect(fromDb?.partyType.name).toEqual(savedPartyType.name) + // }) + // + // it('Should not update creation date when saving party type', async (): Promise => { + // const partyType: NonPersistedPartyType = { + // type: PartyTypeEnum.NATURAL_PERSON, + // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + // name: 'example_name', + // } + // + // const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) + // const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) + // await dbConnection.getRepository(PartyTypeEntity).save({ ...savedPartyType, type: PartyTypeEnum.ORGANIZATION }) + // + // const fromDb: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).findOne({ + // where: { + // type: PartyTypeEnum.ORGANIZATION, + // }, + // }) + // + // expect(fromDb).toBeDefined() + // expect(fromDb?.createdAt).toEqual(savedPartyType?.createdAt) + // }) }) diff --git a/packages/data-store/src/entities/contact/IdentityEntity.ts b/packages/data-store/src/entities/contact/IdentityEntity.ts index c81dcad19..72dccc41a 100644 --- a/packages/data-store/src/entities/contact/IdentityEntity.ts +++ b/packages/data-store/src/entities/contact/IdentityEntity.ts @@ -58,7 +58,7 @@ export class IdentityEntity extends BaseEntity { eager: true, nullable: false, }) - @JoinColumn({ name: 'metadata_id' }) + @JoinColumn({ name: 'metadata_id' }) // TODO check in db file metadata!: Array @CreateDateColumn({ name: 'created_at', nullable: false }) diff --git a/packages/data-store/src/entities/contact/OrganizationEntity.ts b/packages/data-store/src/entities/contact/OrganizationEntity.ts index e20a38ec7..a48e9d4b1 100644 --- a/packages/data-store/src/entities/contact/OrganizationEntity.ts +++ b/packages/data-store/src/entities/contact/OrganizationEntity.ts @@ -16,8 +16,8 @@ export class OrganizationEntity extends BaseContactEntity { displayName!: string @OneToOne(() => PartyEntity) - @JoinColumn({ name: 'contact_id' }) - contact!: PartyEntity + @JoinColumn({ name: 'party_id' }) + party!: PartyEntity @BeforeInsert() @BeforeUpdate() diff --git a/packages/data-store/src/entities/contact/PartyEntity.ts b/packages/data-store/src/entities/contact/PartyEntity.ts index db7adc9de..fe41d1572 100644 --- a/packages/data-store/src/entities/contact/PartyEntity.ts +++ b/packages/data-store/src/entities/contact/PartyEntity.ts @@ -35,7 +35,7 @@ export class PartyEntity extends BaseEntity { eager: true, nullable: false, }) - @JoinColumn({ name: 'identity_id' }) + @JoinColumn({ name: 'identity_id' }) // TODO check this in the db file identities!: Array @OneToMany(() => ElectronicAddressEntity, (electronicAddress: ElectronicAddressEntity) => electronicAddress.party, { @@ -44,7 +44,7 @@ export class PartyEntity extends BaseEntity { eager: true, nullable: false, }) - @JoinColumn({ name: 'electronic_address_id' }) + @JoinColumn({ name: 'electronic_address_id' }) // TODO check this in the db file electronicAddresses!: Array @ManyToOne(() => PartyTypeEntity, (contactType: PartyTypeEntity) => contactType.parties, { diff --git a/packages/data-store/src/migrations/generic/index.ts b/packages/data-store/src/migrations/generic/index.ts index cb9034231..f81e36086 100644 --- a/packages/data-store/src/migrations/generic/index.ts +++ b/packages/data-store/src/migrations/generic/index.ts @@ -1,6 +1,6 @@ import { CreateContacts1659463079429 } from './1-CreateContacts' import { CreateContacts1690925872318 } from './2-CreateContacts' -import { CreateIssuanceBranding1659463079429 } from './1-CreateIssuanceBranding' +//import { CreateIssuanceBranding1659463079429 } from './1-CreateIssuanceBranding' /** * The migrations array that SHOULD be used when initializing a TypeORM database connection. @@ -9,4 +9,4 @@ import { CreateIssuanceBranding1659463079429 } from './1-CreateIssuanceBranding' * * @public */ -export const DataStoreMigrations = [CreateContacts1659463079429, CreateContacts1690925872318, CreateIssuanceBranding1659463079429] +export const DataStoreMigrations = [CreateContacts1659463079429, CreateContacts1690925872318] //CreateIssuanceBranding1659463079429 diff --git a/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts b/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts index ccfe15f81..a68dd5322 100644 --- a/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts +++ b/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts @@ -4,160 +4,244 @@ export class CreateContacts1690925872693 implements MigrationInterface { name = 'CreateContacts1690925872693' public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP INDEX "IDX_BaseConfigEntity_type"`) - await queryRunner.query( - `CREATE TABLE "temporary_BaseConfigEntity" ("id" varchar PRIMARY KEY NOT NULL, "client_id" varchar(255), "client_secret" varchar(255), "scopes" text, "issuer" varchar(255), "redirect_url" text, "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "identifier" varchar(255), "session_id" varchar(255), "type" varchar NOT NULL, "connectionId" varchar, CONSTRAINT "REL_BaseConfig_connectionId" UNIQUE ("connectionId"))` - ) - await queryRunner.query( - `INSERT INTO "temporary_BaseConfigEntity"("id", "client_id", "client_secret", "scopes", "issuer", "redirect_url", "dangerously_allow_insecure_http_requests", "client_auth_method", "identifier", "session_id", "type", "connectionId") SELECT "id", "client_id", "client_secret", "scopes", "issuer", "redirect_url", "dangerously_allow_insecure_http_requests", "client_auth_method", "identifier", "session_id", "type", "connectionId" FROM "BaseConfigEntity"` - ) - await queryRunner.query(`DROP TABLE "BaseConfigEntity"`) - await queryRunner.query(`ALTER TABLE "temporary_BaseConfigEntity" RENAME TO "BaseConfigEntity"`) - await queryRunner.query(`CREATE INDEX "IDX_BaseConfigEntity_type" ON "BaseConfigEntity" ("type")`) - await queryRunner.query( - `CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identityId" varchar, CONSTRAINT "REL_CorrelationIdentifier_identityId" UNIQUE ("identityId"), CONSTRAINT "UQ_Correlation_id" UNIQUE ("correlation_id"))` - ) - await queryRunner.query( - `INSERT INTO "temporary_CorrelationIdentifier"("id", "type", "correlation_id", "identityId") SELECT "id", "type", "correlation_id", "identityId" FROM "CorrelationIdentifier"` - ) + await queryRunner.query(`CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identityId" varchar, CONSTRAINT "REL_28945c1d57c5feee1d5d1f5451" UNIQUE ("identityId"), CONSTRAINT "UQ_775cbf83c248bc73c42aef55664" UNIQUE ("correlation_id"))`) + await queryRunner.query(`INSERT INTO "temporary_CorrelationIdentifier"("id", "type", "correlation_id", "identityId") SELECT "id", "type", "correlation_id", "identityId" FROM "CorrelationIdentifier"`) await queryRunner.query(`DROP TABLE "CorrelationIdentifier"`) await queryRunner.query(`ALTER TABLE "temporary_CorrelationIdentifier" RENAME TO "CorrelationIdentifier"`) - await queryRunner.query( - `CREATE TABLE "temporary_IdentityMetadata" ("id" varchar PRIMARY KEY NOT NULL, "label" varchar(255) NOT NULL, "value" varchar(255) NOT NULL, "identityId" varchar)` - ) - await queryRunner.query( - `INSERT INTO "temporary_IdentityMetadata"("id", "label", "value", "identityId") SELECT "id", "label", "value", "identityId" FROM "IdentityMetadata"` - ) - await queryRunner.query(`DROP TABLE "IdentityMetadata"`) - await queryRunner.query(`ALTER TABLE "temporary_IdentityMetadata" RENAME TO "IdentityMetadata"`) - await queryRunner.query( - `CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Alias" UNIQUE ("alias"))` - ) - await queryRunner.query( - `INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"` - ) + await queryRunner.query(`CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_cbeaf6b68b6dbc9eb8dc3503499" UNIQUE ("alias"))`) + await queryRunner.query(`INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"`) await queryRunner.query(`DROP TABLE "Identity"`) await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) - await queryRunner.query( - `CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identityId" varchar, CONSTRAINT "REL_Connection_identityId" UNIQUE ("identityId"))` - ) + await queryRunner.query(`CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identityId" varchar, CONSTRAINT "REL_fff3668c112a6863bb8c37519a" UNIQUE ("identityId"))`) await queryRunner.query(`INSERT INTO "temporary_Connection"("id", "type", "identityId") SELECT "id", "type", "identityId" FROM "Connection"`) await queryRunner.query(`DROP TABLE "Connection"`) await queryRunner.query(`ALTER TABLE "temporary_Connection" RENAME TO "Connection"`) - await queryRunner.query(`DROP INDEX "IDX_BaseConfigEntity_type"`) - await queryRunner.query( - `CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Alias" UNIQUE ("alias"))` - ) - await queryRunner.query( - `INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"` - ) - await queryRunner.query(`DROP TABLE "Identity"`) - await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) - await queryRunner.query( - `CREATE TABLE "ContactType" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('person','organization') ) NOT NULL, "name" varchar(255) NOT NULL, "description" varchar(255), "tenantId" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "UQ_2229e0d8c1e6817efcc982a6dde" UNIQUE ("name"))` - ) - await queryRunner.query(`CREATE UNIQUE INDEX "IDX_1a1fa2aa0a56649427e427a41f" ON "ContactType" ("type", "tenantId")`) - await queryRunner.query( - `CREATE TABLE "ContactOwner" ("id" varchar PRIMARY KEY NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "firstName" varchar(255), "middleName" varchar(255), "lastName" varchar(255), "displayName" varchar(255), "legalName" varchar(255), "type" varchar NOT NULL, "contactId" varchar, CONSTRAINT "UQ_9177af8a51a2a0598d3a8c68e1e" UNIQUE ("displayName"), CONSTRAINT "UQ_91bf22d2597ff429ece6ae807aa" UNIQUE ("legalName"), CONSTRAINT "UQ_9177af8a51a2a0598d3a8c68e1e" UNIQUE ("displayName"), CONSTRAINT "REL_26ce21b29da1426fa1198b947e" UNIQUE ("contactId"))` - ) - await queryRunner.query(`CREATE INDEX "IDX_e50c368daf85e7ae54585b0f7b" ON "ContactOwner" ("type")`) - await queryRunner.query( - `CREATE TABLE "ContactRelationship" ("id" varchar PRIMARY KEY NOT NULL, "leftId" varchar NOT NULL, "rightId" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')))` - ) - await queryRunner.query(`CREATE UNIQUE INDEX "IDX_ContactRelationshipEntity_left_right" ON "ContactRelationship" ("leftId", "rightId")`) - await queryRunner.query( - `CREATE TABLE "temporary_Contact" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')))` - ) - await queryRunner.query( - `INSERT INTO "temporary_Contact"("id", "uri", "created_at", "last_updated_at") SELECT "id", "uri", "created_at", "last_updated_at" FROM "Contact"` - ) - await queryRunner.query(`DROP TABLE "Contact"`) - await queryRunner.query(`ALTER TABLE "temporary_Contact" RENAME TO "Contact"`) - await queryRunner.query( - `CREATE TABLE "temporary_Contact" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactTypeId" varchar NOT NULL)` - ) - await queryRunner.query( - `INSERT INTO "temporary_Contact"("id", "uri", "created_at", "last_updated_at") SELECT "id", "uri", "created_at", "last_updated_at" FROM "Contact"` - ) - await queryRunner.query(`DROP TABLE "Contact"`) - await queryRunner.query(`ALTER TABLE "temporary_Contact" RENAME TO "Contact"`) - await queryRunner.query( - `CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Alias" UNIQUE ("alias"))` - ) - await queryRunner.query( - `INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"` - ) + await queryRunner.query(`CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identity_id" varchar, CONSTRAINT "REL_28945c1d57c5feee1d5d1f5451" UNIQUE ("identity_id"), CONSTRAINT "UQ_775cbf83c248bc73c42aef55664" UNIQUE ("correlation_id"))`) + await queryRunner.query(`INSERT INTO "temporary_CorrelationIdentifier"("id", "type", "correlation_id", "identity_id") SELECT "id", "type", "correlation_id", "identityId" FROM "CorrelationIdentifier"`) + await queryRunner.query(`DROP TABLE "CorrelationIdentifier"`) + await queryRunner.query(`ALTER TABLE "temporary_CorrelationIdentifier" RENAME TO "CorrelationIdentifier"`) + await queryRunner.query(`CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "partyId" varchar, CONSTRAINT "UQ_cbeaf6b68b6dbc9eb8dc3503499" UNIQUE ("alias"))`) + await queryRunner.query(`INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "partyId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"`) await queryRunner.query(`DROP TABLE "Identity"`) await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) - await queryRunner.query(`CREATE INDEX "IDX_228953a09ee91bbac6e28b7345" ON "BaseConfigEntity" ("type")`) - await queryRunner.query(`DROP INDEX "IDX_228953a09ee91bbac6e28b7345"`) - await queryRunner.query( - `CREATE TABLE "temporary_BaseConfigEntity" ("id" varchar PRIMARY KEY NOT NULL, "client_id" varchar(255), "client_secret" varchar(255), "scopes" text, "issuer" varchar(255), "redirect_url" text, "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "identifier" varchar(255), "session_id" varchar(255), "type" varchar NOT NULL, "connectionId" varchar, CONSTRAINT "REL_BaseConfig_connectionId" UNIQUE ("connectionId"), CONSTRAINT "FK_0ab3b33e0a87e1706025e63d8a9" FOREIGN KEY ("connectionId") REFERENCES "Connection" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` - ) - await queryRunner.query( - `INSERT INTO "temporary_BaseConfigEntity"("id", "client_id", "client_secret", "scopes", "issuer", "redirect_url", "dangerously_allow_insecure_http_requests", "client_auth_method", "identifier", "session_id", "type", "connectionId") SELECT "id", "client_id", "client_secret", "scopes", "issuer", "redirect_url", "dangerously_allow_insecure_http_requests", "client_auth_method", "identifier", "session_id", "type", "connectionId" FROM "BaseConfigEntity"` - ) - await queryRunner.query(`DROP TABLE "BaseConfigEntity"`) - await queryRunner.query(`ALTER TABLE "temporary_BaseConfigEntity" RENAME TO "BaseConfigEntity"`) - await queryRunner.query(`CREATE INDEX "IDX_228953a09ee91bbac6e28b7345" ON "BaseConfigEntity" ("type")`) - await queryRunner.query( - `CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identityId" varchar, CONSTRAINT "REL_CorrelationIdentifier_identityId" UNIQUE ("identityId"), CONSTRAINT "UQ_Correlation_id" UNIQUE ("correlation_id"), CONSTRAINT "FK_28945c1d57c5feee1d5d1f54510" FOREIGN KEY ("identityId") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` - ) - await queryRunner.query( - `INSERT INTO "temporary_CorrelationIdentifier"("id", "type", "correlation_id", "identityId") SELECT "id", "type", "correlation_id", "identityId" FROM "CorrelationIdentifier"` - ) + await queryRunner.query(`CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identity_id" varchar, CONSTRAINT "REL_fff3668c112a6863bb8c37519a" UNIQUE ("identity_id"))`) + await queryRunner.query(`INSERT INTO "temporary_Connection"("id", "type", "identity_id") SELECT "id", "type", "identityId" FROM "Connection"`) + await queryRunner.query(`DROP TABLE "Connection"`) + await queryRunner.query(`ALTER TABLE "temporary_Connection" RENAME TO "Connection"`) + await queryRunner.query(`CREATE TABLE "PartyType" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('naturalPerson','organization') ) NOT NULL, "name" varchar(255) NOT NULL, "description" varchar(255), "tenant_id" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "UQ_06658931a9c40b5c1f7371210a7" UNIQUE ("name"))`) + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_PartyTypeEntity_type_tenantId" ON "PartyType" ("type", "tenant_id")`) + await queryRunner.query(`CREATE TABLE "BaseContact" ("id" varchar PRIMARY KEY NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "legal_name" varchar(255), "display_name" varchar(255), "first_name" varchar(255), "middle_name" varchar(255), "last_name" varchar(255), "type" varchar NOT NULL, "party_id" varchar, CONSTRAINT "UQ_b8c8005251433839dfc2babf9f8" UNIQUE ("legal_name"), CONSTRAINT "REL_be0b2a601d6a71b07e2a8a5b61" UNIQUE ("party_id"))`) + await queryRunner.query(`CREATE INDEX "IDX_d265e69d45aa55a9e197f5e626" ON "BaseContact" ("type")`) + await queryRunner.query(`CREATE TABLE "PartyRelationship" ("id" varchar PRIMARY KEY NOT NULL, "left_id" varchar NOT NULL, "right_id" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')))`) + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_PartyRelationshipEntity_left_right" ON "PartyRelationship" ("left_id", "right_id")`) + await queryRunner.query(`CREATE TABLE "ElectronicAddress" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar(255) NOT NULL, "electronic_address" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "partyId" varchar)`) + await queryRunner.query(`CREATE TABLE "Party" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "party_type_id" varchar NOT NULL)`) + await queryRunner.query(`CREATE TABLE "BaseConfig" ("id" varchar PRIMARY KEY NOT NULL, "identifier" varchar(255), "redirect_url" varchar(255), "session_id" varchar(255), "client_id" varchar(255), "client_secret" varchar(255), "scopes" text, "issuer" varchar(255), "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "type" varchar NOT NULL, "connection_id" varchar, CONSTRAINT "REL_4b10e0398e0bc003b479a21f53" UNIQUE ("connection_id"))`) + await queryRunner.query(`CREATE INDEX "IDX_5624e2253276217cf609b044b1" ON "BaseConfig" ("type")`) + await queryRunner.query(`CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identity_id" varchar, CONSTRAINT "REL_28945c1d57c5feee1d5d1f5451" UNIQUE ("identity_id"), CONSTRAINT "UQ_775cbf83c248bc73c42aef55664" UNIQUE ("correlation_id"), CONSTRAINT "FK_d98b8f355649e9d090ee2a915ca" FOREIGN KEY ("identity_id") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) + await queryRunner.query(`INSERT INTO "temporary_CorrelationIdentifier"("id", "type", "correlation_id", "identity_id") SELECT "id", "type", "correlation_id", "identity_id" FROM "CorrelationIdentifier"`) await queryRunner.query(`DROP TABLE "CorrelationIdentifier"`) await queryRunner.query(`ALTER TABLE "temporary_CorrelationIdentifier" RENAME TO "CorrelationIdentifier"`) - await queryRunner.query( - `CREATE TABLE "temporary_IdentityMetadata" ("id" varchar PRIMARY KEY NOT NULL, "label" varchar(255) NOT NULL, "value" varchar(255) NOT NULL, "identityId" varchar, CONSTRAINT "FK_e22568cc3d201c0131b87186117" FOREIGN KEY ("identityId") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` - ) - await queryRunner.query( - `INSERT INTO "temporary_IdentityMetadata"("id", "label", "value", "identityId") SELECT "id", "label", "value", "identityId" FROM "IdentityMetadata"` - ) - await queryRunner.query(`DROP TABLE "IdentityMetadata"`) - await queryRunner.query(`ALTER TABLE "temporary_IdentityMetadata" RENAME TO "IdentityMetadata"`) - await queryRunner.query(`DROP INDEX "IDX_e50c368daf85e7ae54585b0f7b"`) - await queryRunner.query( - `CREATE TABLE "temporary_ContactOwner" ("id" varchar PRIMARY KEY NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "firstName" varchar(255), "middleName" varchar(255), "lastName" varchar(255), "displayName" varchar(255), "legalName" varchar(255), "type" varchar NOT NULL, "contactId" varchar, CONSTRAINT "UQ_9177af8a51a2a0598d3a8c68e1e" UNIQUE ("displayName"), CONSTRAINT "UQ_91bf22d2597ff429ece6ae807aa" UNIQUE ("legalName"), CONSTRAINT "UQ_9177af8a51a2a0598d3a8c68e1e" UNIQUE ("displayName"), CONSTRAINT "REL_26ce21b29da1426fa1198b947e" UNIQUE ("contactId"), CONSTRAINT "FK_26ce21b29da1426fa1198b947e1" FOREIGN KEY ("contactId") REFERENCES "Contact" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` - ) - await queryRunner.query( - `INSERT INTO "temporary_ContactOwner"("id", "created_at", "last_updated_at", "firstName", "middleName", "lastName", "displayName", "legalName", "type", "contactId") SELECT "id", "created_at", "last_updated_at", "firstName", "middleName", "lastName", "displayName", "legalName", "type", "contactId" FROM "ContactOwner"` - ) - await queryRunner.query(`DROP TABLE "ContactOwner"`) - await queryRunner.query(`ALTER TABLE "temporary_ContactOwner" RENAME TO "ContactOwner"`) - await queryRunner.query(`CREATE INDEX "IDX_e50c368daf85e7ae54585b0f7b" ON "ContactOwner" ("type")`) - await queryRunner.query(`DROP INDEX "IDX_ContactRelationshipEntity_left_right"`) - await queryRunner.query( - `CREATE TABLE "temporary_ContactRelationship" ("id" varchar PRIMARY KEY NOT NULL, "leftId" varchar NOT NULL, "rightId" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "FK_24a7bc0595cc5da51c91e1bee62" FOREIGN KEY ("leftId") REFERENCES "Contact" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "FK_e673c9f78f3c7670a75c0ea7710" FOREIGN KEY ("rightId") REFERENCES "Contact" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` - ) - await queryRunner.query( - `INSERT INTO "temporary_ContactRelationship"("id", "leftId", "rightId", "created_at", "last_updated_at") SELECT "id", "leftId", "rightId", "created_at", "last_updated_at" FROM "ContactRelationship"` - ) - await queryRunner.query(`DROP TABLE "ContactRelationship"`) - await queryRunner.query(`ALTER TABLE "temporary_ContactRelationship" RENAME TO "ContactRelationship"`) - await queryRunner.query(`CREATE UNIQUE INDEX "IDX_ContactRelationshipEntity_left_right" ON "ContactRelationship" ("leftId", "rightId")`) - await queryRunner.query( - `CREATE TABLE "temporary_Contact" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactTypeId" varchar NOT NULL, CONSTRAINT "FK_a992c5cdc48d0bc105d0338f982" FOREIGN KEY ("contactTypeId") REFERENCES "ContactType" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)` - ) - await queryRunner.query( - `INSERT INTO "temporary_Contact"("id", "uri", "created_at", "last_updated_at", "contactTypeId") SELECT "id", "uri", "created_at", "last_updated_at", "contactTypeId" FROM "Contact"` - ) - await queryRunner.query(`DROP TABLE "Contact"`) - await queryRunner.query(`ALTER TABLE "temporary_Contact" RENAME TO "Contact"`) - await queryRunner.query( - `CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Alias" UNIQUE ("alias"), CONSTRAINT "FK_70ac2a54e2041b7914613204e3d" FOREIGN KEY ("contactId") REFERENCES "Contact" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` - ) - await queryRunner.query( - `INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"` - ) + await queryRunner.query(`DROP INDEX "IDX_d265e69d45aa55a9e197f5e626"`) + await queryRunner.query(`CREATE TABLE "temporary_BaseContact" ("id" varchar PRIMARY KEY NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "legal_name" varchar(255), "display_name" varchar(255), "first_name" varchar(255), "middle_name" varchar(255), "last_name" varchar(255), "type" varchar NOT NULL, "party_id" varchar, CONSTRAINT "UQ_b8c8005251433839dfc2babf9f8" UNIQUE ("legal_name"), CONSTRAINT "REL_be0b2a601d6a71b07e2a8a5b61" UNIQUE ("party_id"), CONSTRAINT "FK_be0b2a601d6a71b07e2a8a5b61e" FOREIGN KEY ("party_id") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) + await queryRunner.query(`INSERT INTO "temporary_BaseContact"("id", "created_at", "last_updated_at", "legal_name", "display_name", "first_name", "middle_name", "last_name", "type", "party_id") SELECT "id", "created_at", "last_updated_at", "legal_name", "display_name", "first_name", "middle_name", "last_name", "type", "party_id" FROM "BaseContact"`) + await queryRunner.query(`DROP TABLE "BaseContact"`) + await queryRunner.query(`ALTER TABLE "temporary_BaseContact" RENAME TO "BaseContact"`) + await queryRunner.query(`CREATE INDEX "IDX_d265e69d45aa55a9e197f5e626" ON "BaseContact" ("type")`) + await queryRunner.query(`DROP INDEX "IDX_PartyRelationshipEntity_left_right"`) + await queryRunner.query(`CREATE TABLE "temporary_PartyRelationship" ("id" varchar PRIMARY KEY NOT NULL, "left_id" varchar NOT NULL, "right_id" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "FK_c3db1bd42ed96c5164b2e6276bf" FOREIGN KEY ("left_id") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "FK_f366006d2ad5adbe3632277f1c0" FOREIGN KEY ("right_id") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) + await queryRunner.query(`INSERT INTO "temporary_PartyRelationship"("id", "left_id", "right_id", "created_at", "last_updated_at") SELECT "id", "left_id", "right_id", "created_at", "last_updated_at" FROM "PartyRelationship"`) + await queryRunner.query(`DROP TABLE "PartyRelationship"`) + await queryRunner.query(`ALTER TABLE "temporary_PartyRelationship" RENAME TO "PartyRelationship"`) + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_PartyRelationshipEntity_left_right" ON "PartyRelationship" ("left_id", "right_id")`) + await queryRunner.query(`CREATE TABLE "temporary_ElectronicAddress" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar(255) NOT NULL, "electronic_address" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "partyId" varchar, CONSTRAINT "FK_672ac311680d9c366405bb5737c" FOREIGN KEY ("partyId") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) + await queryRunner.query(`INSERT INTO "temporary_ElectronicAddress"("id", "type", "electronic_address", "created_at", "last_updated_at", "partyId") SELECT "id", "type", "electronic_address", "created_at", "last_updated_at", "partyId" FROM "ElectronicAddress"`) + await queryRunner.query(`DROP TABLE "ElectronicAddress"`) + await queryRunner.query(`ALTER TABLE "temporary_ElectronicAddress" RENAME TO "ElectronicAddress"`) + await queryRunner.query(`CREATE TABLE "temporary_Party" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "party_type_id" varchar NOT NULL, CONSTRAINT "FK_d6b87c0830068c6d396a501e3d1" FOREIGN KEY ("party_type_id") REFERENCES "PartyType" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`) + await queryRunner.query(`INSERT INTO "temporary_Party"("id", "uri", "created_at", "last_updated_at", "party_type_id") SELECT "id", "uri", "created_at", "last_updated_at", "party_type_id" FROM "Party"`) + await queryRunner.query(`DROP TABLE "Party"`) + await queryRunner.query(`ALTER TABLE "temporary_Party" RENAME TO "Party"`) + await queryRunner.query(`CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "partyId" varchar, CONSTRAINT "UQ_cbeaf6b68b6dbc9eb8dc3503499" UNIQUE ("alias"), CONSTRAINT "FK_916e4ef6ee2f24c5c88bdc9dfbb" FOREIGN KEY ("partyId") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) + await queryRunner.query(`INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "partyId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "partyId" FROM "Identity"`) await queryRunner.query(`DROP TABLE "Identity"`) await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) - await queryRunner.query( - `CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identityId" varchar, CONSTRAINT "REL_Connection_identityId" UNIQUE ("identityId"), CONSTRAINT "FK_fff3668c112a6863bb8c37519a0" FOREIGN KEY ("identityId") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` - ) - await queryRunner.query(`INSERT INTO "temporary_Connection"("id", "type", "identityId") SELECT "id", "type", "identityId" FROM "Connection"`) + await queryRunner.query(`CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identity_id" varchar, CONSTRAINT "REL_fff3668c112a6863bb8c37519a" UNIQUE ("identity_id"), CONSTRAINT "FK_360ccf2d714878339680a197d26" FOREIGN KEY ("identity_id") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) + await queryRunner.query(`INSERT INTO "temporary_Connection"("id", "type", "identity_id") SELECT "id", "type", "identity_id" FROM "Connection"`) await queryRunner.query(`DROP TABLE "Connection"`) await queryRunner.query(`ALTER TABLE "temporary_Connection" RENAME TO "Connection"`) + await queryRunner.query(`DROP INDEX "IDX_5624e2253276217cf609b044b1"`) + await queryRunner.query(`CREATE TABLE "temporary_BaseConfig" ("id" varchar PRIMARY KEY NOT NULL, "identifier" varchar(255), "redirect_url" varchar(255), "session_id" varchar(255), "client_id" varchar(255), "client_secret" varchar(255), "scopes" text, "issuer" varchar(255), "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "type" varchar NOT NULL, "connection_id" varchar, CONSTRAINT "REL_4b10e0398e0bc003b479a21f53" UNIQUE ("connection_id"), CONSTRAINT "FK_4b10e0398e0bc003b479a21f53e" FOREIGN KEY ("connection_id") REFERENCES "Connection" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) + await queryRunner.query(`INSERT INTO "temporary_BaseConfig"("id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id") SELECT "id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id" FROM "BaseConfig"`) + await queryRunner.query(`DROP TABLE "BaseConfig"`) + await queryRunner.query(`ALTER TABLE "temporary_BaseConfig" RENAME TO "BaseConfig"`) + await queryRunner.query(`CREATE INDEX "IDX_5624e2253276217cf609b044b1" ON "BaseConfig" ("type")`) + + // migrate existing data + await queryRunner.query(`INSERT INTO "BaseConfig"("id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id") SELECT "id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id" FROM "BaseConfigEntity"`) + await queryRunner.query(`DROP TABLE "BaseConfigEntity"`) + await queryRunner.query(`INSERT INTO "PartyType"(id, type, name, description, tenant_id, created_at, last_updated_at) VALUES ('3875c12e-fdaa-4ef6-a340-c936e054b627', 'organization', 'Sphereon_default_type', 'sphereon_default_organization', '95e09cfc-c974-4174-86aa-7bf1d5251fb4', datetime('now'), datetime('now'))`) + await queryRunner.query(`INSERT INTO "Party"(id, uri, created_at, last_updated_at, party_type_id) SELECT id, uri, created_at, last_updated_at, '3875c12e-fdaa-4ef6-a340-c936e054b627' FROM Contact`) + await queryRunner.query(`INSERT INTO "BaseContact"(id, legal_name, display_name, party_id, created_at, last_updated_at, type) SELECT id, name, alias, id, created_at, last_updated_at, 'Organization' FROM Contact`) + await queryRunner.query(`DROP TABLE "Contact"`) + + + + + // await queryRunner.query(`DROP INDEX "IDX_BaseConfigEntity_type"`) + // await queryRunner.query( + // `CREATE TABLE "temporary_BaseConfigEntity" ("id" varchar PRIMARY KEY NOT NULL, "client_id" varchar(255), "client_secret" varchar(255), "scopes" text, "issuer" varchar(255), "redirect_url" text, "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "identifier" varchar(255), "session_id" varchar(255), "type" varchar NOT NULL, "connectionId" varchar, CONSTRAINT "REL_BaseConfig_connectionId" UNIQUE ("connectionId"))` + // ) + // await queryRunner.query( + // `INSERT INTO "temporary_BaseConfigEntity"("id", "client_id", "client_secret", "scopes", "issuer", "redirect_url", "dangerously_allow_insecure_http_requests", "client_auth_method", "identifier", "session_id", "type", "connectionId") SELECT "id", "client_id", "client_secret", "scopes", "issuer", "redirect_url", "dangerously_allow_insecure_http_requests", "client_auth_method", "identifier", "session_id", "type", "connectionId" FROM "BaseConfigEntity"` + // ) + // await queryRunner.query(`DROP TABLE "BaseConfigEntity"`) + // await queryRunner.query(`ALTER TABLE "temporary_BaseConfigEntity" RENAME TO "BaseConfigEntity"`) + // await queryRunner.query(`CREATE INDEX "IDX_BaseConfigEntity_type" ON "BaseConfigEntity" ("type")`) + // await queryRunner.query( + // `CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identityId" varchar, CONSTRAINT "REL_CorrelationIdentifier_identityId" UNIQUE ("identityId"), CONSTRAINT "UQ_Correlation_id" UNIQUE ("correlation_id"))` + // ) + // await queryRunner.query( + // `INSERT INTO "temporary_CorrelationIdentifier"("id", "type", "correlation_id", "identityId") SELECT "id", "type", "correlation_id", "identityId" FROM "CorrelationIdentifier"` + // ) + // await queryRunner.query(`DROP TABLE "CorrelationIdentifier"`) + // await queryRunner.query(`ALTER TABLE "temporary_CorrelationIdentifier" RENAME TO "CorrelationIdentifier"`) + // await queryRunner.query( + // `CREATE TABLE "temporary_IdentityMetadata" ("id" varchar PRIMARY KEY NOT NULL, "label" varchar(255) NOT NULL, "value" varchar(255) NOT NULL, "identityId" varchar)` + // ) + // await queryRunner.query( + // `INSERT INTO "temporary_IdentityMetadata"("id", "label", "value", "identityId") SELECT "id", "label", "value", "identityId" FROM "IdentityMetadata"` + // ) + // await queryRunner.query(`DROP TABLE "IdentityMetadata"`) + // await queryRunner.query(`ALTER TABLE "temporary_IdentityMetadata" RENAME TO "IdentityMetadata"`) + // await queryRunner.query( + // `CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Alias" UNIQUE ("alias"))` + // ) + // await queryRunner.query( + // `INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"` + // ) + // await queryRunner.query(`DROP TABLE "Identity"`) + // await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) + // await queryRunner.query( + // `CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identityId" varchar, CONSTRAINT "REL_Connection_identityId" UNIQUE ("identityId"))` + // ) + // await queryRunner.query(`INSERT INTO "temporary_Connection"("id", "type", "identityId") SELECT "id", "type", "identityId" FROM "Connection"`) + // await queryRunner.query(`DROP TABLE "Connection"`) + // await queryRunner.query(`ALTER TABLE "temporary_Connection" RENAME TO "Connection"`) + // await queryRunner.query(`DROP INDEX "IDX_BaseConfigEntity_type"`) + // await queryRunner.query( + // `CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Alias" UNIQUE ("alias"))` + // ) + // await queryRunner.query( + // `INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"` + // ) + // await queryRunner.query(`DROP TABLE "Identity"`) + // await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) + // await queryRunner.query( + // `CREATE TABLE "ContactType" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('person','organization') ) NOT NULL, "name" varchar(255) NOT NULL, "description" varchar(255), "tenantId" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "UQ_2229e0d8c1e6817efcc982a6dde" UNIQUE ("name"))` + // ) + // await queryRunner.query(`CREATE UNIQUE INDEX "IDX_1a1fa2aa0a56649427e427a41f" ON "ContactType" ("type", "tenantId")`) + // await queryRunner.query( + // `CREATE TABLE "ContactOwner" ("id" varchar PRIMARY KEY NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "firstName" varchar(255), "middleName" varchar(255), "lastName" varchar(255), "displayName" varchar(255), "legalName" varchar(255), "type" varchar NOT NULL, "contactId" varchar, CONSTRAINT "UQ_9177af8a51a2a0598d3a8c68e1e" UNIQUE ("displayName"), CONSTRAINT "UQ_91bf22d2597ff429ece6ae807aa" UNIQUE ("legalName"), CONSTRAINT "UQ_9177af8a51a2a0598d3a8c68e1e" UNIQUE ("displayName"), CONSTRAINT "REL_26ce21b29da1426fa1198b947e" UNIQUE ("contactId"))` + // ) + // await queryRunner.query(`CREATE INDEX "IDX_e50c368daf85e7ae54585b0f7b" ON "ContactOwner" ("type")`) + // await queryRunner.query( + // `CREATE TABLE "ContactRelationship" ("id" varchar PRIMARY KEY NOT NULL, "leftId" varchar NOT NULL, "rightId" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')))` + // ) + // await queryRunner.query(`CREATE UNIQUE INDEX "IDX_ContactRelationshipEntity_left_right" ON "ContactRelationship" ("leftId", "rightId")`) + // await queryRunner.query( + // `CREATE TABLE "temporary_Contact" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')))` + // ) + // await queryRunner.query( + // `INSERT INTO "temporary_Contact"("id", "uri", "created_at", "last_updated_at") SELECT "id", "uri", "created_at", "last_updated_at" FROM "Contact"` + // ) + // await queryRunner.query(`DROP TABLE "Contact"`) + // await queryRunner.query(`ALTER TABLE "temporary_Contact" RENAME TO "Contact"`) + // await queryRunner.query( + // `CREATE TABLE "temporary_Contact" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactTypeId" varchar NOT NULL)` + // ) + // await queryRunner.query( + // `INSERT INTO "temporary_Contact"("id", "uri", "created_at", "last_updated_at") SELECT "id", "uri", "created_at", "last_updated_at" FROM "Contact"` + // ) + // await queryRunner.query(`DROP TABLE "Contact"`) + // await queryRunner.query(`ALTER TABLE "temporary_Contact" RENAME TO "Contact"`) + // await queryRunner.query( + // `CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Alias" UNIQUE ("alias"))` + // ) + // await queryRunner.query( + // `INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"` + // ) + // await queryRunner.query(`DROP TABLE "Identity"`) + // await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) + // await queryRunner.query(`CREATE INDEX "IDX_228953a09ee91bbac6e28b7345" ON "BaseConfigEntity" ("type")`) + // await queryRunner.query(`DROP INDEX "IDX_228953a09ee91bbac6e28b7345"`) + // await queryRunner.query( + // `CREATE TABLE "temporary_BaseConfigEntity" ("id" varchar PRIMARY KEY NOT NULL, "client_id" varchar(255), "client_secret" varchar(255), "scopes" text, "issuer" varchar(255), "redirect_url" text, "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "identifier" varchar(255), "session_id" varchar(255), "type" varchar NOT NULL, "connectionId" varchar, CONSTRAINT "REL_BaseConfig_connectionId" UNIQUE ("connectionId"), CONSTRAINT "FK_0ab3b33e0a87e1706025e63d8a9" FOREIGN KEY ("connectionId") REFERENCES "Connection" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + // ) + // await queryRunner.query( + // `INSERT INTO "temporary_BaseConfigEntity"("id", "client_id", "client_secret", "scopes", "issuer", "redirect_url", "dangerously_allow_insecure_http_requests", "client_auth_method", "identifier", "session_id", "type", "connectionId") SELECT "id", "client_id", "client_secret", "scopes", "issuer", "redirect_url", "dangerously_allow_insecure_http_requests", "client_auth_method", "identifier", "session_id", "type", "connectionId" FROM "BaseConfigEntity"` + // ) + // await queryRunner.query(`DROP TABLE "BaseConfigEntity"`) + // await queryRunner.query(`ALTER TABLE "temporary_BaseConfigEntity" RENAME TO "BaseConfigEntity"`) + // await queryRunner.query(`CREATE INDEX "IDX_228953a09ee91bbac6e28b7345" ON "BaseConfigEntity" ("type")`) + // await queryRunner.query( + // `CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identityId" varchar, CONSTRAINT "REL_CorrelationIdentifier_identityId" UNIQUE ("identityId"), CONSTRAINT "UQ_Correlation_id" UNIQUE ("correlation_id"), CONSTRAINT "FK_28945c1d57c5feee1d5d1f54510" FOREIGN KEY ("identityId") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + // ) + // await queryRunner.query( + // `INSERT INTO "temporary_CorrelationIdentifier"("id", "type", "correlation_id", "identityId") SELECT "id", "type", "correlation_id", "identityId" FROM "CorrelationIdentifier"` + // ) + // await queryRunner.query(`DROP TABLE "CorrelationIdentifier"`) + // await queryRunner.query(`ALTER TABLE "temporary_CorrelationIdentifier" RENAME TO "CorrelationIdentifier"`) + // await queryRunner.query( + // `CREATE TABLE "temporary_IdentityMetadata" ("id" varchar PRIMARY KEY NOT NULL, "label" varchar(255) NOT NULL, "value" varchar(255) NOT NULL, "identityId" varchar, CONSTRAINT "FK_e22568cc3d201c0131b87186117" FOREIGN KEY ("identityId") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + // ) + // await queryRunner.query( + // `INSERT INTO "temporary_IdentityMetadata"("id", "label", "value", "identityId") SELECT "id", "label", "value", "identityId" FROM "IdentityMetadata"` + // ) + // await queryRunner.query(`DROP TABLE "IdentityMetadata"`) + // await queryRunner.query(`ALTER TABLE "temporary_IdentityMetadata" RENAME TO "IdentityMetadata"`) + // await queryRunner.query(`DROP INDEX "IDX_e50c368daf85e7ae54585b0f7b"`) + // await queryRunner.query( + // `CREATE TABLE "temporary_ContactOwner" ("id" varchar PRIMARY KEY NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "firstName" varchar(255), "middleName" varchar(255), "lastName" varchar(255), "displayName" varchar(255), "legalName" varchar(255), "type" varchar NOT NULL, "contactId" varchar, CONSTRAINT "UQ_9177af8a51a2a0598d3a8c68e1e" UNIQUE ("displayName"), CONSTRAINT "UQ_91bf22d2597ff429ece6ae807aa" UNIQUE ("legalName"), CONSTRAINT "UQ_9177af8a51a2a0598d3a8c68e1e" UNIQUE ("displayName"), CONSTRAINT "REL_26ce21b29da1426fa1198b947e" UNIQUE ("contactId"), CONSTRAINT "FK_26ce21b29da1426fa1198b947e1" FOREIGN KEY ("contactId") REFERENCES "Contact" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + // ) + // await queryRunner.query( + // `INSERT INTO "temporary_ContactOwner"("id", "created_at", "last_updated_at", "firstName", "middleName", "lastName", "displayName", "legalName", "type", "contactId") SELECT "id", "created_at", "last_updated_at", "firstName", "middleName", "lastName", "displayName", "legalName", "type", "contactId" FROM "ContactOwner"` + // ) + // await queryRunner.query(`DROP TABLE "ContactOwner"`) + // await queryRunner.query(`ALTER TABLE "temporary_ContactOwner" RENAME TO "ContactOwner"`) + // await queryRunner.query(`CREATE INDEX "IDX_e50c368daf85e7ae54585b0f7b" ON "ContactOwner" ("type")`) + // await queryRunner.query(`DROP INDEX "IDX_ContactRelationshipEntity_left_right"`) + // await queryRunner.query( + // `CREATE TABLE "temporary_ContactRelationship" ("id" varchar PRIMARY KEY NOT NULL, "leftId" varchar NOT NULL, "rightId" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "FK_24a7bc0595cc5da51c91e1bee62" FOREIGN KEY ("leftId") REFERENCES "Contact" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "FK_e673c9f78f3c7670a75c0ea7710" FOREIGN KEY ("rightId") REFERENCES "Contact" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + // ) + // await queryRunner.query( + // `INSERT INTO "temporary_ContactRelationship"("id", "leftId", "rightId", "created_at", "last_updated_at") SELECT "id", "leftId", "rightId", "created_at", "last_updated_at" FROM "ContactRelationship"` + // ) + // await queryRunner.query(`DROP TABLE "ContactRelationship"`) + // await queryRunner.query(`ALTER TABLE "temporary_ContactRelationship" RENAME TO "ContactRelationship"`) + // await queryRunner.query(`CREATE UNIQUE INDEX "IDX_ContactRelationshipEntity_left_right" ON "ContactRelationship" ("leftId", "rightId")`) + // await queryRunner.query( + // `CREATE TABLE "temporary_Contact" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactTypeId" varchar NOT NULL, CONSTRAINT "FK_a992c5cdc48d0bc105d0338f982" FOREIGN KEY ("contactTypeId") REFERENCES "ContactType" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)` + // ) + // await queryRunner.query( + // `INSERT INTO "temporary_Contact"("id", "uri", "created_at", "last_updated_at", "contactTypeId") SELECT "id", "uri", "created_at", "last_updated_at", "contactTypeId" FROM "Contact"` + // ) + // await queryRunner.query(`DROP TABLE "Contact"`) + // await queryRunner.query(`ALTER TABLE "temporary_Contact" RENAME TO "Contact"`) + // await queryRunner.query( + // `CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Alias" UNIQUE ("alias"), CONSTRAINT "FK_70ac2a54e2041b7914613204e3d" FOREIGN KEY ("contactId") REFERENCES "Contact" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + // ) + // await queryRunner.query( + // `INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"` + // ) + // await queryRunner.query(`DROP TABLE "Identity"`) + // await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) + // await queryRunner.query( + // `CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identityId" varchar, CONSTRAINT "REL_Connection_identityId" UNIQUE ("identityId"), CONSTRAINT "FK_fff3668c112a6863bb8c37519a0" FOREIGN KEY ("identityId") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + // ) + // await queryRunner.query(`INSERT INTO "temporary_Connection"("id", "type", "identityId") SELECT "id", "type", "identityId" FROM "Connection"`) + // await queryRunner.query(`DROP TABLE "Connection"`) + // await queryRunner.query(`ALTER TABLE "temporary_Connection" RENAME TO "Connection"`) } public async down(queryRunner: QueryRunner): Promise {} From 1d541455c191451b3e5ccfa4974c14087a599bce Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Mon, 4 Sep 2023 12:20:42 +0200 Subject: [PATCH 12/35] DPP-1 postgres migration constraint name fix --- .../src/migrations/postgres/1659463079428-CreateContacts.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/data-store/src/migrations/postgres/1659463079428-CreateContacts.ts b/packages/data-store/src/migrations/postgres/1659463079428-CreateContacts.ts index 915d186fc..9d69f599f 100644 --- a/packages/data-store/src/migrations/postgres/1659463079428-CreateContacts.ts +++ b/packages/data-store/src/migrations/postgres/1659463079428-CreateContacts.ts @@ -13,13 +13,13 @@ export class CreateContacts1659463079428 implements MigrationInterface { `CREATE TABLE "CorrelationIdentifier" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "type" "public"."CorrelationIdentifier_type_enum" NOT NULL, "correlation_id" text NOT NULL, "identityId" uuid, CONSTRAINT "UQ_Correlation_id" UNIQUE ("correlation_id"), CONSTRAINT "REL_CorrelationIdentifier_identityId" UNIQUE ("identityId"), CONSTRAINT "PK_CorrelationIdentifier_id" PRIMARY KEY ("id"))` ) await queryRunner.query( - `CREATE TABLE "Contact" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "name" character varying(255) NOT NULL, "alias" character varying(255) NOT NULL, "uri" character varying(255) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "UQ_Name" UNIQUE ("name"), CONSTRAINT "UQ_Alias" UNIQUE ("alias"), CONSTRAINT "PK_Contact_id" PRIMARY KEY ("id"))` + `CREATE TABLE "Contact" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "name" character varying(255) NOT NULL, "alias" character varying(255) NOT NULL, "uri" character varying(255) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "UQ_Name" UNIQUE ("name"), CONSTRAINT "UQ_Contact_Alias" UNIQUE ("alias"), CONSTRAINT "PK_Contact_id" PRIMARY KEY ("id"))` ) await queryRunner.query( `CREATE TABLE "IdentityMetadata" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "label" character varying(255) NOT NULL, "value" character varying(255) NOT NULL, "identityId" uuid, CONSTRAINT "PK_IdentityMetadata_id" PRIMARY KEY ("id"))` ) await queryRunner.query( - `CREATE TABLE "Identity" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "alias" character varying(255) NOT NULL, "roles" text, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), "contactId" uuid, CONSTRAINT "UQ_Alias" UNIQUE ("alias"), CONSTRAINT "PK_Identity_id" PRIMARY KEY ("id"))` + `CREATE TABLE "Identity" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "alias" character varying(255) NOT NULL, "roles" text, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), "contactId" uuid, CONSTRAINT "UQ_Identity_Alias" UNIQUE ("alias"), CONSTRAINT "PK_Identity_id" PRIMARY KEY ("id"))` ) await queryRunner.query(`CREATE TYPE "public"."Connection_type_enum" AS ENUM('OIDC', 'SIOPv2', 'SIOPv2+OpenID4VP')`) await queryRunner.query( From 02cc4f3ed7ba9bae52b0fa3d67702b588a5c2042 Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Mon, 4 Sep 2023 12:50:59 +0200 Subject: [PATCH 13/35] DPP-1 postgres migration WIP --- packages/data-store/package.json | 1 + .../src/__tests__/contact.entities.test.ts | 41 ++++-- pnpm-lock.yaml | 125 ++++++++++++++++-- 3 files changed, 145 insertions(+), 22 deletions(-) diff --git a/packages/data-store/package.json b/packages/data-store/package.json index 6b265e0e7..87763b054 100644 --- a/packages/data-store/package.json +++ b/packages/data-store/package.json @@ -17,6 +17,7 @@ "@veramo/core": "4.2.0", "class-validator": "^0.14.0", "debug": "^4.3.4", + "pg": "^8.11.3", "typeorm": "^0.3.12" }, "devDependencies": { diff --git a/packages/data-store/src/__tests__/contact.entities.test.ts b/packages/data-store/src/__tests__/contact.entities.test.ts index 846d609a1..8881d2cd7 100644 --- a/packages/data-store/src/__tests__/contact.entities.test.ts +++ b/packages/data-store/src/__tests__/contact.entities.test.ts @@ -4,7 +4,7 @@ import { DataSource, import { DataStoreContactEntities, - DataStoreMigrations + //DataStoreMigrations } from '../index' //import { NaturalPersonEntity } from '../entities/contact/NaturalPersonEntity' // import { OrganizationEntity } from '../entities/contact/OrganizationEntity' @@ -77,18 +77,43 @@ describe('Database entities tests', (): void => { // // expect(await dbConnection.showMigrations()).toBeFalsy() // }) + // sqlite + // beforeEach(async (): Promise => { + // dbConnection = await new DataSource({ + // type: 'sqlite', + // database: './database.sqlite', + // logging: 'all', + // migrationsRun: false, + // migrations: DataStoreMigrations, + // synchronize: false, //false + // entities: DataStoreContactEntities, + // }).initialize() + // await dbConnection.runMigrations() + // expect(await dbConnection.showMigrations()).toBeFalsy() + // }) + + // postgres beforeEach(async (): Promise => { dbConnection = await new DataSource({ - type: 'sqlite', - database: './database.sqlite', - logging: 'all', + // type: 'sqlite', + // database: ':memory:', + // //logging: 'all', + + + type: 'postgres', + host: 'localhost', // or '127.0.0.1' + port: 5432, // Default PostgreSQL port + username: 'postgres', + password: 'btencate', + database: 'contacts-ssi-sdk', + migrationsRun: false, - migrations: DataStoreMigrations, - synchronize: false, //false + //migrations: DataStoreMigrations, + synchronize: true, //false entities: DataStoreContactEntities, }).initialize() - await dbConnection.runMigrations() - expect(await dbConnection.showMigrations()).toBeFalsy() + //await dbConnection.runMigrations() + //expect(await dbConnection.showMigrations()).toBeFalsy() }) afterEach(async (): Promise => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b4383b9f3..bbd8e3eb1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -172,7 +172,7 @@ importers: version: 5.0.1 typeorm: specifier: ^0.3.12 - version: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) url-parse: specifier: ^1.5.10 version: 1.5.10 @@ -194,7 +194,7 @@ importers: version: 3.1.5 typeorm: specifier: ^0.3.12 - version: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) devDependencies: '@sphereon/ssi-sdk.agent-config': specifier: workspace:* @@ -220,9 +220,12 @@ importers: debug: specifier: ^4.3.4 version: 4.3.4 + pg: + specifier: ^8.11.3 + version: 8.11.3 typeorm: specifier: ^0.3.12 - version: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) devDependencies: sqlite3: specifier: ^5.1.6 @@ -299,7 +302,7 @@ importers: version: 4.3.4 typeorm: specifier: ^0.3.12 - version: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) devDependencies: '@sphereon/ssi-sdk.agent-config': specifier: workspace:* @@ -327,7 +330,7 @@ importers: version: 3.0.1 typeorm: specifier: ^0.3.12 - version: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) uint8arrays: specifier: ^3.1.1 version: 3.1.1 @@ -419,7 +422,7 @@ importers: version: 1.17.2 typeorm: specifier: ^0.3.12 - version: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) devDependencies: '@sphereon/ssi-sdk.agent-config': specifier: workspace:* @@ -671,7 +674,7 @@ importers: version: 10.9.1(@types/node@18.16.3)(typescript@4.9.5) typeorm: specifier: ^0.3.12 - version: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) web-did-resolver: specifier: ^2.0.24 version: 2.0.24 @@ -1153,7 +1156,7 @@ importers: version: 10.9.1(@types/node@18.16.3)(typescript@4.9.5) typeorm: specifier: ^0.3.12 - version: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) packages/siopv2-oid4vp-rp-rest-client: dependencies: @@ -1563,7 +1566,7 @@ importers: version: 10.9.1(@types/node@18.16.3)(typescript@4.9.5) typeorm: specifier: ^0.3.12 - version: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) packages/wellknown-did-issuer: dependencies: @@ -1587,7 +1590,7 @@ importers: version: 3.1.3 typeorm: specifier: ^0.3.12 - version: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) uuid: specifier: ^8.3.2 version: 8.3.2 @@ -1956,6 +1959,7 @@ packages: /@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.22.9): resolution: {integrity: sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==} engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead. peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -1968,6 +1972,7 @@ packages: /@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.22.9): resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==} engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead. peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -2001,6 +2006,7 @@ packages: /@babel/plugin-proposal-export-namespace-from@7.18.9(@babel/core@7.22.9): resolution: {integrity: sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==} engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-export-namespace-from instead. peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -2011,6 +2017,7 @@ packages: /@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.22.9): resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==} engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead. peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -2021,6 +2028,7 @@ packages: /@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.22.9): resolution: {integrity: sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==} engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-numeric-separator instead. peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -2031,6 +2039,7 @@ packages: /@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.22.9): resolution: {integrity: sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==} engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead. peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -2044,6 +2053,7 @@ packages: /@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.22.9): resolution: {integrity: sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==} engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-catch-binding instead. peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -2054,6 +2064,7 @@ packages: /@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.22.9): resolution: {integrity: sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==} engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead. peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -7170,7 +7181,7 @@ packages: '@veramo/key-manager': 4.2.0 '@veramo/utils': 4.2.0 debug: 4.3.4 - typeorm: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + typeorm: 0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) transitivePeerDependencies: - '@google-cloud/spanner' - '@sap/hana-client' @@ -8414,6 +8425,10 @@ packages: /buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + /buffer-writer@2.0.0: + resolution: {integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==} + engines: {node: '>=4'} + /buffer-xor@1.0.3: resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} dev: true @@ -15672,6 +15687,9 @@ packages: p-reduce: 2.1.0 dev: true + /packet-reader@1.0.0: + resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==} + /pacote@13.6.2: resolution: {integrity: sha512-Gu8fU3GsvOPkak2CkbojR7vjs3k3P9cA6uazKTHdsdV0gpCEQq2opelnEv30KRQWgVzP5Vd/5umjcedma3MKtg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} @@ -15910,6 +15928,62 @@ packages: /pause@0.0.1: resolution: {integrity: sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==} + /pg-cloudflare@1.1.1: + resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==} + requiresBuild: true + optional: true + + /pg-connection-string@2.6.2: + resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==} + + /pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + + /pg-pool@3.6.1(pg@8.11.3): + resolution: {integrity: sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==} + peerDependencies: + pg: '>=8.0' + dependencies: + pg: 8.11.3 + + /pg-protocol@1.6.0: + resolution: {integrity: sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==} + + /pg-types@2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} + dependencies: + pg-int8: 1.0.1 + postgres-array: 2.0.0 + postgres-bytea: 1.0.0 + postgres-date: 1.0.7 + postgres-interval: 1.2.0 + + /pg@8.11.3: + resolution: {integrity: sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==} + engines: {node: '>= 8.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + dependencies: + buffer-writer: 2.0.0 + packet-reader: 1.0.0 + pg-connection-string: 2.6.2 + pg-pool: 3.6.1(pg@8.11.3) + pg-protocol: 1.6.0 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.1.1 + + /pgpass@1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + dependencies: + split2: 4.2.0 + /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} @@ -15995,6 +16069,24 @@ packages: picocolors: 1.0.0 source-map-js: 1.0.2 + /postgres-array@2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} + + /postgres-bytea@1.0.0: + resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} + engines: {node: '>=0.10.0'} + + /postgres-date@1.0.7: + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} + + /postgres-interval@1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} + dependencies: + xtend: 4.0.2 + /prelude-ls@1.1.2: resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} engines: {node: '>= 0.8.0'} @@ -17302,6 +17394,10 @@ packages: readable-stream: 3.6.2 dev: true + /split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + /split@1.0.1: resolution: {integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==} dependencies: @@ -18197,7 +18293,7 @@ packages: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} dev: true - /typeorm@0.3.12(sqlite3@5.1.6)(ts-node@10.9.1): + /typeorm@0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1): resolution: {integrity: sha512-sYSxBmCf1nJLLTcYtwqZ+lQIRtLPyUoO93rHTOKk9vJCyT4UfRtU7oRsJvfvKP3nnZTD1hzz2SEy2zwPEN6OyA==} engines: {node: '>= 12.9.0'} hasBin: true @@ -18266,6 +18362,7 @@ packages: glob: 8.1.0 js-yaml: 4.1.0 mkdirp: 2.1.6 + pg: 8.11.3 reflect-metadata: 0.1.13 sha.js: 2.4.11 sqlite3: 5.1.6 @@ -19087,7 +19184,7 @@ packages: commander: 9.5.0 file:packages/data-store/sphereon-ssi-sdk.data-store-0.23.0-bram.tgz(ts-node@10.9.1): - resolution: {integrity: sha512-arZo36c1KeLyoFxzLYCu0uOqdypcsznGgy4vrS5AvfmDMMtwaAd2qrssk8SQQuDFpLq6SEuplRZ1H0I3gZqJeQ==, tarball: file:packages/data-store/sphereon-ssi-sdk.data-store-0.23.0-bram.tgz} + resolution: {integrity: sha512-SsqNGovatr817lvGbb6GZ/5omE0OjNR+zPa6IB9dtwAD1NI8Y5dWZR8doeXUACbFhBHZ/GMI5Wm6nTPg4wo81A==, tarball: file:packages/data-store/sphereon-ssi-sdk.data-store-0.23.0-bram.tgz} id: file:packages/data-store/sphereon-ssi-sdk.data-store-0.23.0-bram.tgz name: '@sphereon/ssi-sdk.data-store' version: 0.23.0-bram @@ -19096,7 +19193,7 @@ packages: '@veramo/core': 4.2.0(patch_hash=c5oempznsz4br5w3tcuk2i2mau) class-validator: 0.14.0 debug: 4.3.4 - typeorm: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + typeorm: 0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) transitivePeerDependencies: - '@google-cloud/spanner' - '@sap/hana-client' From 750b78fb90edd5968c20e6ea33b1656a5e2aedf8 Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Mon, 4 Sep 2023 13:07:22 +0200 Subject: [PATCH 14/35] DPP-1 postgres migration WIP --- packages/data-store/src/__tests__/contact.entities.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/data-store/src/__tests__/contact.entities.test.ts b/packages/data-store/src/__tests__/contact.entities.test.ts index 8881d2cd7..985d578d8 100644 --- a/packages/data-store/src/__tests__/contact.entities.test.ts +++ b/packages/data-store/src/__tests__/contact.entities.test.ts @@ -97,7 +97,7 @@ describe('Database entities tests', (): void => { dbConnection = await new DataSource({ // type: 'sqlite', // database: ':memory:', - // //logging: 'all', + logging: 'all', type: 'postgres', @@ -105,7 +105,7 @@ describe('Database entities tests', (): void => { port: 5432, // Default PostgreSQL port username: 'postgres', password: 'btencate', - database: 'contacts-ssi-sdk', + database: 'contacts2-ssi-sdk', migrationsRun: false, //migrations: DataStoreMigrations, From 1a29516ccacc05ddeadc8db85a30ec272f86308c Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Mon, 4 Sep 2023 13:48:42 +0200 Subject: [PATCH 15/35] DPP-1 postgres migration WIP --- .../postgres/1690925872592-CreateContacts.ts | 133 +++++++++++++----- 1 file changed, 97 insertions(+), 36 deletions(-) diff --git a/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts b/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts index 73cb16a50..f99a46512 100644 --- a/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts +++ b/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts @@ -3,43 +3,104 @@ import { MigrationInterface, QueryRunner } from 'typeorm' export class CreateContacts1690925872592 implements MigrationInterface { name = 'CreateContacts1690925872592' + + public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `CREATE TABLE "BaseConfigEntity" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "client_id" character varying(255), "client_secret" character varying(255), "scopes" text, "issuer" character varying(255), "redirect_url" text, "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "identifier" character varying(255), "session_id" character varying(255), "type" character varying NOT NULL, "connectionId" uuid, CONSTRAINT "REL_BaseConfig_connectionId" UNIQUE ("connectionId"), CONSTRAINT "PK_BaseConfigEntity_id" PRIMARY KEY ("id"))` - ) - await queryRunner.query(`CREATE INDEX "IDX_BaseConfigEntity_type" ON "BaseConfigEntity" ("type")`) - await queryRunner.query(`CREATE TYPE "public"."CorrelationIdentifier_type_enum" AS ENUM('did', 'url')`) - await queryRunner.query( - `CREATE TABLE "CorrelationIdentifier" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "type" "public"."CorrelationIdentifier_type_enum" NOT NULL, "correlation_id" text NOT NULL, "identityId" uuid, CONSTRAINT "UQ_Correlation_id" UNIQUE ("correlation_id"), CONSTRAINT "REL_CorrelationIdentifier_identityId" UNIQUE ("identityId"), CONSTRAINT "PK_CorrelationIdentifier_id" PRIMARY KEY ("id"))` - ) - await queryRunner.query( - `CREATE TABLE "Contact" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "name" character varying(255) NOT NULL, "alias" character varying(255) NOT NULL, "uri" character varying(255) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "UQ_Name" UNIQUE ("name"), CONSTRAINT "UQ_Alias" UNIQUE ("alias"), CONSTRAINT "PK_Contact_id" PRIMARY KEY ("id"))` - ) - await queryRunner.query( - `CREATE TABLE "IdentityMetadata" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "label" character varying(255) NOT NULL, "value" character varying(255) NOT NULL, "identityId" uuid, CONSTRAINT "PK_IdentityMetadata_id" PRIMARY KEY ("id"))` - ) - await queryRunner.query( - `CREATE TABLE "Identity" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "alias" character varying(255) NOT NULL, "roles" text, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), "contactId" uuid, CONSTRAINT "UQ_Alias" UNIQUE ("alias"), CONSTRAINT "PK_Identity_id" PRIMARY KEY ("id"))` - ) - await queryRunner.query(`CREATE TYPE "public"."Connection_type_enum" AS ENUM('OIDC', 'SIOPv2', 'SIOPv2+OpenID4VP')`) - await queryRunner.query( - `CREATE TABLE "Connection" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "type" "public"."Connection_type_enum" NOT NULL, "identityId" uuid, CONSTRAINT "REL_Connection_identityId" UNIQUE ("identityId"), CONSTRAINT "PK_Connection_id" PRIMARY KEY ("id"))` - ) - await queryRunner.query( - `ALTER TABLE "BaseConfigEntity" ADD CONSTRAINT "FK_BaseConfig_connectionId" FOREIGN KEY ("connectionId") REFERENCES "Connection"("id") ON DELETE CASCADE ON UPDATE NO ACTION` - ) - await queryRunner.query( - `ALTER TABLE "CorrelationIdentifier" ADD CONSTRAINT "FK_CorrelationIdentifier_identityId" FOREIGN KEY ("identityId") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION` - ) - await queryRunner.query( - `ALTER TABLE "IdentityMetadata" ADD CONSTRAINT "FK_IdentityMetadata_identityId" FOREIGN KEY ("identityId") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION` - ) - await queryRunner.query( - `ALTER TABLE "Identity" ADD CONSTRAINT "FK_Identity_contactId" FOREIGN KEY ("contactId") REFERENCES "Contact"("id") ON DELETE CASCADE ON UPDATE NO ACTION` - ) - await queryRunner.query( - `ALTER TABLE "Connection" ADD CONSTRAINT "FK_Connection_identityId" FOREIGN KEY ("identityId") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION` - ) + await queryRunner.query(`ALTER TABLE "CorrelationIdentifier" DROP CONSTRAINT "FK_CorrelationIdentifier_identityId"`) + await queryRunner.query(`ALTER TABLE "IdentityMetadata" DROP CONSTRAINT "FK_IdentityMetadata_identityId"`) + await queryRunner.query(`ALTER TABLE "Identity" DROP CONSTRAINT "FK_Identity_contactId"`) + await queryRunner.query(`ALTER TABLE "Connection" DROP CONSTRAINT "FK_Connection_identityId"`) + await queryRunner.query(`ALTER TABLE "CorrelationIdentifier" RENAME COLUMN "identityId" TO "identity_id"`) + await queryRunner.query(`ALTER TABLE "Connection" RENAME COLUMN "identityId" TO "identity_id"`) + await queryRunner.query(`CREATE TYPE "public"."PartyType_type_enum" AS ENUM('naturalPerson', 'organization')`) + await queryRunner.query(`CREATE TABLE "PartyType" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "type" "public"."PartyType_type_enum" NOT NULL, "name" character varying(255) NOT NULL, "description" character varying(255), "tenant_id" character varying(255) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "UQ_06658931a9c40b5c1f7371210a7" UNIQUE ("name"), CONSTRAINT "PK_cb5d69529212caff17a4a56b65d" PRIMARY KEY ("id"))`) + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_PartyTypeEntity_type_tenantId" ON "PartyType" ("type", "tenant_id")`) + await queryRunner.query(`CREATE TABLE "BaseContact" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), "legal_name" character varying(255), "display_name" character varying(255), "first_name" character varying(255), "middle_name" character varying(255), "last_name" character varying(255), "type" character varying NOT NULL, "party_id" uuid, CONSTRAINT "UQ_b8c8005251433839dfc2babf9f8" UNIQUE ("legal_name"), CONSTRAINT "REL_be0b2a601d6a71b07e2a8a5b61" UNIQUE ("party_id"), CONSTRAINT "PK_49b53d0fabcefd59b204b9b65f6" PRIMARY KEY ("id"))`) + await queryRunner.query(`CREATE INDEX "IDX_d265e69d45aa55a9e197f5e626" ON "BaseContact" ("type")`) + await queryRunner.query(`CREATE TABLE "PartyRelationship" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "left_id" uuid NOT NULL, "right_id" uuid NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_57bc64287935e4546d3c3161df7" PRIMARY KEY ("id"))`) + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_PartyRelationshipEntity_left_right" ON "PartyRelationship" ("left_id", "right_id")`) + await queryRunner.query(`CREATE TABLE "ElectronicAddress" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "type" character varying(255) NOT NULL, "electronic_address" character varying(255) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), "partyId" uuid, CONSTRAINT "PK_4b1c9ab5ad01c105abed06a0a9c" PRIMARY KEY ("id"))`) + await queryRunner.query(`CREATE TABLE "Party" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "uri" character varying(255) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), "party_type_id" uuid NOT NULL, CONSTRAINT "PK_1d61626792eccfcb50ff6f7cda2" PRIMARY KEY ("id"))`) + await queryRunner.query(`CREATE TABLE "BaseConfig" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "identifier" character varying(255), "redirect_url" character varying(255), "session_id" character varying(255), "client_id" character varying(255), "client_secret" character varying(255), "scopes" text, "issuer" character varying(255), "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "type" character varying NOT NULL, "connection_id" uuid, CONSTRAINT "REL_4b10e0398e0bc003b479a21f53" UNIQUE ("connection_id"), CONSTRAINT "PK_71b897e705b414db840e1751679" PRIMARY KEY ("id"))`) + await queryRunner.query(`CREATE INDEX "IDX_5624e2253276217cf609b044b1" ON "BaseConfig" ("type")`) + await queryRunner.query(`ALTER TABLE "Identity" DROP COLUMN "contactId"`) + await queryRunner.query(`ALTER TABLE "Identity" ADD "partyId" uuid`) + await queryRunner.query(`ALTER TABLE "Identity" ALTER COLUMN "roles" SET NOT NULL`) + await queryRunner.query(`ALTER TABLE "CorrelationIdentifier" ADD CONSTRAINT "FK_d98b8f355649e9d090ee2a915ca" FOREIGN KEY ("identity_id") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) + await queryRunner.query(`ALTER TABLE "IdentityMetadata" ADD CONSTRAINT "FK_e22568cc3d201c0131b87186117" FOREIGN KEY ("identityId") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) + await queryRunner.query(`ALTER TABLE "BaseContact" ADD CONSTRAINT "FK_be0b2a601d6a71b07e2a8a5b61e" FOREIGN KEY ("party_id") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) + await queryRunner.query(`ALTER TABLE "PartyRelationship" ADD CONSTRAINT "FK_c3db1bd42ed96c5164b2e6276bf" FOREIGN KEY ("left_id") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) + await queryRunner.query(`ALTER TABLE "PartyRelationship" ADD CONSTRAINT "FK_f366006d2ad5adbe3632277f1c0" FOREIGN KEY ("right_id") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) + await queryRunner.query(`ALTER TABLE "ElectronicAddress" ADD CONSTRAINT "FK_672ac311680d9c366405bb5737c" FOREIGN KEY ("partyId") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) + await queryRunner.query(`ALTER TABLE "Party" ADD CONSTRAINT "FK_d6b87c0830068c6d396a501e3d1" FOREIGN KEY ("party_type_id") REFERENCES "PartyType"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) + await queryRunner.query(`ALTER TABLE "Identity" ADD CONSTRAINT "FK_916e4ef6ee2f24c5c88bdc9dfbb" FOREIGN KEY ("partyId") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) + await queryRunner.query(`ALTER TABLE "Connection" ADD CONSTRAINT "FK_360ccf2d714878339680a197d26" FOREIGN KEY ("identity_id") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) + await queryRunner.query(`ALTER TABLE "BaseConfig" ADD CONSTRAINT "FK_4b10e0398e0bc003b479a21f53e" FOREIGN KEY ("connection_id") REFERENCES "Connection"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + // await queryRunner.query( + // `CREATE TABLE "BaseConfigEntity" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "client_id" character varying(255), "client_secret" character varying(255), "scopes" text, "issuer" character varying(255), "redirect_url" text, "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "identifier" character varying(255), "session_id" character varying(255), "type" character varying NOT NULL, "connectionId" uuid, CONSTRAINT "REL_BaseConfig_connectionId" UNIQUE ("connectionId"), CONSTRAINT "PK_BaseConfigEntity_id" PRIMARY KEY ("id"))` + // ) + // await queryRunner.query(`CREATE INDEX "IDX_BaseConfigEntity_type" ON "BaseConfigEntity" ("type")`) + // await queryRunner.query(`CREATE TYPE "public"."CorrelationIdentifier_type_enum" AS ENUM('did', 'url')`) + // await queryRunner.query( + // `CREATE TABLE "CorrelationIdentifier" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "type" "public"."CorrelationIdentifier_type_enum" NOT NULL, "correlation_id" text NOT NULL, "identityId" uuid, CONSTRAINT "UQ_Correlation_id" UNIQUE ("correlation_id"), CONSTRAINT "REL_CorrelationIdentifier_identityId" UNIQUE ("identityId"), CONSTRAINT "PK_CorrelationIdentifier_id" PRIMARY KEY ("id"))` + // ) + // await queryRunner.query( + // `CREATE TABLE "Contact" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "name" character varying(255) NOT NULL, "alias" character varying(255) NOT NULL, "uri" character varying(255) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "UQ_Name" UNIQUE ("name"), CONSTRAINT "UQ_Alias" UNIQUE ("alias"), CONSTRAINT "PK_Contact_id" PRIMARY KEY ("id"))` + // ) + // await queryRunner.query( + // `CREATE TABLE "IdentityMetadata" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "label" character varying(255) NOT NULL, "value" character varying(255) NOT NULL, "identityId" uuid, CONSTRAINT "PK_IdentityMetadata_id" PRIMARY KEY ("id"))` + // ) + // await queryRunner.query( + // `CREATE TABLE "Identity" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "alias" character varying(255) NOT NULL, "roles" text, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), "contactId" uuid, CONSTRAINT "UQ_Alias" UNIQUE ("alias"), CONSTRAINT "PK_Identity_id" PRIMARY KEY ("id"))` + // ) + // await queryRunner.query(`CREATE TYPE "public"."Connection_type_enum" AS ENUM('OIDC', 'SIOPv2', 'SIOPv2+OpenID4VP')`) + // await queryRunner.query( + // `CREATE TABLE "Connection" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "type" "public"."Connection_type_enum" NOT NULL, "identityId" uuid, CONSTRAINT "REL_Connection_identityId" UNIQUE ("identityId"), CONSTRAINT "PK_Connection_id" PRIMARY KEY ("id"))` + // ) + // await queryRunner.query( + // `ALTER TABLE "BaseConfigEntity" ADD CONSTRAINT "FK_BaseConfig_connectionId" FOREIGN KEY ("connectionId") REFERENCES "Connection"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + // ) + // await queryRunner.query( + // `ALTER TABLE "CorrelationIdentifier" ADD CONSTRAINT "FK_CorrelationIdentifier_identityId" FOREIGN KEY ("identityId") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + // ) + // await queryRunner.query( + // `ALTER TABLE "IdentityMetadata" ADD CONSTRAINT "FK_IdentityMetadata_identityId" FOREIGN KEY ("identityId") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + // ) + // await queryRunner.query( + // `ALTER TABLE "Identity" ADD CONSTRAINT "FK_Identity_contactId" FOREIGN KEY ("contactId") REFERENCES "Contact"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + // ) + // await queryRunner.query( + // `ALTER TABLE "Connection" ADD CONSTRAINT "FK_Connection_identityId" FOREIGN KEY ("identityId") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + // ) } public async down(queryRunner: QueryRunner): Promise { From 8843354156ee673b0fcace682bc585d465a39b92 Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Mon, 4 Sep 2023 14:05:20 +0200 Subject: [PATCH 16/35] DPP-1 postgres migration WIP --- .../src/__tests__/contact.entities.test.ts | 12 ++++---- .../postgres/1690925872592-CreateContacts.ts | 28 +++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/packages/data-store/src/__tests__/contact.entities.test.ts b/packages/data-store/src/__tests__/contact.entities.test.ts index 985d578d8..fb9ab380b 100644 --- a/packages/data-store/src/__tests__/contact.entities.test.ts +++ b/packages/data-store/src/__tests__/contact.entities.test.ts @@ -4,7 +4,7 @@ import { DataSource, import { DataStoreContactEntities, - //DataStoreMigrations + DataStoreMigrations } from '../index' //import { NaturalPersonEntity } from '../entities/contact/NaturalPersonEntity' // import { OrganizationEntity } from '../entities/contact/OrganizationEntity' @@ -105,15 +105,15 @@ describe('Database entities tests', (): void => { port: 5432, // Default PostgreSQL port username: 'postgres', password: 'btencate', - database: 'contacts2-ssi-sdk', + database: 'contacts3-ssi-sdk', migrationsRun: false, - //migrations: DataStoreMigrations, - synchronize: true, //false + migrations: DataStoreMigrations, + synchronize: false, entities: DataStoreContactEntities, }).initialize() - //await dbConnection.runMigrations() - //expect(await dbConnection.showMigrations()).toBeFalsy() + await dbConnection.runMigrations() + expect(await dbConnection.showMigrations()).toBeFalsy() }) afterEach(async (): Promise => { diff --git a/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts b/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts index f99a46512..4615c7ad6 100644 --- a/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts +++ b/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts @@ -104,19 +104,19 @@ export class CreateContacts1690925872592 implements MigrationInterface { } public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "Connection" DROP CONSTRAINT "FK_Connection_identityId"`) - await queryRunner.query(`ALTER TABLE "Identity" DROP CONSTRAINT "FK_Identity_contactId"`) - await queryRunner.query(`ALTER TABLE "IdentityMetadata" DROP CONSTRAINT "FK_IdentityMetadata_identityId"`) - await queryRunner.query(`ALTER TABLE "CorrelationIdentifier" DROP CONSTRAINT "FK_CorrelationIdentifier_identityId"`) - await queryRunner.query(`ALTER TABLE "BaseConfigEntity" DROP CONSTRAINT "FK_BaseConfig_connectionId"`) - await queryRunner.query(`DROP TABLE "Connection"`) - await queryRunner.query(`DROP TYPE "public"."Connection_type_enum"`) - await queryRunner.query(`DROP TABLE "Identity"`) - await queryRunner.query(`DROP TABLE "IdentityMetadata"`) - await queryRunner.query(`DROP TABLE "Contact"`) - await queryRunner.query(`DROP TABLE "CorrelationIdentifier"`) - await queryRunner.query(`DROP TYPE "public"."CorrelationIdentifier_type_enum"`) - await queryRunner.query(`DROP INDEX "public"."IDX_BaseConfigEntity_type"`) - await queryRunner.query(`DROP TABLE "BaseConfigEntity"`) + // await queryRunner.query(`ALTER TABLE "Connection" DROP CONSTRAINT "FK_Connection_identityId"`) + // await queryRunner.query(`ALTER TABLE "Identity" DROP CONSTRAINT "FK_Identity_contactId"`) + // await queryRunner.query(`ALTER TABLE "IdentityMetadata" DROP CONSTRAINT "FK_IdentityMetadata_identityId"`) + // await queryRunner.query(`ALTER TABLE "CorrelationIdentifier" DROP CONSTRAINT "FK_CorrelationIdentifier_identityId"`) + // await queryRunner.query(`ALTER TABLE "BaseConfigEntity" DROP CONSTRAINT "FK_BaseConfig_connectionId"`) + // await queryRunner.query(`DROP TABLE "Connection"`) + // await queryRunner.query(`DROP TYPE "public"."Connection_type_enum"`) + // await queryRunner.query(`DROP TABLE "Identity"`) + // await queryRunner.query(`DROP TABLE "IdentityMetadata"`) + // await queryRunner.query(`DROP TABLE "Contact"`) + // await queryRunner.query(`DROP TABLE "CorrelationIdentifier"`) + // await queryRunner.query(`DROP TYPE "public"."CorrelationIdentifier_type_enum"`) + // await queryRunner.query(`DROP INDEX "public"."IDX_BaseConfigEntity_type"`) + // await queryRunner.query(`DROP TABLE "BaseConfigEntity"`) } } From 8069fe9445ec5e6b8531efb99198284d9eb53fe3 Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Mon, 4 Sep 2023 14:10:52 +0200 Subject: [PATCH 17/35] DPP-1 postgres migration WIP --- .../src/migrations/postgres/1690925872592-CreateContacts.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts b/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts index 4615c7ad6..0ab73368d 100644 --- a/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts +++ b/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts @@ -38,8 +38,8 @@ export class CreateContacts1690925872592 implements MigrationInterface { await queryRunner.query(`ALTER TABLE "BaseConfig" ADD CONSTRAINT "FK_4b10e0398e0bc003b479a21f53e" FOREIGN KEY ("connection_id") REFERENCES "Connection"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) - - + await queryRunner.query(`DROP TABLE "BaseConfigEntity"`) + await queryRunner.query(`DROP TABLE "Contact"`) From deb73c7293512da85ed33608e54178b952913df9 Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Mon, 4 Sep 2023 14:35:49 +0200 Subject: [PATCH 18/35] DPP-1 postgres migration WIP --- packages/data-store/src/__tests__/contact.entities.test.ts | 2 +- .../src/migrations/postgres/1690925872592-CreateContacts.ts | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/data-store/src/__tests__/contact.entities.test.ts b/packages/data-store/src/__tests__/contact.entities.test.ts index fb9ab380b..f68998a5b 100644 --- a/packages/data-store/src/__tests__/contact.entities.test.ts +++ b/packages/data-store/src/__tests__/contact.entities.test.ts @@ -105,7 +105,7 @@ describe('Database entities tests', (): void => { port: 5432, // Default PostgreSQL port username: 'postgres', password: 'btencate', - database: 'contacts3-ssi-sdk', + database: 'contacts4-ssi-sdk', migrationsRun: false, migrations: DataStoreMigrations, diff --git a/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts b/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts index 0ab73368d..729e6395e 100644 --- a/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts +++ b/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts @@ -38,7 +38,11 @@ export class CreateContacts1690925872592 implements MigrationInterface { await queryRunner.query(`ALTER TABLE "BaseConfig" ADD CONSTRAINT "FK_4b10e0398e0bc003b479a21f53e" FOREIGN KEY ("connection_id") REFERENCES "Connection"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) + await queryRunner.query(`INSERT INTO "BaseConfig"("id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id") SELECT "id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id" FROM "BaseConfigEntity"`) await queryRunner.query(`DROP TABLE "BaseConfigEntity"`) + await queryRunner.query(`INSERT INTO "PartyType"(id, type, name, description, tenant_id, created_at, last_updated_at) VALUES ('3875c12e-fdaa-4ef6-a340-c936e054b627', 'organization', 'Sphereon_default_type', 'sphereon_default_organization', '95e09cfc-c974-4174-86aa-7bf1d5251fb4', now(), now())`) + await queryRunner.query(`INSERT INTO "Party"(id, uri, created_at, last_updated_at, party_type_id) SELECT id, uri, created_at, last_updated_at, '3875c12e-fdaa-4ef6-a340-c936e054b627' FROM Contact`) + await queryRunner.query(`INSERT INTO "BaseContact"(id, legal_name, display_name, party_id, created_at, last_updated_at, type) SELECT id, name, alias, id, created_at, last_updated_at, 'Organization' FROM Contact`) await queryRunner.query(`DROP TABLE "Contact"`) From 576bf9bde2f44d432a4efb927e9b6476bb68b0a4 Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Mon, 4 Sep 2023 15:32:48 +0200 Subject: [PATCH 19/35] DPP-1 postgres migration WIP --- .../data-store/src/__tests__/contact.entities.test.ts | 2 +- .../migrations/postgres/1690925872592-CreateContacts.ts | 8 ++++---- .../src/migrations/sqlite/1690925872693-CreateContacts.ts | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/data-store/src/__tests__/contact.entities.test.ts b/packages/data-store/src/__tests__/contact.entities.test.ts index f68998a5b..edd886b6e 100644 --- a/packages/data-store/src/__tests__/contact.entities.test.ts +++ b/packages/data-store/src/__tests__/contact.entities.test.ts @@ -105,7 +105,7 @@ describe('Database entities tests', (): void => { port: 5432, // Default PostgreSQL port username: 'postgres', password: 'btencate', - database: 'contacts4-ssi-sdk', + database: 'contacts5-ssi-sdk', migrationsRun: false, migrations: DataStoreMigrations, diff --git a/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts b/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts index 729e6395e..91b8af3c1 100644 --- a/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts +++ b/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts @@ -38,15 +38,15 @@ export class CreateContacts1690925872592 implements MigrationInterface { await queryRunner.query(`ALTER TABLE "BaseConfig" ADD CONSTRAINT "FK_4b10e0398e0bc003b479a21f53e" FOREIGN KEY ("connection_id") REFERENCES "Connection"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) - await queryRunner.query(`INSERT INTO "BaseConfig"("id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id") SELECT "id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id" FROM "BaseConfigEntity"`) + await queryRunner.query(`INSERT INTO "BaseConfig"("id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id") SELECT "id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connectionId" FROM "BaseConfigEntity"`) await queryRunner.query(`DROP TABLE "BaseConfigEntity"`) await queryRunner.query(`INSERT INTO "PartyType"(id, type, name, description, tenant_id, created_at, last_updated_at) VALUES ('3875c12e-fdaa-4ef6-a340-c936e054b627', 'organization', 'Sphereon_default_type', 'sphereon_default_organization', '95e09cfc-c974-4174-86aa-7bf1d5251fb4', now(), now())`) - await queryRunner.query(`INSERT INTO "Party"(id, uri, created_at, last_updated_at, party_type_id) SELECT id, uri, created_at, last_updated_at, '3875c12e-fdaa-4ef6-a340-c936e054b627' FROM Contact`) - await queryRunner.query(`INSERT INTO "BaseContact"(id, legal_name, display_name, party_id, created_at, last_updated_at, type) SELECT id, name, alias, id, created_at, last_updated_at, 'Organization' FROM Contact`) + await queryRunner.query(`INSERT INTO "Party"(id, uri, created_at, last_updated_at, party_type_id) SELECT id, uri, created_at, last_updated_at, '3875c12e-fdaa-4ef6-a340-c936e054b627' FROM "Contact"`) + await queryRunner.query(`INSERT INTO "BaseContact"(id, legal_name, display_name, party_id, created_at, last_updated_at, type) SELECT id, name, alias, id, created_at, last_updated_at, 'Organization' FROM "Contact"`) await queryRunner.query(`DROP TABLE "Contact"`) - + await queryRunner.query(`ROLLBACK`) diff --git a/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts b/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts index a68dd5322..dea2aab57 100644 --- a/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts +++ b/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts @@ -81,8 +81,8 @@ export class CreateContacts1690925872693 implements MigrationInterface { await queryRunner.query(`INSERT INTO "BaseConfig"("id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id") SELECT "id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id" FROM "BaseConfigEntity"`) await queryRunner.query(`DROP TABLE "BaseConfigEntity"`) await queryRunner.query(`INSERT INTO "PartyType"(id, type, name, description, tenant_id, created_at, last_updated_at) VALUES ('3875c12e-fdaa-4ef6-a340-c936e054b627', 'organization', 'Sphereon_default_type', 'sphereon_default_organization', '95e09cfc-c974-4174-86aa-7bf1d5251fb4', datetime('now'), datetime('now'))`) - await queryRunner.query(`INSERT INTO "Party"(id, uri, created_at, last_updated_at, party_type_id) SELECT id, uri, created_at, last_updated_at, '3875c12e-fdaa-4ef6-a340-c936e054b627' FROM Contact`) - await queryRunner.query(`INSERT INTO "BaseContact"(id, legal_name, display_name, party_id, created_at, last_updated_at, type) SELECT id, name, alias, id, created_at, last_updated_at, 'Organization' FROM Contact`) + await queryRunner.query(`INSERT INTO "Party"(id, uri, created_at, last_updated_at, party_type_id) SELECT id, uri, created_at, last_updated_at, '3875c12e-fdaa-4ef6-a340-c936e054b627' FROM "Contact"`) + await queryRunner.query(`INSERT INTO "BaseContact"(id, legal_name, display_name, party_id, created_at, last_updated_at, type) SELECT id, name, alias, id, created_at, last_updated_at, 'Organization' FROM "Contact"`) await queryRunner.query(`DROP TABLE "Contact"`) From 76dcce21c972d8b7ba051d7cc7e5c61ea319f013 Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Mon, 4 Sep 2023 21:29:57 +0200 Subject: [PATCH 20/35] DPP-1 migration WIP --- .../src/__tests__/contact.entities.test.ts | 2 +- .../postgres/1690925872592-CreateContacts.ts | 65 +------ .../sqlite/1690925872693-CreateContacts.ts | 160 +----------------- 3 files changed, 4 insertions(+), 223 deletions(-) diff --git a/packages/data-store/src/__tests__/contact.entities.test.ts b/packages/data-store/src/__tests__/contact.entities.test.ts index edd886b6e..5785cff83 100644 --- a/packages/data-store/src/__tests__/contact.entities.test.ts +++ b/packages/data-store/src/__tests__/contact.entities.test.ts @@ -105,7 +105,7 @@ describe('Database entities tests', (): void => { port: 5432, // Default PostgreSQL port username: 'postgres', password: 'btencate', - database: 'contacts5-ssi-sdk', + database: 'contacts6-ssi-sdk', migrationsRun: false, migrations: DataStoreMigrations, diff --git a/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts b/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts index 91b8af3c1..a25f3dafb 100644 --- a/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts +++ b/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts @@ -3,8 +3,6 @@ import { MigrationInterface, QueryRunner } from 'typeorm' export class CreateContacts1690925872592 implements MigrationInterface { name = 'CreateContacts1690925872592' - - public async up(queryRunner: QueryRunner): Promise { await queryRunner.query(`ALTER TABLE "CorrelationIdentifier" DROP CONSTRAINT "FK_CorrelationIdentifier_identityId"`) await queryRunner.query(`ALTER TABLE "IdentityMetadata" DROP CONSTRAINT "FK_IdentityMetadata_identityId"`) @@ -37,74 +35,13 @@ export class CreateContacts1690925872592 implements MigrationInterface { await queryRunner.query(`ALTER TABLE "Connection" ADD CONSTRAINT "FK_360ccf2d714878339680a197d26" FOREIGN KEY ("identity_id") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) await queryRunner.query(`ALTER TABLE "BaseConfig" ADD CONSTRAINT "FK_4b10e0398e0bc003b479a21f53e" FOREIGN KEY ("connection_id") REFERENCES "Connection"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) - + // migrate existing data await queryRunner.query(`INSERT INTO "BaseConfig"("id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id") SELECT "id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connectionId" FROM "BaseConfigEntity"`) await queryRunner.query(`DROP TABLE "BaseConfigEntity"`) await queryRunner.query(`INSERT INTO "PartyType"(id, type, name, description, tenant_id, created_at, last_updated_at) VALUES ('3875c12e-fdaa-4ef6-a340-c936e054b627', 'organization', 'Sphereon_default_type', 'sphereon_default_organization', '95e09cfc-c974-4174-86aa-7bf1d5251fb4', now(), now())`) await queryRunner.query(`INSERT INTO "Party"(id, uri, created_at, last_updated_at, party_type_id) SELECT id, uri, created_at, last_updated_at, '3875c12e-fdaa-4ef6-a340-c936e054b627' FROM "Contact"`) await queryRunner.query(`INSERT INTO "BaseContact"(id, legal_name, display_name, party_id, created_at, last_updated_at, type) SELECT id, name, alias, id, created_at, last_updated_at, 'Organization' FROM "Contact"`) await queryRunner.query(`DROP TABLE "Contact"`) - - - await queryRunner.query(`ROLLBACK`) - - - - - - - - - - - - - - - - - - - - - - - // await queryRunner.query( - // `CREATE TABLE "BaseConfigEntity" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "client_id" character varying(255), "client_secret" character varying(255), "scopes" text, "issuer" character varying(255), "redirect_url" text, "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "identifier" character varying(255), "session_id" character varying(255), "type" character varying NOT NULL, "connectionId" uuid, CONSTRAINT "REL_BaseConfig_connectionId" UNIQUE ("connectionId"), CONSTRAINT "PK_BaseConfigEntity_id" PRIMARY KEY ("id"))` - // ) - // await queryRunner.query(`CREATE INDEX "IDX_BaseConfigEntity_type" ON "BaseConfigEntity" ("type")`) - // await queryRunner.query(`CREATE TYPE "public"."CorrelationIdentifier_type_enum" AS ENUM('did', 'url')`) - // await queryRunner.query( - // `CREATE TABLE "CorrelationIdentifier" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "type" "public"."CorrelationIdentifier_type_enum" NOT NULL, "correlation_id" text NOT NULL, "identityId" uuid, CONSTRAINT "UQ_Correlation_id" UNIQUE ("correlation_id"), CONSTRAINT "REL_CorrelationIdentifier_identityId" UNIQUE ("identityId"), CONSTRAINT "PK_CorrelationIdentifier_id" PRIMARY KEY ("id"))` - // ) - // await queryRunner.query( - // `CREATE TABLE "Contact" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "name" character varying(255) NOT NULL, "alias" character varying(255) NOT NULL, "uri" character varying(255) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "UQ_Name" UNIQUE ("name"), CONSTRAINT "UQ_Alias" UNIQUE ("alias"), CONSTRAINT "PK_Contact_id" PRIMARY KEY ("id"))` - // ) - // await queryRunner.query( - // `CREATE TABLE "IdentityMetadata" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "label" character varying(255) NOT NULL, "value" character varying(255) NOT NULL, "identityId" uuid, CONSTRAINT "PK_IdentityMetadata_id" PRIMARY KEY ("id"))` - // ) - // await queryRunner.query( - // `CREATE TABLE "Identity" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "alias" character varying(255) NOT NULL, "roles" text, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), "contactId" uuid, CONSTRAINT "UQ_Alias" UNIQUE ("alias"), CONSTRAINT "PK_Identity_id" PRIMARY KEY ("id"))` - // ) - // await queryRunner.query(`CREATE TYPE "public"."Connection_type_enum" AS ENUM('OIDC', 'SIOPv2', 'SIOPv2+OpenID4VP')`) - // await queryRunner.query( - // `CREATE TABLE "Connection" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "type" "public"."Connection_type_enum" NOT NULL, "identityId" uuid, CONSTRAINT "REL_Connection_identityId" UNIQUE ("identityId"), CONSTRAINT "PK_Connection_id" PRIMARY KEY ("id"))` - // ) - // await queryRunner.query( - // `ALTER TABLE "BaseConfigEntity" ADD CONSTRAINT "FK_BaseConfig_connectionId" FOREIGN KEY ("connectionId") REFERENCES "Connection"("id") ON DELETE CASCADE ON UPDATE NO ACTION` - // ) - // await queryRunner.query( - // `ALTER TABLE "CorrelationIdentifier" ADD CONSTRAINT "FK_CorrelationIdentifier_identityId" FOREIGN KEY ("identityId") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION` - // ) - // await queryRunner.query( - // `ALTER TABLE "IdentityMetadata" ADD CONSTRAINT "FK_IdentityMetadata_identityId" FOREIGN KEY ("identityId") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION` - // ) - // await queryRunner.query( - // `ALTER TABLE "Identity" ADD CONSTRAINT "FK_Identity_contactId" FOREIGN KEY ("contactId") REFERENCES "Contact"("id") ON DELETE CASCADE ON UPDATE NO ACTION` - // ) - // await queryRunner.query( - // `ALTER TABLE "Connection" ADD CONSTRAINT "FK_Connection_identityId" FOREIGN KEY ("identityId") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION` - // ) } public async down(queryRunner: QueryRunner): Promise { diff --git a/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts b/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts index dea2aab57..7c4e8fa89 100644 --- a/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts +++ b/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts @@ -84,165 +84,9 @@ export class CreateContacts1690925872693 implements MigrationInterface { await queryRunner.query(`INSERT INTO "Party"(id, uri, created_at, last_updated_at, party_type_id) SELECT id, uri, created_at, last_updated_at, '3875c12e-fdaa-4ef6-a340-c936e054b627' FROM "Contact"`) await queryRunner.query(`INSERT INTO "BaseContact"(id, legal_name, display_name, party_id, created_at, last_updated_at, type) SELECT id, name, alias, id, created_at, last_updated_at, 'Organization' FROM "Contact"`) await queryRunner.query(`DROP TABLE "Contact"`) + } + public async down(queryRunner: QueryRunner): Promise { - - - // await queryRunner.query(`DROP INDEX "IDX_BaseConfigEntity_type"`) - // await queryRunner.query( - // `CREATE TABLE "temporary_BaseConfigEntity" ("id" varchar PRIMARY KEY NOT NULL, "client_id" varchar(255), "client_secret" varchar(255), "scopes" text, "issuer" varchar(255), "redirect_url" text, "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "identifier" varchar(255), "session_id" varchar(255), "type" varchar NOT NULL, "connectionId" varchar, CONSTRAINT "REL_BaseConfig_connectionId" UNIQUE ("connectionId"))` - // ) - // await queryRunner.query( - // `INSERT INTO "temporary_BaseConfigEntity"("id", "client_id", "client_secret", "scopes", "issuer", "redirect_url", "dangerously_allow_insecure_http_requests", "client_auth_method", "identifier", "session_id", "type", "connectionId") SELECT "id", "client_id", "client_secret", "scopes", "issuer", "redirect_url", "dangerously_allow_insecure_http_requests", "client_auth_method", "identifier", "session_id", "type", "connectionId" FROM "BaseConfigEntity"` - // ) - // await queryRunner.query(`DROP TABLE "BaseConfigEntity"`) - // await queryRunner.query(`ALTER TABLE "temporary_BaseConfigEntity" RENAME TO "BaseConfigEntity"`) - // await queryRunner.query(`CREATE INDEX "IDX_BaseConfigEntity_type" ON "BaseConfigEntity" ("type")`) - // await queryRunner.query( - // `CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identityId" varchar, CONSTRAINT "REL_CorrelationIdentifier_identityId" UNIQUE ("identityId"), CONSTRAINT "UQ_Correlation_id" UNIQUE ("correlation_id"))` - // ) - // await queryRunner.query( - // `INSERT INTO "temporary_CorrelationIdentifier"("id", "type", "correlation_id", "identityId") SELECT "id", "type", "correlation_id", "identityId" FROM "CorrelationIdentifier"` - // ) - // await queryRunner.query(`DROP TABLE "CorrelationIdentifier"`) - // await queryRunner.query(`ALTER TABLE "temporary_CorrelationIdentifier" RENAME TO "CorrelationIdentifier"`) - // await queryRunner.query( - // `CREATE TABLE "temporary_IdentityMetadata" ("id" varchar PRIMARY KEY NOT NULL, "label" varchar(255) NOT NULL, "value" varchar(255) NOT NULL, "identityId" varchar)` - // ) - // await queryRunner.query( - // `INSERT INTO "temporary_IdentityMetadata"("id", "label", "value", "identityId") SELECT "id", "label", "value", "identityId" FROM "IdentityMetadata"` - // ) - // await queryRunner.query(`DROP TABLE "IdentityMetadata"`) - // await queryRunner.query(`ALTER TABLE "temporary_IdentityMetadata" RENAME TO "IdentityMetadata"`) - // await queryRunner.query( - // `CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Alias" UNIQUE ("alias"))` - // ) - // await queryRunner.query( - // `INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"` - // ) - // await queryRunner.query(`DROP TABLE "Identity"`) - // await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) - // await queryRunner.query( - // `CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identityId" varchar, CONSTRAINT "REL_Connection_identityId" UNIQUE ("identityId"))` - // ) - // await queryRunner.query(`INSERT INTO "temporary_Connection"("id", "type", "identityId") SELECT "id", "type", "identityId" FROM "Connection"`) - // await queryRunner.query(`DROP TABLE "Connection"`) - // await queryRunner.query(`ALTER TABLE "temporary_Connection" RENAME TO "Connection"`) - // await queryRunner.query(`DROP INDEX "IDX_BaseConfigEntity_type"`) - // await queryRunner.query( - // `CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Alias" UNIQUE ("alias"))` - // ) - // await queryRunner.query( - // `INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"` - // ) - // await queryRunner.query(`DROP TABLE "Identity"`) - // await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) - // await queryRunner.query( - // `CREATE TABLE "ContactType" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('person','organization') ) NOT NULL, "name" varchar(255) NOT NULL, "description" varchar(255), "tenantId" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "UQ_2229e0d8c1e6817efcc982a6dde" UNIQUE ("name"))` - // ) - // await queryRunner.query(`CREATE UNIQUE INDEX "IDX_1a1fa2aa0a56649427e427a41f" ON "ContactType" ("type", "tenantId")`) - // await queryRunner.query( - // `CREATE TABLE "ContactOwner" ("id" varchar PRIMARY KEY NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "firstName" varchar(255), "middleName" varchar(255), "lastName" varchar(255), "displayName" varchar(255), "legalName" varchar(255), "type" varchar NOT NULL, "contactId" varchar, CONSTRAINT "UQ_9177af8a51a2a0598d3a8c68e1e" UNIQUE ("displayName"), CONSTRAINT "UQ_91bf22d2597ff429ece6ae807aa" UNIQUE ("legalName"), CONSTRAINT "UQ_9177af8a51a2a0598d3a8c68e1e" UNIQUE ("displayName"), CONSTRAINT "REL_26ce21b29da1426fa1198b947e" UNIQUE ("contactId"))` - // ) - // await queryRunner.query(`CREATE INDEX "IDX_e50c368daf85e7ae54585b0f7b" ON "ContactOwner" ("type")`) - // await queryRunner.query( - // `CREATE TABLE "ContactRelationship" ("id" varchar PRIMARY KEY NOT NULL, "leftId" varchar NOT NULL, "rightId" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')))` - // ) - // await queryRunner.query(`CREATE UNIQUE INDEX "IDX_ContactRelationshipEntity_left_right" ON "ContactRelationship" ("leftId", "rightId")`) - // await queryRunner.query( - // `CREATE TABLE "temporary_Contact" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')))` - // ) - // await queryRunner.query( - // `INSERT INTO "temporary_Contact"("id", "uri", "created_at", "last_updated_at") SELECT "id", "uri", "created_at", "last_updated_at" FROM "Contact"` - // ) - // await queryRunner.query(`DROP TABLE "Contact"`) - // await queryRunner.query(`ALTER TABLE "temporary_Contact" RENAME TO "Contact"`) - // await queryRunner.query( - // `CREATE TABLE "temporary_Contact" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactTypeId" varchar NOT NULL)` - // ) - // await queryRunner.query( - // `INSERT INTO "temporary_Contact"("id", "uri", "created_at", "last_updated_at") SELECT "id", "uri", "created_at", "last_updated_at" FROM "Contact"` - // ) - // await queryRunner.query(`DROP TABLE "Contact"`) - // await queryRunner.query(`ALTER TABLE "temporary_Contact" RENAME TO "Contact"`) - // await queryRunner.query( - // `CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Alias" UNIQUE ("alias"))` - // ) - // await queryRunner.query( - // `INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"` - // ) - // await queryRunner.query(`DROP TABLE "Identity"`) - // await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) - // await queryRunner.query(`CREATE INDEX "IDX_228953a09ee91bbac6e28b7345" ON "BaseConfigEntity" ("type")`) - // await queryRunner.query(`DROP INDEX "IDX_228953a09ee91bbac6e28b7345"`) - // await queryRunner.query( - // `CREATE TABLE "temporary_BaseConfigEntity" ("id" varchar PRIMARY KEY NOT NULL, "client_id" varchar(255), "client_secret" varchar(255), "scopes" text, "issuer" varchar(255), "redirect_url" text, "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "identifier" varchar(255), "session_id" varchar(255), "type" varchar NOT NULL, "connectionId" varchar, CONSTRAINT "REL_BaseConfig_connectionId" UNIQUE ("connectionId"), CONSTRAINT "FK_0ab3b33e0a87e1706025e63d8a9" FOREIGN KEY ("connectionId") REFERENCES "Connection" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` - // ) - // await queryRunner.query( - // `INSERT INTO "temporary_BaseConfigEntity"("id", "client_id", "client_secret", "scopes", "issuer", "redirect_url", "dangerously_allow_insecure_http_requests", "client_auth_method", "identifier", "session_id", "type", "connectionId") SELECT "id", "client_id", "client_secret", "scopes", "issuer", "redirect_url", "dangerously_allow_insecure_http_requests", "client_auth_method", "identifier", "session_id", "type", "connectionId" FROM "BaseConfigEntity"` - // ) - // await queryRunner.query(`DROP TABLE "BaseConfigEntity"`) - // await queryRunner.query(`ALTER TABLE "temporary_BaseConfigEntity" RENAME TO "BaseConfigEntity"`) - // await queryRunner.query(`CREATE INDEX "IDX_228953a09ee91bbac6e28b7345" ON "BaseConfigEntity" ("type")`) - // await queryRunner.query( - // `CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identityId" varchar, CONSTRAINT "REL_CorrelationIdentifier_identityId" UNIQUE ("identityId"), CONSTRAINT "UQ_Correlation_id" UNIQUE ("correlation_id"), CONSTRAINT "FK_28945c1d57c5feee1d5d1f54510" FOREIGN KEY ("identityId") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` - // ) - // await queryRunner.query( - // `INSERT INTO "temporary_CorrelationIdentifier"("id", "type", "correlation_id", "identityId") SELECT "id", "type", "correlation_id", "identityId" FROM "CorrelationIdentifier"` - // ) - // await queryRunner.query(`DROP TABLE "CorrelationIdentifier"`) - // await queryRunner.query(`ALTER TABLE "temporary_CorrelationIdentifier" RENAME TO "CorrelationIdentifier"`) - // await queryRunner.query( - // `CREATE TABLE "temporary_IdentityMetadata" ("id" varchar PRIMARY KEY NOT NULL, "label" varchar(255) NOT NULL, "value" varchar(255) NOT NULL, "identityId" varchar, CONSTRAINT "FK_e22568cc3d201c0131b87186117" FOREIGN KEY ("identityId") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` - // ) - // await queryRunner.query( - // `INSERT INTO "temporary_IdentityMetadata"("id", "label", "value", "identityId") SELECT "id", "label", "value", "identityId" FROM "IdentityMetadata"` - // ) - // await queryRunner.query(`DROP TABLE "IdentityMetadata"`) - // await queryRunner.query(`ALTER TABLE "temporary_IdentityMetadata" RENAME TO "IdentityMetadata"`) - // await queryRunner.query(`DROP INDEX "IDX_e50c368daf85e7ae54585b0f7b"`) - // await queryRunner.query( - // `CREATE TABLE "temporary_ContactOwner" ("id" varchar PRIMARY KEY NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "firstName" varchar(255), "middleName" varchar(255), "lastName" varchar(255), "displayName" varchar(255), "legalName" varchar(255), "type" varchar NOT NULL, "contactId" varchar, CONSTRAINT "UQ_9177af8a51a2a0598d3a8c68e1e" UNIQUE ("displayName"), CONSTRAINT "UQ_91bf22d2597ff429ece6ae807aa" UNIQUE ("legalName"), CONSTRAINT "UQ_9177af8a51a2a0598d3a8c68e1e" UNIQUE ("displayName"), CONSTRAINT "REL_26ce21b29da1426fa1198b947e" UNIQUE ("contactId"), CONSTRAINT "FK_26ce21b29da1426fa1198b947e1" FOREIGN KEY ("contactId") REFERENCES "Contact" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` - // ) - // await queryRunner.query( - // `INSERT INTO "temporary_ContactOwner"("id", "created_at", "last_updated_at", "firstName", "middleName", "lastName", "displayName", "legalName", "type", "contactId") SELECT "id", "created_at", "last_updated_at", "firstName", "middleName", "lastName", "displayName", "legalName", "type", "contactId" FROM "ContactOwner"` - // ) - // await queryRunner.query(`DROP TABLE "ContactOwner"`) - // await queryRunner.query(`ALTER TABLE "temporary_ContactOwner" RENAME TO "ContactOwner"`) - // await queryRunner.query(`CREATE INDEX "IDX_e50c368daf85e7ae54585b0f7b" ON "ContactOwner" ("type")`) - // await queryRunner.query(`DROP INDEX "IDX_ContactRelationshipEntity_left_right"`) - // await queryRunner.query( - // `CREATE TABLE "temporary_ContactRelationship" ("id" varchar PRIMARY KEY NOT NULL, "leftId" varchar NOT NULL, "rightId" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "FK_24a7bc0595cc5da51c91e1bee62" FOREIGN KEY ("leftId") REFERENCES "Contact" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "FK_e673c9f78f3c7670a75c0ea7710" FOREIGN KEY ("rightId") REFERENCES "Contact" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` - // ) - // await queryRunner.query( - // `INSERT INTO "temporary_ContactRelationship"("id", "leftId", "rightId", "created_at", "last_updated_at") SELECT "id", "leftId", "rightId", "created_at", "last_updated_at" FROM "ContactRelationship"` - // ) - // await queryRunner.query(`DROP TABLE "ContactRelationship"`) - // await queryRunner.query(`ALTER TABLE "temporary_ContactRelationship" RENAME TO "ContactRelationship"`) - // await queryRunner.query(`CREATE UNIQUE INDEX "IDX_ContactRelationshipEntity_left_right" ON "ContactRelationship" ("leftId", "rightId")`) - // await queryRunner.query( - // `CREATE TABLE "temporary_Contact" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactTypeId" varchar NOT NULL, CONSTRAINT "FK_a992c5cdc48d0bc105d0338f982" FOREIGN KEY ("contactTypeId") REFERENCES "ContactType" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)` - // ) - // await queryRunner.query( - // `INSERT INTO "temporary_Contact"("id", "uri", "created_at", "last_updated_at", "contactTypeId") SELECT "id", "uri", "created_at", "last_updated_at", "contactTypeId" FROM "Contact"` - // ) - // await queryRunner.query(`DROP TABLE "Contact"`) - // await queryRunner.query(`ALTER TABLE "temporary_Contact" RENAME TO "Contact"`) - // await queryRunner.query( - // `CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Alias" UNIQUE ("alias"), CONSTRAINT "FK_70ac2a54e2041b7914613204e3d" FOREIGN KEY ("contactId") REFERENCES "Contact" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` - // ) - // await queryRunner.query( - // `INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"` - // ) - // await queryRunner.query(`DROP TABLE "Identity"`) - // await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) - // await queryRunner.query( - // `CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identityId" varchar, CONSTRAINT "REL_Connection_identityId" UNIQUE ("identityId"), CONSTRAINT "FK_fff3668c112a6863bb8c37519a0" FOREIGN KEY ("identityId") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` - // ) - // await queryRunner.query(`INSERT INTO "temporary_Connection"("id", "type", "identityId") SELECT "id", "type", "identityId" FROM "Connection"`) - // await queryRunner.query(`DROP TABLE "Connection"`) - // await queryRunner.query(`ALTER TABLE "temporary_Connection" RENAME TO "Connection"`) } - - public async down(queryRunner: QueryRunner): Promise {} } From ad889d8b49f298d8b05abd86c2e90ba8914b5d1e Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Mon, 4 Sep 2023 22:30:23 +0200 Subject: [PATCH 21/35] DPP-1 sqlite migration constraint names --- .../src/__tests__/contact.entities.test.ts | 54 +++++++++---------- .../contact/PartyRelationshipEntity.ts | 2 +- .../src/entities/contact/PartyTypeEntity.ts | 2 +- .../sqlite/1690925872693-CreateContacts.ts | 54 +++++++++---------- 4 files changed, 56 insertions(+), 56 deletions(-) diff --git a/packages/data-store/src/__tests__/contact.entities.test.ts b/packages/data-store/src/__tests__/contact.entities.test.ts index 5785cff83..742c51c46 100644 --- a/packages/data-store/src/__tests__/contact.entities.test.ts +++ b/packages/data-store/src/__tests__/contact.entities.test.ts @@ -78,44 +78,44 @@ describe('Database entities tests', (): void => { // }) // sqlite - // beforeEach(async (): Promise => { - // dbConnection = await new DataSource({ - // type: 'sqlite', - // database: './database.sqlite', - // logging: 'all', - // migrationsRun: false, - // migrations: DataStoreMigrations, - // synchronize: false, //false - // entities: DataStoreContactEntities, - // }).initialize() - // await dbConnection.runMigrations() - // expect(await dbConnection.showMigrations()).toBeFalsy() - // }) - - // postgres beforeEach(async (): Promise => { dbConnection = await new DataSource({ - // type: 'sqlite', - // database: ':memory:', + type: 'sqlite', + database: './database.sqlite', logging: 'all', - - - type: 'postgres', - host: 'localhost', // or '127.0.0.1' - port: 5432, // Default PostgreSQL port - username: 'postgres', - password: 'btencate', - database: 'contacts6-ssi-sdk', - migrationsRun: false, migrations: DataStoreMigrations, - synchronize: false, + synchronize: false, //false entities: DataStoreContactEntities, }).initialize() await dbConnection.runMigrations() expect(await dbConnection.showMigrations()).toBeFalsy() }) + // postgres + // beforeEach(async (): Promise => { + // dbConnection = await new DataSource({ + // // type: 'sqlite', + // // database: ':memory:', + // logging: 'all', + // + // + // type: 'postgres', + // host: 'localhost', // or '127.0.0.1' + // port: 5432, // Default PostgreSQL port + // username: 'postgres', + // password: 'btencate', + // database: 'contacts7-ssi-sdk', + // + // migrationsRun: false, + // migrations: DataStoreMigrations, + // synchronize: false, + // entities: DataStoreContactEntities, + // }).initialize() + // await dbConnection.runMigrations() + // expect(await dbConnection.showMigrations()).toBeFalsy() + // }) + afterEach(async (): Promise => { await (await dbConnection).destroy() }) diff --git a/packages/data-store/src/entities/contact/PartyRelationshipEntity.ts b/packages/data-store/src/entities/contact/PartyRelationshipEntity.ts index d50946fe0..7807b2058 100644 --- a/packages/data-store/src/entities/contact/PartyRelationshipEntity.ts +++ b/packages/data-store/src/entities/contact/PartyRelationshipEntity.ts @@ -13,7 +13,7 @@ import { import { PartyEntity } from './PartyEntity' @Entity('PartyRelationship') -@Index('IDX_PartyRelationshipEntity_left_right', ['left', 'right'], { unique: true }) +@Index('IDX_PartyRelationship_left_right', ['left', 'right'], { unique: true }) export class PartyRelationshipEntity { @PrimaryGeneratedColumn('uuid') id!: string diff --git a/packages/data-store/src/entities/contact/PartyTypeEntity.ts b/packages/data-store/src/entities/contact/PartyTypeEntity.ts index 3de7c9b79..058ea2085 100644 --- a/packages/data-store/src/entities/contact/PartyTypeEntity.ts +++ b/packages/data-store/src/entities/contact/PartyTypeEntity.ts @@ -6,7 +6,7 @@ import { IsNonEmptyStringConstraint } from '../validators' import { getConstraint } from '../../utils/ValidatorUtils' @Entity('PartyType') -@Index('IDX_PartyTypeEntity_type_tenantId', ['type', 'tenantId'], { unique: true }) // TODO use name for migrations +@Index('IDX_PartyType_type_tenant_id', ['type', 'tenantId'], { unique: true }) // TODO use name for migrations export class PartyTypeEntity { @PrimaryGeneratedColumn('uuid') id!: string diff --git a/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts b/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts index 7c4e8fa89..ff2476c16 100644 --- a/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts +++ b/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts @@ -4,78 +4,78 @@ export class CreateContacts1690925872693 implements MigrationInterface { name = 'CreateContacts1690925872693' public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identityId" varchar, CONSTRAINT "REL_28945c1d57c5feee1d5d1f5451" UNIQUE ("identityId"), CONSTRAINT "UQ_775cbf83c248bc73c42aef55664" UNIQUE ("correlation_id"))`) + await queryRunner.query(`CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identityId" varchar, CONSTRAINT "REL_CorrelationIdentifier_identityId" UNIQUE ("identityId"), CONSTRAINT "UQ_CorrelationIdentifier_correlation_id" UNIQUE ("correlation_id"))`) await queryRunner.query(`INSERT INTO "temporary_CorrelationIdentifier"("id", "type", "correlation_id", "identityId") SELECT "id", "type", "correlation_id", "identityId" FROM "CorrelationIdentifier"`) await queryRunner.query(`DROP TABLE "CorrelationIdentifier"`) await queryRunner.query(`ALTER TABLE "temporary_CorrelationIdentifier" RENAME TO "CorrelationIdentifier"`) - await queryRunner.query(`CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_cbeaf6b68b6dbc9eb8dc3503499" UNIQUE ("alias"))`) + await queryRunner.query(`CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Identity_alias" UNIQUE ("alias"))`) await queryRunner.query(`INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"`) await queryRunner.query(`DROP TABLE "Identity"`) await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) - await queryRunner.query(`CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identityId" varchar, CONSTRAINT "REL_fff3668c112a6863bb8c37519a" UNIQUE ("identityId"))`) + await queryRunner.query(`CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identityId" varchar, CONSTRAINT "REL_Connection_identityId" UNIQUE ("identityId"))`) await queryRunner.query(`INSERT INTO "temporary_Connection"("id", "type", "identityId") SELECT "id", "type", "identityId" FROM "Connection"`) await queryRunner.query(`DROP TABLE "Connection"`) await queryRunner.query(`ALTER TABLE "temporary_Connection" RENAME TO "Connection"`) - await queryRunner.query(`CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identity_id" varchar, CONSTRAINT "REL_28945c1d57c5feee1d5d1f5451" UNIQUE ("identity_id"), CONSTRAINT "UQ_775cbf83c248bc73c42aef55664" UNIQUE ("correlation_id"))`) + await queryRunner.query(`CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identity_id" varchar, CONSTRAINT "REL_CorrelationIdentifier_identityId" UNIQUE ("identity_id"), CONSTRAINT "UQ_CorrelationIdentifier_correlation_id" UNIQUE ("correlation_id"))`) await queryRunner.query(`INSERT INTO "temporary_CorrelationIdentifier"("id", "type", "correlation_id", "identity_id") SELECT "id", "type", "correlation_id", "identityId" FROM "CorrelationIdentifier"`) await queryRunner.query(`DROP TABLE "CorrelationIdentifier"`) await queryRunner.query(`ALTER TABLE "temporary_CorrelationIdentifier" RENAME TO "CorrelationIdentifier"`) - await queryRunner.query(`CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "partyId" varchar, CONSTRAINT "UQ_cbeaf6b68b6dbc9eb8dc3503499" UNIQUE ("alias"))`) + await queryRunner.query(`CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "partyId" varchar, CONSTRAINT "UQ_Identity_alias" UNIQUE ("alias"))`) await queryRunner.query(`INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "partyId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"`) await queryRunner.query(`DROP TABLE "Identity"`) await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) - await queryRunner.query(`CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identity_id" varchar, CONSTRAINT "REL_fff3668c112a6863bb8c37519a" UNIQUE ("identity_id"))`) + await queryRunner.query(`CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identity_id" varchar, CONSTRAINT "REL_Connection_identityId" UNIQUE ("identity_id"))`) await queryRunner.query(`INSERT INTO "temporary_Connection"("id", "type", "identity_id") SELECT "id", "type", "identityId" FROM "Connection"`) await queryRunner.query(`DROP TABLE "Connection"`) await queryRunner.query(`ALTER TABLE "temporary_Connection" RENAME TO "Connection"`) - await queryRunner.query(`CREATE TABLE "PartyType" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('naturalPerson','organization') ) NOT NULL, "name" varchar(255) NOT NULL, "description" varchar(255), "tenant_id" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "UQ_06658931a9c40b5c1f7371210a7" UNIQUE ("name"))`) - await queryRunner.query(`CREATE UNIQUE INDEX "IDX_PartyTypeEntity_type_tenantId" ON "PartyType" ("type", "tenant_id")`) - await queryRunner.query(`CREATE TABLE "BaseContact" ("id" varchar PRIMARY KEY NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "legal_name" varchar(255), "display_name" varchar(255), "first_name" varchar(255), "middle_name" varchar(255), "last_name" varchar(255), "type" varchar NOT NULL, "party_id" varchar, CONSTRAINT "UQ_b8c8005251433839dfc2babf9f8" UNIQUE ("legal_name"), CONSTRAINT "REL_be0b2a601d6a71b07e2a8a5b61" UNIQUE ("party_id"))`) - await queryRunner.query(`CREATE INDEX "IDX_d265e69d45aa55a9e197f5e626" ON "BaseContact" ("type")`) + await queryRunner.query(`CREATE TABLE "PartyType" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('naturalPerson','organization') ) NOT NULL, "name" varchar(255) NOT NULL, "description" varchar(255), "tenant_id" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "UQ_PartyType_name" UNIQUE ("name"))`) + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_PartyType_type_tenant_id" ON "PartyType" ("type", "tenant_id")`) + await queryRunner.query(`CREATE TABLE "BaseContact" ("id" varchar PRIMARY KEY NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "legal_name" varchar(255), "display_name" varchar(255), "first_name" varchar(255), "middle_name" varchar(255), "last_name" varchar(255), "type" varchar NOT NULL, "party_id" varchar, CONSTRAINT "UQ_BaseContact_legal_name" UNIQUE ("legal_name"), CONSTRAINT "REL_BaseContact_party_id" UNIQUE ("party_id"))`) + await queryRunner.query(`CREATE INDEX "IDX_BaseContact_type" ON "BaseContact" ("type")`) await queryRunner.query(`CREATE TABLE "PartyRelationship" ("id" varchar PRIMARY KEY NOT NULL, "left_id" varchar NOT NULL, "right_id" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')))`) - await queryRunner.query(`CREATE UNIQUE INDEX "IDX_PartyRelationshipEntity_left_right" ON "PartyRelationship" ("left_id", "right_id")`) + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_PartyRelationship_left_right" ON "PartyRelationship" ("left_id", "right_id")`) await queryRunner.query(`CREATE TABLE "ElectronicAddress" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar(255) NOT NULL, "electronic_address" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "partyId" varchar)`) await queryRunner.query(`CREATE TABLE "Party" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "party_type_id" varchar NOT NULL)`) - await queryRunner.query(`CREATE TABLE "BaseConfig" ("id" varchar PRIMARY KEY NOT NULL, "identifier" varchar(255), "redirect_url" varchar(255), "session_id" varchar(255), "client_id" varchar(255), "client_secret" varchar(255), "scopes" text, "issuer" varchar(255), "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "type" varchar NOT NULL, "connection_id" varchar, CONSTRAINT "REL_4b10e0398e0bc003b479a21f53" UNIQUE ("connection_id"))`) - await queryRunner.query(`CREATE INDEX "IDX_5624e2253276217cf609b044b1" ON "BaseConfig" ("type")`) - await queryRunner.query(`CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identity_id" varchar, CONSTRAINT "REL_28945c1d57c5feee1d5d1f5451" UNIQUE ("identity_id"), CONSTRAINT "UQ_775cbf83c248bc73c42aef55664" UNIQUE ("correlation_id"), CONSTRAINT "FK_d98b8f355649e9d090ee2a915ca" FOREIGN KEY ("identity_id") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) + await queryRunner.query(`CREATE TABLE "BaseConfig" ("id" varchar PRIMARY KEY NOT NULL, "identifier" varchar(255), "redirect_url" varchar(255), "session_id" varchar(255), "client_id" varchar(255), "client_secret" varchar(255), "scopes" text, "issuer" varchar(255), "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "type" varchar NOT NULL, "connection_id" varchar, CONSTRAINT "REL_BaseConfig_connection_id" UNIQUE ("connection_id"))`) + await queryRunner.query(`CREATE INDEX "IDX_BaseConfig_type" ON "BaseConfig" ("type")`) + await queryRunner.query(`CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identity_id" varchar, CONSTRAINT "REL_CorrelationIdentifier_identity_id" UNIQUE ("identity_id"), CONSTRAINT "UQ_CorrelationIdentifier_correlation_id" UNIQUE ("correlation_id"), CONSTRAINT "FK_CorrelationIdentifier_identity_id" FOREIGN KEY ("identity_id") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) await queryRunner.query(`INSERT INTO "temporary_CorrelationIdentifier"("id", "type", "correlation_id", "identity_id") SELECT "id", "type", "correlation_id", "identity_id" FROM "CorrelationIdentifier"`) await queryRunner.query(`DROP TABLE "CorrelationIdentifier"`) await queryRunner.query(`ALTER TABLE "temporary_CorrelationIdentifier" RENAME TO "CorrelationIdentifier"`) - await queryRunner.query(`DROP INDEX "IDX_d265e69d45aa55a9e197f5e626"`) - await queryRunner.query(`CREATE TABLE "temporary_BaseContact" ("id" varchar PRIMARY KEY NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "legal_name" varchar(255), "display_name" varchar(255), "first_name" varchar(255), "middle_name" varchar(255), "last_name" varchar(255), "type" varchar NOT NULL, "party_id" varchar, CONSTRAINT "UQ_b8c8005251433839dfc2babf9f8" UNIQUE ("legal_name"), CONSTRAINT "REL_be0b2a601d6a71b07e2a8a5b61" UNIQUE ("party_id"), CONSTRAINT "FK_be0b2a601d6a71b07e2a8a5b61e" FOREIGN KEY ("party_id") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) + await queryRunner.query(`DROP INDEX "IDX_BaseContact_type"`) + await queryRunner.query(`CREATE TABLE "temporary_BaseContact" ("id" varchar PRIMARY KEY NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "legal_name" varchar(255), "display_name" varchar(255), "first_name" varchar(255), "middle_name" varchar(255), "last_name" varchar(255), "type" varchar NOT NULL, "party_id" varchar, CONSTRAINT "UQ_BaseContact_legal_name" UNIQUE ("legal_name"), CONSTRAINT "REL_BaseContact_party_id" UNIQUE ("party_id"), CONSTRAINT "FK_BaseContact_party_id" FOREIGN KEY ("party_id") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) await queryRunner.query(`INSERT INTO "temporary_BaseContact"("id", "created_at", "last_updated_at", "legal_name", "display_name", "first_name", "middle_name", "last_name", "type", "party_id") SELECT "id", "created_at", "last_updated_at", "legal_name", "display_name", "first_name", "middle_name", "last_name", "type", "party_id" FROM "BaseContact"`) await queryRunner.query(`DROP TABLE "BaseContact"`) await queryRunner.query(`ALTER TABLE "temporary_BaseContact" RENAME TO "BaseContact"`) - await queryRunner.query(`CREATE INDEX "IDX_d265e69d45aa55a9e197f5e626" ON "BaseContact" ("type")`) - await queryRunner.query(`DROP INDEX "IDX_PartyRelationshipEntity_left_right"`) - await queryRunner.query(`CREATE TABLE "temporary_PartyRelationship" ("id" varchar PRIMARY KEY NOT NULL, "left_id" varchar NOT NULL, "right_id" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "FK_c3db1bd42ed96c5164b2e6276bf" FOREIGN KEY ("left_id") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "FK_f366006d2ad5adbe3632277f1c0" FOREIGN KEY ("right_id") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) + await queryRunner.query(`CREATE INDEX "IDX_BaseContact_type" ON "BaseContact" ("type")`) + await queryRunner.query(`DROP INDEX "IDX_PartyRelationship_left_right"`) + await queryRunner.query(`CREATE TABLE "temporary_PartyRelationship" ("id" varchar PRIMARY KEY NOT NULL, "left_id" varchar NOT NULL, "right_id" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "FK_PartyRelationship_left_id" FOREIGN KEY ("left_id") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "FK_PartyRelationship_right_id" FOREIGN KEY ("right_id") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) await queryRunner.query(`INSERT INTO "temporary_PartyRelationship"("id", "left_id", "right_id", "created_at", "last_updated_at") SELECT "id", "left_id", "right_id", "created_at", "last_updated_at" FROM "PartyRelationship"`) await queryRunner.query(`DROP TABLE "PartyRelationship"`) await queryRunner.query(`ALTER TABLE "temporary_PartyRelationship" RENAME TO "PartyRelationship"`) - await queryRunner.query(`CREATE UNIQUE INDEX "IDX_PartyRelationshipEntity_left_right" ON "PartyRelationship" ("left_id", "right_id")`) - await queryRunner.query(`CREATE TABLE "temporary_ElectronicAddress" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar(255) NOT NULL, "electronic_address" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "partyId" varchar, CONSTRAINT "FK_672ac311680d9c366405bb5737c" FOREIGN KEY ("partyId") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_PartyRelationship_left_right" ON "PartyRelationship" ("left_id", "right_id")`) + await queryRunner.query(`CREATE TABLE "temporary_ElectronicAddress" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar(255) NOT NULL, "electronic_address" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "partyId" varchar, CONSTRAINT "FK_ElectronicAddress_partyId" FOREIGN KEY ("partyId") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) await queryRunner.query(`INSERT INTO "temporary_ElectronicAddress"("id", "type", "electronic_address", "created_at", "last_updated_at", "partyId") SELECT "id", "type", "electronic_address", "created_at", "last_updated_at", "partyId" FROM "ElectronicAddress"`) await queryRunner.query(`DROP TABLE "ElectronicAddress"`) await queryRunner.query(`ALTER TABLE "temporary_ElectronicAddress" RENAME TO "ElectronicAddress"`) - await queryRunner.query(`CREATE TABLE "temporary_Party" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "party_type_id" varchar NOT NULL, CONSTRAINT "FK_d6b87c0830068c6d396a501e3d1" FOREIGN KEY ("party_type_id") REFERENCES "PartyType" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`) + await queryRunner.query(`CREATE TABLE "temporary_Party" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "party_type_id" varchar NOT NULL, CONSTRAINT "FK_Party_party_type_id" FOREIGN KEY ("party_type_id") REFERENCES "PartyType" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`) await queryRunner.query(`INSERT INTO "temporary_Party"("id", "uri", "created_at", "last_updated_at", "party_type_id") SELECT "id", "uri", "created_at", "last_updated_at", "party_type_id" FROM "Party"`) await queryRunner.query(`DROP TABLE "Party"`) await queryRunner.query(`ALTER TABLE "temporary_Party" RENAME TO "Party"`) - await queryRunner.query(`CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "partyId" varchar, CONSTRAINT "UQ_cbeaf6b68b6dbc9eb8dc3503499" UNIQUE ("alias"), CONSTRAINT "FK_916e4ef6ee2f24c5c88bdc9dfbb" FOREIGN KEY ("partyId") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) + await queryRunner.query(`CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "partyId" varchar, CONSTRAINT "UQ_Identity_alias" UNIQUE ("alias"), CONSTRAINT "FK_Identity_partyId" FOREIGN KEY ("partyId") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) await queryRunner.query(`INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "partyId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "partyId" FROM "Identity"`) await queryRunner.query(`DROP TABLE "Identity"`) await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) - await queryRunner.query(`CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identity_id" varchar, CONSTRAINT "REL_fff3668c112a6863bb8c37519a" UNIQUE ("identity_id"), CONSTRAINT "FK_360ccf2d714878339680a197d26" FOREIGN KEY ("identity_id") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) + await queryRunner.query(`CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identity_id" varchar, CONSTRAINT "REL_Connection_identity_id" UNIQUE ("identity_id"), CONSTRAINT "FK_Connection_identity_id" FOREIGN KEY ("identity_id") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) await queryRunner.query(`INSERT INTO "temporary_Connection"("id", "type", "identity_id") SELECT "id", "type", "identity_id" FROM "Connection"`) await queryRunner.query(`DROP TABLE "Connection"`) await queryRunner.query(`ALTER TABLE "temporary_Connection" RENAME TO "Connection"`) - await queryRunner.query(`DROP INDEX "IDX_5624e2253276217cf609b044b1"`) - await queryRunner.query(`CREATE TABLE "temporary_BaseConfig" ("id" varchar PRIMARY KEY NOT NULL, "identifier" varchar(255), "redirect_url" varchar(255), "session_id" varchar(255), "client_id" varchar(255), "client_secret" varchar(255), "scopes" text, "issuer" varchar(255), "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "type" varchar NOT NULL, "connection_id" varchar, CONSTRAINT "REL_4b10e0398e0bc003b479a21f53" UNIQUE ("connection_id"), CONSTRAINT "FK_4b10e0398e0bc003b479a21f53e" FOREIGN KEY ("connection_id") REFERENCES "Connection" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) + await queryRunner.query(`DROP INDEX "IDX_BaseConfig_type"`) + await queryRunner.query(`CREATE TABLE "temporary_BaseConfig" ("id" varchar PRIMARY KEY NOT NULL, "identifier" varchar(255), "redirect_url" varchar(255), "session_id" varchar(255), "client_id" varchar(255), "client_secret" varchar(255), "scopes" text, "issuer" varchar(255), "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "type" varchar NOT NULL, "connection_id" varchar, CONSTRAINT "REL_BaseConfig_connection_id" UNIQUE ("connection_id"), CONSTRAINT "FK_BaseConfig_connection_id" FOREIGN KEY ("connection_id") REFERENCES "Connection" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) await queryRunner.query(`INSERT INTO "temporary_BaseConfig"("id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id") SELECT "id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id" FROM "BaseConfig"`) await queryRunner.query(`DROP TABLE "BaseConfig"`) await queryRunner.query(`ALTER TABLE "temporary_BaseConfig" RENAME TO "BaseConfig"`) - await queryRunner.query(`CREATE INDEX "IDX_5624e2253276217cf609b044b1" ON "BaseConfig" ("type")`) + await queryRunner.query(`CREATE INDEX "IDX_BaseConfig_type" ON "BaseConfig" ("type")`) // migrate existing data await queryRunner.query(`INSERT INTO "BaseConfig"("id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id") SELECT "id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id" FROM "BaseConfigEntity"`) From f52c2ec8985122cb559f640610c5e4c2069ec90b Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Mon, 4 Sep 2023 23:27:17 +0200 Subject: [PATCH 22/35] DPP-1 postgres migration constraint names --- .../postgres/1690925872592-CreateContacts.ts | 58 ++++++++----------- .../sqlite/1690925872693-CreateContacts.ts | 3 +- 2 files changed, 26 insertions(+), 35 deletions(-) diff --git a/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts b/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts index a25f3dafb..83fd4302b 100644 --- a/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts +++ b/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts @@ -11,31 +11,33 @@ export class CreateContacts1690925872592 implements MigrationInterface { await queryRunner.query(`ALTER TABLE "CorrelationIdentifier" RENAME COLUMN "identityId" TO "identity_id"`) await queryRunner.query(`ALTER TABLE "Connection" RENAME COLUMN "identityId" TO "identity_id"`) await queryRunner.query(`CREATE TYPE "public"."PartyType_type_enum" AS ENUM('naturalPerson', 'organization')`) - await queryRunner.query(`CREATE TABLE "PartyType" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "type" "public"."PartyType_type_enum" NOT NULL, "name" character varying(255) NOT NULL, "description" character varying(255), "tenant_id" character varying(255) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "UQ_06658931a9c40b5c1f7371210a7" UNIQUE ("name"), CONSTRAINT "PK_cb5d69529212caff17a4a56b65d" PRIMARY KEY ("id"))`) - await queryRunner.query(`CREATE UNIQUE INDEX "IDX_PartyTypeEntity_type_tenantId" ON "PartyType" ("type", "tenant_id")`) - await queryRunner.query(`CREATE TABLE "BaseContact" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), "legal_name" character varying(255), "display_name" character varying(255), "first_name" character varying(255), "middle_name" character varying(255), "last_name" character varying(255), "type" character varying NOT NULL, "party_id" uuid, CONSTRAINT "UQ_b8c8005251433839dfc2babf9f8" UNIQUE ("legal_name"), CONSTRAINT "REL_be0b2a601d6a71b07e2a8a5b61" UNIQUE ("party_id"), CONSTRAINT "PK_49b53d0fabcefd59b204b9b65f6" PRIMARY KEY ("id"))`) - await queryRunner.query(`CREATE INDEX "IDX_d265e69d45aa55a9e197f5e626" ON "BaseContact" ("type")`) - await queryRunner.query(`CREATE TABLE "PartyRelationship" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "left_id" uuid NOT NULL, "right_id" uuid NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_57bc64287935e4546d3c3161df7" PRIMARY KEY ("id"))`) - await queryRunner.query(`CREATE UNIQUE INDEX "IDX_PartyRelationshipEntity_left_right" ON "PartyRelationship" ("left_id", "right_id")`) - await queryRunner.query(`CREATE TABLE "ElectronicAddress" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "type" character varying(255) NOT NULL, "electronic_address" character varying(255) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), "partyId" uuid, CONSTRAINT "PK_4b1c9ab5ad01c105abed06a0a9c" PRIMARY KEY ("id"))`) - await queryRunner.query(`CREATE TABLE "Party" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "uri" character varying(255) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), "party_type_id" uuid NOT NULL, CONSTRAINT "PK_1d61626792eccfcb50ff6f7cda2" PRIMARY KEY ("id"))`) - await queryRunner.query(`CREATE TABLE "BaseConfig" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "identifier" character varying(255), "redirect_url" character varying(255), "session_id" character varying(255), "client_id" character varying(255), "client_secret" character varying(255), "scopes" text, "issuer" character varying(255), "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "type" character varying NOT NULL, "connection_id" uuid, CONSTRAINT "REL_4b10e0398e0bc003b479a21f53" UNIQUE ("connection_id"), CONSTRAINT "PK_71b897e705b414db840e1751679" PRIMARY KEY ("id"))`) - await queryRunner.query(`CREATE INDEX "IDX_5624e2253276217cf609b044b1" ON "BaseConfig" ("type")`) + await queryRunner.query(`CREATE TABLE "PartyType" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "type" "public"."PartyType_type_enum" NOT NULL, "name" character varying(255) NOT NULL, "description" character varying(255), "tenant_id" character varying(255) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "UQ_PartyType_name" UNIQUE ("name"), CONSTRAINT "PK_PartyType_id" PRIMARY KEY ("id"))`) + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_PartyType_type_tenant_id" ON "PartyType" ("type", "tenant_id")`) + await queryRunner.query(`CREATE TABLE "BaseContact" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), "legal_name" character varying(255), "display_name" character varying(255), "first_name" character varying(255), "middle_name" character varying(255), "last_name" character varying(255), "type" character varying NOT NULL, "party_id" uuid, CONSTRAINT "UQ_BaseContact_legal_name" UNIQUE ("legal_name"), CONSTRAINT "REL_BaseContact_party_id" UNIQUE ("party_id"), CONSTRAINT "PK_BaseContact_id" PRIMARY KEY ("id"))`) + await queryRunner.query(`CREATE INDEX "IDX_BaseContact_type" ON "BaseContact" ("type")`) + await queryRunner.query(`CREATE TABLE "PartyRelationship" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "left_id" uuid NOT NULL, "right_id" uuid NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_PartyRelationship_id" PRIMARY KEY ("id"))`) + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_PartyRelationship_left_right" ON "PartyRelationship" ("left_id", "right_id")`) + await queryRunner.query(`CREATE TABLE "ElectronicAddress" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "type" character varying(255) NOT NULL, "electronic_address" character varying(255) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), "partyId" uuid, CONSTRAINT "PK_ElectronicAddress_id" PRIMARY KEY ("id"))`) + await queryRunner.query(`CREATE TABLE "Party" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "uri" character varying(255) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), "party_type_id" uuid NOT NULL, CONSTRAINT "PK_Party_id" PRIMARY KEY ("id"))`) + await queryRunner.query(`CREATE TABLE "BaseConfig" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "identifier" character varying(255), "redirect_url" character varying(255), "session_id" character varying(255), "client_id" character varying(255), "client_secret" character varying(255), "scopes" text, "issuer" character varying(255), "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "type" character varying NOT NULL, "connection_id" uuid, CONSTRAINT "REL_BaseConfig_connection_id" UNIQUE ("connection_id"), CONSTRAINT "PK_BaseConfig_id" PRIMARY KEY ("id"))`) + await queryRunner.query(`CREATE INDEX "IDX_BaseConfig_type" ON "BaseConfig" ("type")`) await queryRunner.query(`ALTER TABLE "Identity" DROP COLUMN "contactId"`) await queryRunner.query(`ALTER TABLE "Identity" ADD "partyId" uuid`) await queryRunner.query(`ALTER TABLE "Identity" ALTER COLUMN "roles" SET NOT NULL`) - await queryRunner.query(`ALTER TABLE "CorrelationIdentifier" ADD CONSTRAINT "FK_d98b8f355649e9d090ee2a915ca" FOREIGN KEY ("identity_id") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) - await queryRunner.query(`ALTER TABLE "IdentityMetadata" ADD CONSTRAINT "FK_e22568cc3d201c0131b87186117" FOREIGN KEY ("identityId") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) - await queryRunner.query(`ALTER TABLE "BaseContact" ADD CONSTRAINT "FK_be0b2a601d6a71b07e2a8a5b61e" FOREIGN KEY ("party_id") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) - await queryRunner.query(`ALTER TABLE "PartyRelationship" ADD CONSTRAINT "FK_c3db1bd42ed96c5164b2e6276bf" FOREIGN KEY ("left_id") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) - await queryRunner.query(`ALTER TABLE "PartyRelationship" ADD CONSTRAINT "FK_f366006d2ad5adbe3632277f1c0" FOREIGN KEY ("right_id") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) - await queryRunner.query(`ALTER TABLE "ElectronicAddress" ADD CONSTRAINT "FK_672ac311680d9c366405bb5737c" FOREIGN KEY ("partyId") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) - await queryRunner.query(`ALTER TABLE "Party" ADD CONSTRAINT "FK_d6b87c0830068c6d396a501e3d1" FOREIGN KEY ("party_type_id") REFERENCES "PartyType"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) - await queryRunner.query(`ALTER TABLE "Identity" ADD CONSTRAINT "FK_916e4ef6ee2f24c5c88bdc9dfbb" FOREIGN KEY ("partyId") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) - await queryRunner.query(`ALTER TABLE "Connection" ADD CONSTRAINT "FK_360ccf2d714878339680a197d26" FOREIGN KEY ("identity_id") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) - await queryRunner.query(`ALTER TABLE "BaseConfig" ADD CONSTRAINT "FK_4b10e0398e0bc003b479a21f53e" FOREIGN KEY ("connection_id") REFERENCES "Connection"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) + await queryRunner.query(`ALTER TABLE "CorrelationIdentifier" ADD CONSTRAINT "FK_CorrelationIdentifier_identity_id" FOREIGN KEY ("identity_id") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) + await queryRunner.query(`ALTER TABLE "IdentityMetadata" ADD CONSTRAINT "FK_IdentityMetadata_identityId" FOREIGN KEY ("identityId") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) + await queryRunner.query(`ALTER TABLE "BaseContact" ADD CONSTRAINT "FK_BaseContact_party_id" FOREIGN KEY ("party_id") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) + await queryRunner.query(`ALTER TABLE "PartyRelationship" ADD CONSTRAINT "FK_PartyRelationship_left_id" FOREIGN KEY ("left_id") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) + await queryRunner.query(`ALTER TABLE "PartyRelationship" ADD CONSTRAINT "FK_PartyRelationship_right_id" FOREIGN KEY ("right_id") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) + await queryRunner.query(`ALTER TABLE "ElectronicAddress" ADD CONSTRAINT "FK_ElectronicAddress_partyId" FOREIGN KEY ("partyId") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) + await queryRunner.query(`ALTER TABLE "Party" ADD CONSTRAINT "FK_Party_party_type_id" FOREIGN KEY ("party_type_id") REFERENCES "PartyType"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) + await queryRunner.query(`ALTER TABLE "Identity" ADD CONSTRAINT "FK_partyId" FOREIGN KEY ("partyId") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) + await queryRunner.query(`ALTER TABLE "Connection" ADD CONSTRAINT "FK_Connection_identity_id" FOREIGN KEY ("identity_id") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) + await queryRunner.query(`ALTER TABLE "BaseConfig" ADD CONSTRAINT "FK_BaseConfig_connection_id" FOREIGN KEY ("connection_id") REFERENCES "Connection"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) // migrate existing data + await queryRunner.query(`ALTER TABLE "CorrelationIdentifier" RENAME CONSTRAINT "UQ_Correlation_id" TO "UQ_CorrelationIdentifier_correlation_id"`) + await queryRunner.query(`ALTER TABLE "Identity" RENAME CONSTRAINT "UQ_Identity_Alias" TO "UQ_Identity_alias"`) await queryRunner.query(`INSERT INTO "BaseConfig"("id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id") SELECT "id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connectionId" FROM "BaseConfigEntity"`) await queryRunner.query(`DROP TABLE "BaseConfigEntity"`) await queryRunner.query(`INSERT INTO "PartyType"(id, type, name, description, tenant_id, created_at, last_updated_at) VALUES ('3875c12e-fdaa-4ef6-a340-c936e054b627', 'organization', 'Sphereon_default_type', 'sphereon_default_organization', '95e09cfc-c974-4174-86aa-7bf1d5251fb4', now(), now())`) @@ -45,19 +47,7 @@ export class CreateContacts1690925872592 implements MigrationInterface { } public async down(queryRunner: QueryRunner): Promise { - // await queryRunner.query(`ALTER TABLE "Connection" DROP CONSTRAINT "FK_Connection_identityId"`) - // await queryRunner.query(`ALTER TABLE "Identity" DROP CONSTRAINT "FK_Identity_contactId"`) - // await queryRunner.query(`ALTER TABLE "IdentityMetadata" DROP CONSTRAINT "FK_IdentityMetadata_identityId"`) - // await queryRunner.query(`ALTER TABLE "CorrelationIdentifier" DROP CONSTRAINT "FK_CorrelationIdentifier_identityId"`) - // await queryRunner.query(`ALTER TABLE "BaseConfigEntity" DROP CONSTRAINT "FK_BaseConfig_connectionId"`) - // await queryRunner.query(`DROP TABLE "Connection"`) - // await queryRunner.query(`DROP TYPE "public"."Connection_type_enum"`) - // await queryRunner.query(`DROP TABLE "Identity"`) - // await queryRunner.query(`DROP TABLE "IdentityMetadata"`) - // await queryRunner.query(`DROP TABLE "Contact"`) - // await queryRunner.query(`DROP TABLE "CorrelationIdentifier"`) - // await queryRunner.query(`DROP TYPE "public"."CorrelationIdentifier_type_enum"`) - // await queryRunner.query(`DROP INDEX "public"."IDX_BaseConfigEntity_type"`) - // await queryRunner.query(`DROP TABLE "BaseConfigEntity"`) + // TODO DPP-27 implement downgrade + return Promise.reject(Error(`Downgrade is not yet implemented for ${this.name}`)) } } diff --git a/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts b/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts index ff2476c16..155724f8b 100644 --- a/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts +++ b/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts @@ -87,6 +87,7 @@ export class CreateContacts1690925872693 implements MigrationInterface { } public async down(queryRunner: QueryRunner): Promise { - + // TODO DPP-27 implement downgrade + return Promise.reject(Error(`Downgrade is not yet implemented for ${this.name}`)) } } From 49fccef59c7798db3a2977560174e9b4c5044425 Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Mon, 4 Sep 2023 23:43:36 +0200 Subject: [PATCH 23/35] DPP-1 postgres identity relation migration fix --- .../src/migrations/postgres/1690925872592-CreateContacts.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts b/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts index 83fd4302b..23de7b22a 100644 --- a/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts +++ b/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts @@ -21,8 +21,10 @@ export class CreateContacts1690925872592 implements MigrationInterface { await queryRunner.query(`CREATE TABLE "Party" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "uri" character varying(255) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), "party_type_id" uuid NOT NULL, CONSTRAINT "PK_Party_id" PRIMARY KEY ("id"))`) await queryRunner.query(`CREATE TABLE "BaseConfig" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "identifier" character varying(255), "redirect_url" character varying(255), "session_id" character varying(255), "client_id" character varying(255), "client_secret" character varying(255), "scopes" text, "issuer" character varying(255), "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "type" character varying NOT NULL, "connection_id" uuid, CONSTRAINT "REL_BaseConfig_connection_id" UNIQUE ("connection_id"), CONSTRAINT "PK_BaseConfig_id" PRIMARY KEY ("id"))`) await queryRunner.query(`CREATE INDEX "IDX_BaseConfig_type" ON "BaseConfig" ("type")`) - await queryRunner.query(`ALTER TABLE "Identity" DROP COLUMN "contactId"`) - await queryRunner.query(`ALTER TABLE "Identity" ADD "partyId" uuid`) + // await queryRunner.query(`ALTER TABLE "Identity" DROP COLUMN "contactId"`) // TODO we need rename this column + // await queryRunner.query(`ALTER TABLE "Identity" ADD "partyId" uuid`) + await queryRunner.query(`ALTER TABLE "Identity" RENAME COLUMN "contactId" TO "partyId"`) + await queryRunner.query(`ALTER TABLE "Identity" ALTER COLUMN "roles" SET NOT NULL`) await queryRunner.query(`ALTER TABLE "CorrelationIdentifier" ADD CONSTRAINT "FK_CorrelationIdentifier_identity_id" FOREIGN KEY ("identity_id") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) await queryRunner.query(`ALTER TABLE "IdentityMetadata" ADD CONSTRAINT "FK_IdentityMetadata_identityId" FOREIGN KEY ("identityId") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) From 60decd8ff358611b6afe3070389cd6c5b28e195b Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Tue, 5 Sep 2023 11:29:18 +0200 Subject: [PATCH 24/35] DPP-1 migration nameing fix --- .../src/migrations/postgres/1690925872592-CreateContacts.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts b/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts index 23de7b22a..dbd74b480 100644 --- a/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts +++ b/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts @@ -33,7 +33,7 @@ export class CreateContacts1690925872592 implements MigrationInterface { await queryRunner.query(`ALTER TABLE "PartyRelationship" ADD CONSTRAINT "FK_PartyRelationship_right_id" FOREIGN KEY ("right_id") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) await queryRunner.query(`ALTER TABLE "ElectronicAddress" ADD CONSTRAINT "FK_ElectronicAddress_partyId" FOREIGN KEY ("partyId") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) await queryRunner.query(`ALTER TABLE "Party" ADD CONSTRAINT "FK_Party_party_type_id" FOREIGN KEY ("party_type_id") REFERENCES "PartyType"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) - await queryRunner.query(`ALTER TABLE "Identity" ADD CONSTRAINT "FK_partyId" FOREIGN KEY ("partyId") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) + await queryRunner.query(`ALTER TABLE "Identity" ADD CONSTRAINT "FK_Identity_partyId" FOREIGN KEY ("partyId") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) await queryRunner.query(`ALTER TABLE "Connection" ADD CONSTRAINT "FK_Connection_identity_id" FOREIGN KEY ("identity_id") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) await queryRunner.query(`ALTER TABLE "BaseConfig" ADD CONSTRAINT "FK_BaseConfig_connection_id" FOREIGN KEY ("connection_id") REFERENCES "Connection"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) From aa38fc1b51d5a9e876a72f4afaac2f4bbe544c8d Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Tue, 5 Sep 2023 11:36:37 +0200 Subject: [PATCH 25/35] DPP-1 test cleanup --- .../src/__tests__/contact.entities.test.ts | 4300 ++++++++--------- 1 file changed, 2121 insertions(+), 2179 deletions(-) diff --git a/packages/data-store/src/__tests__/contact.entities.test.ts b/packages/data-store/src/__tests__/contact.entities.test.ts index 742c51c46..99d6c101e 100644 --- a/packages/data-store/src/__tests__/contact.entities.test.ts +++ b/packages/data-store/src/__tests__/contact.entities.test.ts @@ -1,325 +1,267 @@ -import { DataSource, - // FindOptionsWhere -} from 'typeorm' +import { DataSource, FindOptionsWhere} from 'typeorm' -import { - DataStoreContactEntities, - DataStoreMigrations -} from '../index' -//import { NaturalPersonEntity } from '../entities/contact/NaturalPersonEntity' -// import { OrganizationEntity } from '../entities/contact/OrganizationEntity' -// import { PartyRelationshipEntity } from '../entities/contact/PartyRelationshipEntity' -// import { PartyTypeEntity } from '../entities/contact/PartyTypeEntity' +import { DataStoreContactEntities, DataStoreMigrations } from '../index' +import { NaturalPersonEntity } from '../entities/contact/NaturalPersonEntity' +import { OrganizationEntity } from '../entities/contact/OrganizationEntity' +import { PartyRelationshipEntity } from '../entities/contact/PartyRelationshipEntity' +import { PartyTypeEntity } from '../entities/contact/PartyTypeEntity' import { PartyEntity } from '../entities/contact/PartyEntity' -// import { IdentityEntity } from '../entities/contact/IdentityEntity' -// import { OpenIdConfigEntity } from '../entities/contact/OpenIdConfigEntity' -// import { DidAuthConfigEntity } from '../entities/contact/DidAuthConfigEntity' -// import { ConnectionEntity } from '../entities/contact/ConnectionEntity' -// import { CorrelationIdentifierEntity } from '../entities/contact/CorrelationIdentifierEntity' -// import { IdentityMetadataItemEntity } from '../entities/contact/IdentityMetadataItemEntity' -// import { BaseContactEntity } from '../entities/contact/BaseContactEntity' +import { IdentityEntity } from '../entities/contact/IdentityEntity' +import { OpenIdConfigEntity } from '../entities/contact/OpenIdConfigEntity' +import { DidAuthConfigEntity } from '../entities/contact/DidAuthConfigEntity' +import { ConnectionEntity } from '../entities/contact/ConnectionEntity' +import { CorrelationIdentifierEntity } from '../entities/contact/CorrelationIdentifierEntity' +import { IdentityMetadataItemEntity } from '../entities/contact/IdentityMetadataItemEntity' +import { BaseContactEntity } from '../entities/contact/BaseContactEntity' import { NonPersistedParty, PartyTypeEnum, - //NaturalPerson, - // Organization, - // IdentityRoleEnum, - // CorrelationIdentifierEnum, - // ConnectionTypeEnum, - // NonPersistedPartyType, - // NonPersistedOrganization, - // NonPersistedNaturalPerson, - // NonPersistedConnection, - // NonPersistedIdentity, - // NonPersistedDidAuthConfig, - // NonPersistedOpenIdConfig, + NaturalPerson, + Organization, + IdentityRoleEnum, + CorrelationIdentifierEnum, + ConnectionTypeEnum, + NonPersistedPartyType, + NonPersistedOrganization, + NonPersistedNaturalPerson, + NonPersistedConnection, + NonPersistedIdentity, + NonPersistedDidAuthConfig, + NonPersistedOpenIdConfig, } from '../types' import { - // connectionEntityFrom, - // didAuthConfigEntityFrom, - // identityEntityFrom, - // naturalPersonEntityFrom, - // openIdConfigEntityFrom, - // organizationEntityFrom, + connectionEntityFrom, + didAuthConfigEntityFrom, + identityEntityFrom, + naturalPersonEntityFrom, + openIdConfigEntityFrom, + organizationEntityFrom, partyEntityFrom, - // partyRelationshipEntityFrom, - // partyTypeEntityFrom, + partyRelationshipEntityFrom, + partyTypeEntityFrom, } from '../utils/contact/MappingUtils' describe('Database entities tests', (): void => { let dbConnection: DataSource - // beforeEach(async (): Promise => { - // dbConnection = await new DataSource({ - // type: 'sqlite', - // database: ':memory:', - // logging: 'all', - // migrationsRun: false, - // // migrations: DataStoreMigrations, - // synchronize: true, //false - // entities: DataStoreContactEntities, - // }).initialize() - // // await dbConnection.runMigrations() - // // expect(await dbConnection.showMigrations()).toBeFalsy() - // }) - - // beforeEach(async (): Promise => { - // dbConnection = await new DataSource({ - // type: 'sqlite', - // database: './database.sqlite', - // logging: 'all', - // migrationsRun: false, - // // migrations: DataStoreMigrations, - // synchronize: true, //false - // entities: DataStoreContactEntities, - // }).initialize() - // // await dbConnection.runMigrations() - // // expect(await dbConnection.showMigrations()).toBeFalsy() - // }) - - // sqlite beforeEach(async (): Promise => { dbConnection = await new DataSource({ type: 'sqlite', - database: './database.sqlite', + database: ':memory:', logging: 'all', migrationsRun: false, migrations: DataStoreMigrations, - synchronize: false, //false + synchronize: false, entities: DataStoreContactEntities, }).initialize() await dbConnection.runMigrations() expect(await dbConnection.showMigrations()).toBeFalsy() }) - // postgres - // beforeEach(async (): Promise => { - // dbConnection = await new DataSource({ - // // type: 'sqlite', - // // database: ':memory:', - // logging: 'all', - // - // - // type: 'postgres', - // host: 'localhost', // or '127.0.0.1' - // port: 5432, // Default PostgreSQL port - // username: 'postgres', - // password: 'btencate', - // database: 'contacts7-ssi-sdk', - // - // migrationsRun: false, - // migrations: DataStoreMigrations, - // synchronize: false, - // entities: DataStoreContactEntities, - // }).initialize() - // await dbConnection.runMigrations() - // expect(await dbConnection.showMigrations()).toBeFalsy() - // }) - afterEach(async (): Promise => { await (await dbConnection).destroy() }) - // it('Should save person party to database', async (): Promise => { - // const party: NonPersistedParty = { - // uri: 'example.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contact: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const partyEntity: PartyEntity = partyEntityFrom(party) - // await dbConnection.getRepository(PartyEntity).save(partyEntity, { - // transaction: true, - // }) - // - // const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - // where: { id: partyEntity.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.identities?.length).toEqual(0) - // expect(fromDb?.uri).toEqual(party.uri) - // expect(fromDb?.partyType).toBeDefined() - // expect(fromDb?.partyType.type).toEqual(party.partyType.type) - // expect(fromDb?.partyType.tenantId).toEqual(party.partyType.tenantId) - // expect(fromDb?.partyType.name).toEqual(party.partyType.name) - // expect(fromDb?.contact).toBeDefined() - // expect((fromDb?.contact).firstName).toEqual((party.contact).firstName) - // expect((fromDb?.contact).middleName).toEqual((party.contact).middleName) - // expect((fromDb?.contact).lastName).toEqual((party.contact).lastName) - // expect((fromDb?.contact).displayName).toEqual((party.contact).displayName) - // }) - - // it('Should save organization party to database', async (): Promise => { - // const party: NonPersistedParty = { - // uri: 'example.com', - // partyType: { - // type: PartyTypeEnum.ORGANIZATION, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contact: { - // legalName: 'example_legal_name', - // displayName: 'example_display_name', - // }, - // } - // - // const partyEntity: PartyEntity = partyEntityFrom(party) - // await dbConnection.getRepository(PartyEntity).save(partyEntity, { - // transaction: true, - // }) - // - // const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - // where: { id: partyEntity.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.identities?.length).toEqual(0) - // expect(fromDb?.uri).toEqual(party.uri) - // expect(fromDb?.partyType).toBeDefined() - // expect(fromDb?.partyType.type).toEqual(party.partyType.type) - // expect(fromDb?.partyType.tenantId).toEqual(party.partyType.tenantId) - // expect(fromDb?.partyType.name).toEqual(party.partyType.name) - // expect(fromDb?.contact).toBeDefined() - // expect((fromDb?.contact).legalName).toEqual((party.contact).legalName) - // expect((fromDb?.contact).displayName).toEqual((party.contact).displayName) - // }) - // - // it('Should result in party relationship for the owner side only', async (): Promise => { - // const party1: NonPersistedParty = { - // uri: 'example1.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name1', - // }, - // contact: { - // firstName: 'example_first_name1', - // middleName: 'example_middle_name1', - // lastName: 'example_last_name1', - // displayName: 'example_display_name1', - // }, - // } - // - // const partyEntity1: PartyEntity = partyEntityFrom(party1) - // const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { - // transaction: true, - // }) - // - // const party2: NonPersistedParty = { - // uri: 'example2.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - // name: 'example_name2', - // }, - // contact: { - // firstName: 'example_first_name2', - // middleName: 'example_middle_name2', - // lastName: 'example_last_name2', - // displayName: 'example_display_name2', - // }, - // } - // - // const partyEntity2: PartyEntity = partyEntityFrom(party2) - // const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { - // transaction: true, - // }) - // - // const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ - // leftId: savedParty1.id, - // rightId: savedParty2.id, - // }) - // - // await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { - // transaction: true, - // }) - // - // const fromDb1: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - // where: { id: savedParty1.id }, - // }) - // - // const fromDb2: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - // where: { id: savedParty2.id }, - // }) - // - // expect(fromDb1).toBeDefined() - // expect(fromDb1?.relationships.length).toEqual(1) - // expect(fromDb2).toBeDefined() - // expect(fromDb2?.relationships.length).toEqual(0) - // }) - // - // it('should throw error when saving person party with blank first name', async (): Promise => { - // const party: NonPersistedParty = { - // uri: 'example.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contact: { - // firstName: '', - // middleName: 'example_middle_name1', - // lastName: 'example_last_name1', - // displayName: 'example_display_name1', - // }, - // } - // - // const partyEntity: PartyEntity = partyEntityFrom(party) - // - // await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank first names are not allowed') - // }) - // - // it('should throw error when saving person party with blank middle name', async (): Promise => { - // const party: NonPersistedParty = { - // uri: 'example.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contact: { - // firstName: 'example_first_name', - // middleName: '', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const partyEntity: PartyEntity = partyEntityFrom(party) - // - // await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank middle names are not allowed') - // }) - // - // it('should throw error when saving person party with blank last name', async (): Promise => { - // const party: NonPersistedParty = { - // uri: 'example.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contact: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: '', - // displayName: 'example_display_name', - // }, - // } - // - // const partyEntity: PartyEntity = partyEntityFrom(party) - // - // await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank last names are not allowed') - // }) + it('Should save person party to database', async (): Promise => { + const party: NonPersistedParty = { + uri: 'example.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contact: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const partyEntity: PartyEntity = partyEntityFrom(party) + await dbConnection.getRepository(PartyEntity).save(partyEntity, { + transaction: true, + }) + + const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: partyEntity.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.identities?.length).toEqual(0) + expect(fromDb?.uri).toEqual(party.uri) + expect(fromDb?.partyType).toBeDefined() + expect(fromDb?.partyType.type).toEqual(party.partyType.type) + expect(fromDb?.partyType.tenantId).toEqual(party.partyType.tenantId) + expect(fromDb?.partyType.name).toEqual(party.partyType.name) + expect(fromDb?.contact).toBeDefined() + expect((fromDb?.contact).firstName).toEqual((party.contact).firstName) + expect((fromDb?.contact).middleName).toEqual((party.contact).middleName) + expect((fromDb?.contact).lastName).toEqual((party.contact).lastName) + expect((fromDb?.contact).displayName).toEqual((party.contact).displayName) + }) + + it('Should save organization party to database', async (): Promise => { + const party: NonPersistedParty = { + uri: 'example.com', + partyType: { + type: PartyTypeEnum.ORGANIZATION, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contact: { + legalName: 'example_legal_name', + displayName: 'example_display_name', + }, + } + + const partyEntity: PartyEntity = partyEntityFrom(party) + await dbConnection.getRepository(PartyEntity).save(partyEntity, { + transaction: true, + }) + + const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: partyEntity.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.identities?.length).toEqual(0) + expect(fromDb?.uri).toEqual(party.uri) + expect(fromDb?.partyType).toBeDefined() + expect(fromDb?.partyType.type).toEqual(party.partyType.type) + expect(fromDb?.partyType.tenantId).toEqual(party.partyType.tenantId) + expect(fromDb?.partyType.name).toEqual(party.partyType.name) + expect(fromDb?.contact).toBeDefined() + expect((fromDb?.contact).legalName).toEqual((party.contact).legalName) + expect((fromDb?.contact).displayName).toEqual((party.contact).displayName) + }) + + it('Should result in party relationship for the owner side only', async (): Promise => { + const party1: NonPersistedParty = { + uri: 'example1.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contact: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const partyEntity1: PartyEntity = partyEntityFrom(party1) + const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { + transaction: true, + }) + + const party2: NonPersistedParty = { + uri: 'example2.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contact: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + + const partyEntity2: PartyEntity = partyEntityFrom(party2) + const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { + transaction: true, + }) + + const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ + leftId: savedParty1.id, + rightId: savedParty2.id, + }) + + await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { + transaction: true, + }) + + const fromDb1: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: savedParty1.id }, + }) + + const fromDb2: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: savedParty2.id }, + }) + + expect(fromDb1).toBeDefined() + expect(fromDb1?.relationships.length).toEqual(1) + expect(fromDb2).toBeDefined() + expect(fromDb2?.relationships.length).toEqual(0) + }) + + it('should throw error when saving person party with blank first name', async (): Promise => { + const party: NonPersistedParty = { + uri: 'example.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contact: { + firstName: '', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const partyEntity: PartyEntity = partyEntityFrom(party) + + await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank first names are not allowed') + }) + + it('should throw error when saving person party with blank middle name', async (): Promise => { + const party: NonPersistedParty = { + uri: 'example.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contact: { + firstName: 'example_first_name', + middleName: '', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const partyEntity: PartyEntity = partyEntityFrom(party) + + await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank middle names are not allowed') + }) + + it('should throw error when saving person party with blank last name', async (): Promise => { + const party: NonPersistedParty = { + uri: 'example.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contact: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: '', + displayName: 'example_display_name', + }, + } + + const partyEntity: PartyEntity = partyEntityFrom(party) + + await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank last names are not allowed') + }) it('should throw error when saving person party with blank display name', async (): Promise => { const party: NonPersistedParty = { @@ -342,1890 +284,1890 @@ describe('Database entities tests', (): void => { await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank display names are not allowed') }) - // it('should throw error when saving organization party with blank legal name', async (): Promise => { - // const party: NonPersistedParty = { - // uri: 'example.com', - // partyType: { - // type: PartyTypeEnum.ORGANIZATION, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contact: { - // legalName: '', - // displayName: 'example_legal_name', - // }, - // } - // - // const partyEntity: PartyEntity = partyEntityFrom(party) - // - // await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank legal names are not allowed') - // }) - // - // it('should throw error when saving organization party with blank display name', async (): Promise => { - // const party: NonPersistedParty = { - // uri: 'example.com', - // partyType: { - // type: PartyTypeEnum.ORGANIZATION, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contact: { - // legalName: 'example_first_name', - // displayName: '', - // }, - // } - // - // const partyEntity: PartyEntity = partyEntityFrom(party) - // - // await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank display names are not allowed') - // }) - // - // it('should throw error when saving party with blank party type name', async (): Promise => { - // const party: NonPersistedParty = { - // uri: 'example.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: '', - // }, - // contact: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const partyEntity: PartyEntity = partyEntityFrom(party) - // - // await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank names are not allowed') - // }) - // - // it('should throw error when saving party with blank party type description', async (): Promise => { - // const party: NonPersistedParty = { - // uri: 'example.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // description: '', - // }, - // contact: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const partyEntity: PartyEntity = partyEntityFrom(party) - // - // await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank descriptions are not allowed') - // }) - // - // it('should throw error when saving party with blank party type tenant id', async (): Promise => { - // const party: NonPersistedParty = { - // uri: 'example.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '', - // name: 'example_name', - // }, - // contact: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const partyEntity: PartyEntity = partyEntityFrom(party) - // - // await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError("Blank tenant id's are not allowed") - // }) - // - // it('Should enforce unique alias for an identity', async (): Promise => { - // const alias = 'non_unique_alias' - // const identity1: NonPersistedIdentity = { - // alias, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId: 'unique_correlationId1', - // }, - // } - // const identity1Entity: IdentityEntity = identityEntityFrom(identity1) - // await dbConnection.getRepository(IdentityEntity).save(identity1Entity) - // - // const identity2: NonPersistedIdentity = { - // alias: alias, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId: 'unique_correlationId2', - // }, - // } - // const identity2Entity: IdentityEntity = identityEntityFrom(identity2) - // await expect(dbConnection.getRepository(IdentityEntity).save(identity2Entity)).rejects.toThrowError( - // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: Identity.alias' - // ) - // }) - // - // it('Should enforce unique correlationId for a identity', async (): Promise => { - // const correlationId = 'non_unique_correlationId' - // const identity1: NonPersistedIdentity = { - // alias: 'unique_alias1', - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId, - // }, - // } - // const identity1Entity: IdentityEntity = identityEntityFrom(identity1) - // await dbConnection.getRepository(IdentityEntity).save(identity1Entity) - // - // const identity2: NonPersistedIdentity = { - // alias: 'unique_alias2', - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId, - // }, - // } - // const identity2Entity: IdentityEntity = identityEntityFrom(identity2) - // await expect(dbConnection.getRepository(IdentityEntity).save(identity2Entity)).rejects.toThrowError( - // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: CorrelationIdentifier.correlation_id' - // ) - // }) - // - // it('Should save identity to database', async (): Promise => { - // const correlationId = 'example_did' - // const identity: NonPersistedIdentity = { - // alias: correlationId, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId, - // }, - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // - // await dbConnection.getRepository(IdentityEntity).save(identityEntity) - // - // const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ - // where: { - // identifier: { - // correlationId, - // }, - // }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.connection).toBeNull() - // expect(fromDb?.identifier).toBeDefined() - // expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) - // expect(fromDb?.identifier.type).toEqual(identity.identifier.type) - // }) - // - // it('should throw error when saving identity with blank alias', async (): Promise => { - // const identity: NonPersistedIdentity = { - // alias: '', - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId: 'example_did', - // }, - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // - // await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank aliases are not allowed') - // }) - // - // it('should throw error when saving identity with blank correlation id', async (): Promise => { - // const identity: NonPersistedIdentity = { - // alias: 'example_did', - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId: '', - // }, - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // - // await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank correlation ids are not allowed') - // }) - // - // it('should throw error when saving identity with blank metadata label', async (): Promise => { - // const correlationId = 'example_did' - // const identity: NonPersistedIdentity = { - // alias: correlationId, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId, - // }, - // metadata: [ - // { - // label: '', - // value: 'example_value', - // }, - // ], - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // - // await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank metadata labels are not allowed') - // }) - // - // it('should throw error when saving identity with blank metadata value', async (): Promise => { - // const correlationId = 'example_did' - // const identity: NonPersistedIdentity = { - // alias: correlationId, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId, - // }, - // metadata: [ - // { - // label: 'example_label', - // value: '', - // }, - // ], - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // - // await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank metadata values are not allowed') - // }) - // - // it('Should save identity with openid connection to database', async (): Promise => { - // const correlationId = 'example.com' - // const identity: NonPersistedIdentity = { - // alias: correlationId, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.URL, - // correlationId, - // }, - // connection: { - // type: ConnectionTypeEnum.OPENID_CONNECT, - // config: { - // clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', - // clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', - // scopes: ['auth'], - // issuer: 'https://example.com/app-test', - // redirectUrl: 'app:/callback', - // dangerouslyAllowInsecureHttpRequests: true, - // clientAuthMethod: 'post', - // }, - // }, - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // - // await dbConnection.getRepository(IdentityEntity).save(identityEntity) - // - // const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ - // where: { - // identifier: { - // correlationId, - // }, - // }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.connection).toBeDefined() - // expect(fromDb?.identifier).toBeDefined() - // expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) - // expect(fromDb?.identifier.type).toEqual(identity.identifier.type) - // expect(fromDb?.connection?.type).toEqual(identity.connection?.type) - // expect(fromDb?.connection?.config).toBeDefined() - // expect((fromDb?.connection?.config).clientId).toEqual((identity.connection?.config).clientId) - // }) - // - // it('Should save identity with didauth connection to database', async (): Promise => { - // const correlationId = 'example.com' - // const identity: NonPersistedIdentity = { - // alias: correlationId, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.URL, - // correlationId, - // }, - // connection: { - // type: ConnectionTypeEnum.SIOPv2, - // config: { - // identifier: { - // did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - // provider: 'test_provider', - // keys: [], - // services: [], - // }, - // redirectUrl: 'https://example.com', - // stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', - // sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - // }, - // }, - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // - // await dbConnection.getRepository(IdentityEntity).save(identityEntity) - // - // const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ - // where: { - // identifier: { - // correlationId, - // }, - // }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.connection).toBeDefined() - // expect(fromDb?.identifier).toBeDefined() - // expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) - // expect(fromDb?.identifier.type).toEqual(identity.identifier.type) - // expect(fromDb?.connection?.type).toEqual(identity.connection?.type) - // expect(fromDb?.connection?.config).toBeDefined() - // expect((fromDb?.connection?.config).identifier).toEqual( - // (identity.connection?.config).identifier.did - // ) - // }) - // - // it('Should save connection with openid config to database', async (): Promise => { - // const connection: NonPersistedConnection = { - // type: ConnectionTypeEnum.OPENID_CONNECT, - // config: { - // clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', - // clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', - // scopes: ['auth'], - // issuer: 'https://example.com/app-test', - // redirectUrl: 'app:/callback', - // dangerouslyAllowInsecureHttpRequests: true, - // clientAuthMethod: 'post', - // }, - // } - // const connectionEntity: ConnectionEntity = connectionEntityFrom(connection) - // await dbConnection.getRepository(ConnectionEntity).save(connectionEntity, { - // transaction: true, - // }) - // - // const fromDb: ConnectionEntity | null = await dbConnection.getRepository(ConnectionEntity).findOne({ - // where: { type: connection.type }, - // }) - // - // expect(fromDb).toBeDefined() - // - // const fromDbConfig: OpenIdConfigEntity | null = await dbConnection.getRepository(OpenIdConfigEntity).findOne({ - // where: { id: fromDb?.id }, - // }) - // - // expect(fromDbConfig).toBeDefined() - // expect(fromDb?.type).toEqual(connection.type) - // expect(fromDb?.config).toBeDefined() - // expect((fromDb?.config).clientId).toEqual((connection.config).clientId) - // }) - // - // it('Should save connection with didauth config to database', async (): Promise => { - // const connection: NonPersistedConnection = { - // type: ConnectionTypeEnum.SIOPv2, - // config: { - // identifier: { - // did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - // provider: 'test_provider', - // keys: [], - // services: [], - // }, - // redirectUrl: 'https://example.com', - // stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', - // sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - // }, - // } - // const connectionEntity: ConnectionEntity = connectionEntityFrom(connection) - // await dbConnection.getRepository(ConnectionEntity).save(connectionEntity, { - // transaction: true, - // }) - // - // const fromDb: ConnectionEntity | null = await dbConnection.getRepository(ConnectionEntity).findOne({ - // where: { type: connection.type }, - // }) - // - // expect(fromDb).toBeDefined() - // - // const fromDbConfig: DidAuthConfigEntity | null = await dbConnection.getRepository(DidAuthConfigEntity).findOne({ - // where: { id: fromDb?.id }, - // }) - // - // expect(fromDbConfig).toBeDefined() - // expect(fromDb?.type).toEqual(connection.type) - // expect(fromDb?.config).toBeDefined() - // expect((fromDb?.config).identifier).toEqual((connection.config).identifier.did) - // }) - // - // it('Should save openid config to database', async (): Promise => { - // const clientId = '138d7bf8-c930-4c6e-b928-97d3a4928b01' - // const config: NonPersistedOpenIdConfig = { - // clientId, - // clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', - // scopes: ['auth'], - // issuer: 'https://example.com/app-test', - // redirectUrl: 'app:/callback', - // dangerouslyAllowInsecureHttpRequests: true, - // clientAuthMethod: 'post', - // } - // - // const configEntity: OpenIdConfigEntity = openIdConfigEntityFrom(config) - // await dbConnection.getRepository(OpenIdConfigEntity).save(configEntity, { - // transaction: true, - // }) - // - // const fromDb: OpenIdConfigEntity | null = await dbConnection.getRepository(OpenIdConfigEntity).findOne({ - // where: { clientId: config.clientId }, - // }) - // - // expect(fromDb).toBeDefined() - // expect((fromDb).clientId).toEqual(config.clientId) - // }) - // - // it('Should save didauth config to database', async (): Promise => { - // const sessionId = 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01' - // const config: NonPersistedDidAuthConfig = { - // identifier: { - // did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - // provider: 'test_provider', - // keys: [], - // services: [], - // }, - // redirectUrl: 'https://example.com', - // stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', - // sessionId, - // } - // - // const configEntity: DidAuthConfigEntity = didAuthConfigEntityFrom(config) - // await dbConnection.getRepository(DidAuthConfigEntity).save(configEntity, { - // transaction: true, - // }) - // - // const fromDb: DidAuthConfigEntity | null = await dbConnection.getRepository(DidAuthConfigEntity).findOne({ - // where: { sessionId: config.sessionId }, - // }) - // - // expect(fromDb).toBeDefined() - // expect((fromDb).identifier).toEqual(config.identifier.did) - // }) - // - // it('Should delete party and all child relations', async (): Promise => { - // const party1: NonPersistedParty = { - // uri: 'example.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name1', - // }, - // contact: { - // firstName: 'example_first_name1', - // middleName: 'example_middle_name1', - // lastName: 'example_last_name1', - // displayName: 'example_display_name1', - // }, - // } - // - // const partyEntity1: PartyEntity = partyEntityFrom(party1) - // const savedParty1: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity1) - // - // expect(savedParty1).toBeDefined() - // - // const party2: NonPersistedParty = { - // uri: 'example.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - // name: 'example_name2', - // }, - // contact: { - // firstName: 'example_first_name2', - // middleName: 'example_middle_name2', - // lastName: 'example_last_name2', - // displayName: 'example_display_name2', - // }, - // } - // - // const partyEntity2: PartyEntity = partyEntityFrom(party2) - // const savedParty2: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity2) - // - // expect(savedParty2).toBeDefined() - // - // const correlationId = 'relation_example.com' - // const identity: NonPersistedIdentity = { - // alias: correlationId, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.URL, - // correlationId, - // }, - // connection: { - // type: ConnectionTypeEnum.OPENID_CONNECT, - // config: { - // clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', - // clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', - // scopes: ['auth'], - // issuer: 'https://example.com/app-test', - // redirectUrl: 'app:/callback', - // dangerouslyAllowInsecureHttpRequests: true, - // clientAuthMethod: 'post', - // }, - // }, - // metadata: [ - // { - // label: 'example_label', - // value: 'example_value', - // }, - // ], - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // identityEntity.party = savedParty1 - // - // const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) - // - // expect(savedIdentity).toBeDefined() - // - // const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ - // leftId: savedParty1.id, - // rightId: savedParty2.id, - // }) - // - // const savedRelationship: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { - // transaction: true, - // }) - // - // expect(savedRelationship).toBeDefined() - // - // expect( - // await dbConnection.getRepository(PartyEntity).findOne({ - // where: { id: savedParty1.id }, - // }) - // ).toBeDefined() - // - // await dbConnection.getRepository(PartyEntity).delete({ id: savedParty1.id }) - // - // // check party - // await expect( - // await dbConnection.getRepository(PartyEntity).findOne({ - // where: { id: savedParty1.id }, - // }) - // ).toBeNull() - // - // // check identity - // expect( - // await dbConnection.getRepository(IdentityEntity).findOne({ - // where: { id: savedParty1.id }, - // }) - // ).toBeNull() - // - // // check identity identifier - // expect( - // await dbConnection.getRepository(CorrelationIdentifierEntity).findOne({ - // where: { id: savedIdentity.identifier.id }, - // }) - // ).toBeNull() - // - // // check identity connection - // expect( - // await dbConnection.getRepository(ConnectionEntity).findOne({ - // where: { id: savedIdentity.connection!.id }, - // }) - // ).toBeNull() - // - // // check connection config - // expect( - // await dbConnection.getRepository(OpenIdConfigEntity).findOne({ - // where: { id: savedIdentity.connection!.config.id }, - // }) - // ).toBeNull() - // - // // check identity metadata - // expect( - // await dbConnection.getRepository(IdentityMetadataItemEntity).findOne({ - // where: { id: savedIdentity.metadata![0].id }, - // }) - // ).toBeNull() - // - // // check contact - // expect( - // await dbConnection.getRepository(BaseContactEntity).findOne({ - // where: { id: savedParty1.contact.id }, - // }) - // ).toBeNull() - // - // // check party type - // expect( - // await dbConnection.getRepository(PartyTypeEntity).findOne({ - // where: { id: savedParty1.partyType.id }, - // }) - // ).toBeDefined() - // - // // check relation - // expect( - // await dbConnection.getRepository(PartyRelationshipEntity).findOne({ - // where: { id: savedRelationship.id }, - // }) - // ).toBeNull() - // }) - // - // it('Should delete identity and all child relations', async (): Promise => { - // const party: NonPersistedParty = { - // uri: 'example.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contact: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const partyEntity: PartyEntity = partyEntityFrom(party) - // const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) - // - // expect(savedParty).toBeDefined() - // - // const correlationId = 'relation_example.com' - // const identity: NonPersistedIdentity = { - // alias: correlationId, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.URL, - // correlationId, - // }, - // connection: { - // type: ConnectionTypeEnum.SIOPv2, - // config: { - // identifier: { - // did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - // provider: 'test_provider', - // keys: [], - // services: [], - // }, - // redirectUrl: 'https://example.com', - // stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', - // sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - // }, - // }, - // metadata: [ - // { - // label: 'example_label', - // value: 'example_value', - // }, - // ], - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // identityEntity.party = savedParty - // - // const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) - // - // expect( - // await dbConnection.getRepository(PartyEntity).findOne({ - // where: { id: savedParty.id }, - // }) - // ).toBeDefined() - // - // await dbConnection.getRepository(IdentityEntity).delete({ id: savedIdentity.id }) - // - // // check identity - // expect( - // await dbConnection.getRepository(IdentityEntity).findOne({ - // where: { alias: correlationId }, - // }) - // ).toBeNull() - // - // // check identity identifier - // expect( - // await dbConnection.getRepository(CorrelationIdentifierEntity).findOne({ - // where: { id: savedIdentity.identifier.id }, - // }) - // ).toBeNull() - // - // // check identity connection - // expect( - // await dbConnection.getRepository(ConnectionEntity).findOne({ - // where: { id: savedIdentity.connection!.id }, - // }) - // ).toBeNull() - // - // // check connection config - // expect( - // await dbConnection.getRepository(OpenIdConfigEntity).findOne({ - // where: { id: savedIdentity.connection!.config.id }, - // }) - // ).toBeNull() - // - // // check identity metadata - // expect( - // await dbConnection.getRepository(IdentityMetadataItemEntity).findOne({ - // where: { id: savedIdentity.metadata![0].id }, - // }) - // ).toBeNull() - // }) - // - // it('Should not delete party when deleting identity', async (): Promise => { - // const party: NonPersistedParty = { - // uri: 'example.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contact: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const partyEntity: PartyEntity = partyEntityFrom(party) - // const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) - // - // expect(savedParty).toBeDefined() - // - // const correlationId = 'relation_example.com' - // const identity: NonPersistedIdentity = { - // alias: correlationId, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.URL, - // correlationId, - // }, - // connection: { - // type: ConnectionTypeEnum.SIOPv2, - // config: { - // identifier: { - // did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - // provider: 'test_provider', - // keys: [], - // services: [], - // }, - // redirectUrl: 'https://example.com', - // stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', - // sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', - // }, - // }, - // metadata: [ - // { - // label: 'example_label', - // value: 'example_value', - // }, - // ], - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // identityEntity.party = savedParty - // - // const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) - // - // expect(savedIdentity).toBeDefined() - // - // await dbConnection.getRepository(IdentityEntity).delete({ id: savedIdentity.id }) - // - // // check identity - // expect( - // await dbConnection.getRepository(IdentityEntity).findOne({ - // where: { id: savedIdentity.id }, - // }) - // ).toBeNull() - // - // // check party - // expect( - // await dbConnection.getRepository(PartyEntity).findOne({ - // where: { id: savedParty.id }, - // }) - // ).toBeDefined() - // }) - // - // it('Should set creation date when saving party', async (): Promise => { - // const party: NonPersistedParty = { - // uri: 'example.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contact: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const partyEntity: PartyEntity = partyEntityFrom(party) - // const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) - // - // const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - // where: { id: savedParty.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.createdAt).toBeDefined() - // }) - // - // it('Should not update creation date when updating party', async (): Promise => { - // const party: NonPersistedParty = { - // uri: 'example.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contact: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const partyEntity: PartyEntity = partyEntityFrom(party) - // const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) - // - // expect(savedParty).toBeDefined() - // - // const newContactFirstName = 'new_first_name' - // await dbConnection.getRepository(PartyEntity).save({ - // ...savedParty, - // contact: { - // ...savedParty.contact, - // firstName: newContactFirstName, - // }, - // }) - // - // const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - // where: { id: savedParty.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect((fromDb?.contact).firstName).toEqual(newContactFirstName) - // expect(fromDb?.createdAt).toEqual(savedParty?.createdAt) - // }) - // - // it('Should set creation date when saving identity', async (): Promise => { - // const correlationId = 'example_did' - // const identity: NonPersistedIdentity = { - // alias: correlationId, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId, - // }, - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // await dbConnection.getRepository(IdentityEntity).save(identityEntity) - // - // const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ - // where: { - // identifier: { - // correlationId, - // }, - // }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.createdAt).toBeDefined() - // }) - // - // it('Should not update creation date when saving identity', async (): Promise => { - // const correlationId = 'example_did' - // const identity: NonPersistedIdentity = { - // alias: correlationId, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId, - // }, - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) - // const newCorrelationId = 'new_example_did' - // await dbConnection - // .getRepository(IdentityEntity) - // .save({ ...savedIdentity, identifier: { ...savedIdentity.identifier, correlationId: newCorrelationId } }) - // - // const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ - // where: { - // identifier: { - // correlationId: newCorrelationId, - // }, - // }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.createdAt).toEqual(savedIdentity?.createdAt) - // }) - // - // it('Should set last updated date when saving party', async (): Promise => { - // const party: NonPersistedParty = { - // uri: 'example.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contact: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const partyEntity: PartyEntity = partyEntityFrom(party) - // const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) - // - // const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - // where: { id: savedParty.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.lastUpdatedAt).toBeDefined() - // }) - // - // it('Should update last updated date when updating party', async (): Promise => { - // const party: NonPersistedParty = { - // uri: 'example.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contact: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const partyEntity: PartyEntity = partyEntityFrom(party) - // const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) - // expect(savedParty).toBeDefined() - // - // // waiting here to get a different timestamp - // await new Promise((resolve) => setTimeout(resolve, 2000)) - // - // const newContactFirstName = 'new_first_name' - // await dbConnection.getRepository(PartyEntity).save({ - // ...savedParty, - // // FIXME there is still an issue when updating nested objects, the parent does not update - // // https://github.com/typeorm/typeorm/issues/5378 - // uri: 'new uri', // TODO remove this to trigger the bug - // contact: { - // ...savedParty.contact, - // firstName: newContactFirstName, - // }, - // }) - // - // const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - // where: { id: savedParty.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect((fromDb?.contact).firstName).toEqual(newContactFirstName) - // expect(fromDb?.lastUpdatedAt).not.toEqual(savedParty?.lastUpdatedAt) - // }) - // - // it('Should set last updated date when saving party type', async (): Promise => { - // const partyType: NonPersistedPartyType = { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // } - // - // const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) - // const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) - // - // const fromDb: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).findOne({ - // where: { id: savedPartyType.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.lastUpdatedAt).toBeDefined() - // }) - // - // it('Should set last creation date when saving party type', async (): Promise => { - // const partyType: NonPersistedPartyType = { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // } - // - // const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) - // const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) - // - // const fromDb: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).findOne({ - // where: { id: savedPartyType.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.createdAt).toBeDefined() - // }) - // - // it('Should set last updated date when saving identity', async (): Promise => { - // const correlationId = 'example_did' - // const identity: NonPersistedIdentity = { - // alias: correlationId, - // roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], - // identifier: { - // type: CorrelationIdentifierEnum.DID, - // correlationId, - // }, - // } - // - // const identityEntity: IdentityEntity = identityEntityFrom(identity) - // await dbConnection.getRepository(IdentityEntity).save(identityEntity) - // - // const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ - // where: { - // identifier: { - // correlationId, - // }, - // }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.lastUpdatedAt).toBeDefined() - // }) - // - // it('Should enforce unique type and tenant id combination when saving party type', async (): Promise => { - // const tenantId = 'non_unique_value' - // const name = 'non_unique_value' - // const partyType1: NonPersistedPartyType = { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId, - // name, - // } - // - // const partyTypeEntity1: PartyTypeEntity = partyTypeEntityFrom(partyType1) - // const savedPartyType1: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity1) - // - // expect(savedPartyType1).toBeDefined() - // - // const partyType2: NonPersistedPartyType = { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId, - // name, - // } - // - // const partyTypeEntity2: PartyTypeEntity = partyTypeEntityFrom(partyType2) - // await expect(dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity2)).rejects.toThrowError( - // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: PartyType.type, PartyType.tenant_id' - // ) - // }) - // - // it('Should enforce unique name when saving party type', async (): Promise => { - // const name = 'non_unique_value' - // const partyType1: NonPersistedPartyType = { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name, - // } - // - // const partyTypeEntity1: PartyTypeEntity = partyTypeEntityFrom(partyType1) - // const savedPartyType1: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity1) - // - // expect(savedPartyType1).toBeDefined() - // - // const partyType2: NonPersistedPartyType = { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - // name, - // } - // - // const partyTypeEntity2: PartyTypeEntity = partyTypeEntityFrom(partyType2) - // await expect(dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity2)).rejects.toThrowError( - // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: PartyType.name' - // ) - // }) - // - // it('Should enforce unique legal name when saving organization', async (): Promise => { - // const legalName = 'non_unique_value' - // const organization1: NonPersistedOrganization = { - // legalName, - // displayName: 'example_display_name', - // } - // - // const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) - // const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { - // transaction: true, - // }) - // - // expect(savedOrganization1).toBeDefined() - // - // const organization2: NonPersistedOrganization = { - // legalName, - // displayName: 'example_display_name', - // } - // - // const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) - // await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( - // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: BaseContact.legal_name' - // ) - // }) - // - // it('Should enforce unique legal name when saving organization', async (): Promise => { - // const legalName = 'example_legal_name' - // const organization1: NonPersistedOrganization = { - // legalName, - // displayName: 'example_display_name', - // } - // - // const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) - // const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { - // transaction: true, - // }) - // - // expect(savedOrganization1).toBeDefined() - // - // const organization2: NonPersistedOrganization = { - // legalName, - // displayName: 'example_display_name', - // } - // - // const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) - // await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( - // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: BaseContact.legal_name' - // ) - // }) - // - // it('Should save party relationship to database', async (): Promise => { - // const party1: NonPersistedParty = { - // uri: 'example1.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name1', - // }, - // contact: { - // firstName: 'example_first_name1', - // middleName: 'example_middle_name1', - // lastName: 'example_last_name1', - // displayName: 'example_display_name1', - // }, - // } - // - // const partyEntity1: PartyEntity = partyEntityFrom(party1) - // const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { - // transaction: true, - // }) - // - // expect(savedParty1).toBeDefined() - // - // const party2: NonPersistedParty = { - // uri: 'example2.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - // name: 'example_name2', - // }, - // contact: { - // firstName: 'example_first_name2', - // middleName: 'example_middle_name2', - // lastName: 'example_last_name2', - // displayName: 'example_display_name2', - // }, - // } - // - // const partyEntity2: PartyEntity = partyEntityFrom(party2) - // const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { - // transaction: true, - // }) - // - // expect(savedParty2).toBeDefined() - // - // const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ - // leftId: savedParty1.id, - // rightId: savedParty2.id, - // }) - // - // await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { - // transaction: true, - // }) - // - // // TODO check the relation field - // const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - // where: { id: partyEntity1.id }, - // }) - // - // expect(fromDb).toBeDefined() - // }) - // - // it('Should set last updated date when saving party relationship', async (): Promise => { - // const party1: NonPersistedParty = { - // uri: 'example1.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name1', - // }, - // contact: { - // firstName: 'example_first_name1', - // middleName: 'example_middle_name1', - // lastName: 'example_last_name1', - // displayName: 'example_display_name1', - // }, - // } - // - // const partyEntity1: PartyEntity = partyEntityFrom(party1) - // const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { - // transaction: true, - // }) - // - // const party2: NonPersistedParty = { - // uri: 'example2.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - // name: 'example_name2', - // }, - // contact: { - // firstName: 'example_first_name2', - // middleName: 'example_middle_name2', - // lastName: 'example_last_name2', - // displayName: 'example_display_name2', - // }, - // } - // - // const partyEntity2: PartyEntity = partyEntityFrom(party2) - // const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { - // transaction: true, - // }) - // - // const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ - // leftId: savedParty1.id, - // rightId: savedParty2.id, - // }) - // - // await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { - // transaction: true, - // }) - // - // const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - // where: { id: partyEntity1.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.lastUpdatedAt).toBeDefined() - // }) - // - // it('Should set creation date when saving party relationship', async (): Promise => { - // const party1: NonPersistedParty = { - // uri: 'example1.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name1', - // }, - // contact: { - // firstName: 'example_first_name1', - // middleName: 'example_middle_name1', - // lastName: 'example_last_name1', - // displayName: 'example_display_name1', - // }, - // } - // - // const partyEntity1: PartyEntity = partyEntityFrom(party1) - // const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { - // transaction: true, - // }) - // - // const party2: NonPersistedParty = { - // uri: 'example2.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - // name: 'example_name2', - // }, - // contact: { - // firstName: 'example_first_name2', - // middleName: 'example_middle_name2', - // lastName: 'example_last_name2', - // displayName: 'example_display_name2', - // }, - // } - // - // const partyEntity2: PartyEntity = partyEntityFrom(party2) - // const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { - // transaction: true, - // }) - // - // const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ - // leftId: savedParty1.id, - // rightId: savedParty2.id, - // }) - // - // await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { - // transaction: true, - // }) - // - // const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - // where: { id: partyEntity1.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.createdAt).toBeDefined() - // }) - // - // it('Should save bidirectional party relationships to database', async (): Promise => { - // const party1: NonPersistedParty = { - // uri: 'example1.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name1', - // }, - // contact: { - // firstName: 'example_first_name1', - // middleName: 'example_middle_name1', - // lastName: 'example_last_name1', - // displayName: 'example_display_name1', - // }, - // } - // - // const partyEntity1: PartyEntity = partyEntityFrom(party1) - // const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { - // transaction: true, - // }) - // - // expect(savedParty1).toBeDefined() - // - // const party2: NonPersistedParty = { - // uri: 'example2.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - // name: 'example_name2', - // }, - // contact: { - // firstName: 'example_first_name2', - // middleName: 'example_middle_name2', - // lastName: 'example_last_name2', - // displayName: 'example_display_name2', - // }, - // } - // - // const partyEntity2: PartyEntity = partyEntityFrom(party2) - // const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { - // transaction: true, - // }) - // - // expect(savedParty2).toBeDefined() - // - // const relationship1: PartyRelationshipEntity = partyRelationshipEntityFrom({ - // leftId: savedParty1.id, - // rightId: savedParty2.id, - // }) - // - // const savedRelationship1: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship1, { - // transaction: true, - // }) - // - // expect(savedRelationship1).toBeDefined() - // - // const relationship2: PartyRelationshipEntity = partyRelationshipEntityFrom({ - // leftId: savedParty2.id, - // rightId: savedParty1.id, - // }) - // - // const savedRelationship2: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship2, { - // transaction: true, - // }) - // - // expect(savedRelationship2).toBeDefined() - // - // const fromDb: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).findOne({ - // where: { id: savedRelationship2.id }, - // }) - // - // expect(fromDb).toBeDefined() - // }) - // - // it('Should enforce unique owner combination for party relationship', async (): Promise => { - // const party1: NonPersistedParty = { - // uri: 'example1.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name1', - // }, - // contact: { - // firstName: 'example_first_name1', - // middleName: 'example_middle_name1', - // lastName: 'example_last_name1', - // displayName: 'example_display_name1', - // }, - // } - // - // const partyEntity1: PartyEntity = partyEntityFrom(party1) - // const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { - // transaction: true, - // }) - // - // expect(savedParty1).toBeDefined() - // - // const party2: NonPersistedParty = { - // uri: 'example2.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - // name: 'example_name2', - // }, - // contact: { - // firstName: 'example_first_name2', - // middleName: 'example_middle_name2', - // lastName: 'example_last_name2', - // displayName: 'example_display_name2', - // }, - // } - // - // const partyEntity2: PartyEntity = partyEntityFrom(party2) - // const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { - // transaction: true, - // }) - // - // expect(savedParty2).toBeDefined() - // - // const relationship1: PartyRelationshipEntity = partyRelationshipEntityFrom({ - // leftId: savedParty1.id, - // rightId: savedParty2.id, - // }) - // - // const savedRelationship1: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship1, { - // transaction: true, - // }) - // - // expect(savedRelationship1).toBeDefined() - // - // const relationship2: PartyRelationshipEntity = partyRelationshipEntityFrom({ - // leftId: savedParty1.id, - // rightId: savedParty2.id, - // }) - // - // await expect(dbConnection.getRepository(PartyRelationshipEntity).save(relationship2)).rejects.toThrowError( - // 'SQLITE_CONSTRAINT: UNIQUE constraint failed: PartyRelationship.left_id, PartyRelationship.right_id' - // ) - // }) - // - // it('Should save party type to database', async (): Promise => { - // const partyType: NonPersistedPartyType = { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // } - // - // const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) - // const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) - // - // const fromDb: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).findOne({ - // where: { id: savedPartyType.id }, - // }) - // - // expect(fromDb).toBeDefined() - // }) - // - // it('Should save person to database', async (): Promise => { - // const person: NonPersistedNaturalPerson = { - // firstName: 'example_first_name', - // lastName: 'lastName2', - // displayName: 'displayName', - // } - // - // const personEntity: NaturalPersonEntity = naturalPersonEntityFrom(person) - // const savedPerson: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).save(personEntity, { - // transaction: true, - // }) - // - // const fromDb: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).findOne({ - // where: { id: savedPerson.id }, - // }) - // - // expect(fromDb).toBeDefined() - // }) - // - // it('Should set last updated date when saving person', async (): Promise => { - // const person: NonPersistedNaturalPerson = { - // firstName: 'example_first_name', - // lastName: 'lastName2', - // displayName: 'displayName', - // } - // - // const personEntity: NaturalPersonEntity = naturalPersonEntityFrom(person) - // const savedPerson: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).save(personEntity, { - // transaction: true, - // }) - // - // const fromDb: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).findOne({ - // where: { id: savedPerson.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.lastUpdatedAt).toBeDefined() - // }) - // - // it('Should set creation date when saving person', async (): Promise => { - // const person: NonPersistedNaturalPerson = { - // firstName: 'example_first_name', - // lastName: 'lastName2', - // displayName: 'displayName', - // } - // - // const personEntity: NaturalPersonEntity = naturalPersonEntityFrom(person) - // const savedPerson: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).save(personEntity, { - // transaction: true, - // }) - // - // const fromDb: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).findOne({ - // where: { id: savedPerson.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.createdAt).toBeDefined() - // }) - // - // it('Should save organization to database', async (): Promise => { - // const organization: NonPersistedOrganization = { - // legalName: 'example_legal_name', - // displayName: 'example_display_name', - // } - // - // const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) - // const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { - // transaction: true, - // }) - // - // const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ - // where: { id: savedOrganization.id }, - // }) - // - // expect(fromDb).toBeDefined() - // }) - // - // it('Should set last updated date when saving organization', async (): Promise => { - // const organization: NonPersistedOrganization = { - // legalName: 'example_legal_name', - // displayName: 'example_display_name', - // } - // - // const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) - // const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { - // transaction: true, - // }) - // - // const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ - // where: { id: savedOrganization.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.lastUpdatedAt).toBeDefined() - // }) - // - // it('Should set creation date when saving organization', async (): Promise => { - // const organization: NonPersistedOrganization = { - // legalName: 'example_legal_name', - // displayName: 'example_display_name', - // } - // - // const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) - // const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { - // transaction: true, - // }) - // - // const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ - // where: { id: savedOrganization.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.createdAt).toBeDefined() - // }) - // - // it('Should get party based on person information', async (): Promise => { - // const firstName = 'example_first_name' - // const party: NonPersistedParty = { - // uri: 'example.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contact: { - // firstName, - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const partyEntity: PartyEntity = partyEntityFrom(party) - // await dbConnection.getRepository(PartyEntity).save(partyEntity, { - // transaction: true, - // }) - // - // const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - // where: { - // contact: { - // firstName, - // } as FindOptionsWhere, //NaturalPersonEntity | OrganizationEntity - // }, - // }) - // - // expect(fromDb).toBeDefined() - // }) - // - // it('Should get party based on organization information', async (): Promise => { - // const legalName = 'example_legal_name' - // const party: NonPersistedParty = { - // uri: 'example.com', - // partyType: { - // type: PartyTypeEnum.ORGANIZATION, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contact: { - // legalName, - // displayName: 'example_display_name', - // }, - // } - // - // const partyEntity: PartyEntity = partyEntityFrom(party) - // await dbConnection.getRepository(PartyEntity).save(partyEntity, { - // transaction: true, - // }) - // - // const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - // where: { - // contact: { - // legalName, - // } as FindOptionsWhere, //NaturalPersonEntity | OrganizationEntity - // }, - // }) - // - // expect(fromDb).toBeDefined() - // }) - // - // it("Should enforce unique party id's for relationship sides", async (): Promise => { - // const party: NonPersistedParty = { - // uri: 'example.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contact: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const partyEntity: PartyEntity = partyEntityFrom(party) - // const savedParty: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity, { - // transaction: true, - // }) - // - // expect(savedParty).toBeDefined() - // - // const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ - // leftId: savedParty.id, - // rightId: savedParty.id, - // }) - // - // await expect(dbConnection.getRepository(PartyRelationshipEntity).save(relationship)).rejects.toThrowError( - // 'Cannot use the same id for both sides of the relationship' - // ) - // }) - // - // it('Should delete party relationship', async (): Promise => { - // const party1: NonPersistedParty = { - // uri: 'example1.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name1', - // }, - // contact: { - // firstName: 'example_first_name1', - // middleName: 'example_middle_name1', - // lastName: 'example_last_name1', - // displayName: 'example_display_name1', - // }, - // } - // - // const partyEntity1: PartyEntity = partyEntityFrom(party1) - // const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { - // transaction: true, - // }) - // - // expect(savedParty1).toBeDefined() - // - // const party2: NonPersistedParty = { - // uri: 'example2.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', - // name: 'example_name2', - // }, - // contact: { - // firstName: 'example_first_name2', - // middleName: 'example_middle_name2', - // lastName: 'example_last_name2', - // displayName: 'example_display_name2', - // }, - // } - // - // const partyEntity2: PartyEntity = partyEntityFrom(party2) - // const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { - // transaction: true, - // }) - // - // expect(savedParty2).toBeDefined() - // - // const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ - // leftId: savedParty1.id, - // rightId: savedParty2.id, - // }) - // - // const savedRelationship: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { - // transaction: true, - // }) - // - // expect(savedRelationship).toBeDefined() - // - // await dbConnection.getRepository(PartyRelationshipEntity).delete({ id: savedRelationship.id }) - // - // await expect( - // await dbConnection.getRepository(PartyRelationshipEntity).findOne({ - // where: { id: savedRelationship.id }, - // }) - // ).toBeNull() - // }) - // - // it('Should delete party type', async (): Promise => { - // const partyType: NonPersistedPartyType = { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // } - // - // const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) - // const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) - // - // expect(savedPartyType).toBeDefined() - // - // await dbConnection.getRepository(PartyTypeEntity).delete({ id: savedPartyType.id }) - // - // await expect( - // await dbConnection.getRepository(PartyTypeEntity).findOne({ - // where: { id: savedPartyType.id }, - // }) - // ).toBeNull() - // }) - // - // it('Should not be able to remove party type when used by parties', async (): Promise => { - // const party: NonPersistedParty = { - // uri: 'example.com', - // partyType: { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // }, - // contact: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const partyEntity: PartyEntity = partyEntityFrom(party) - // const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity, { - // transaction: true, - // }) - // - // expect(savedParty).toBeDefined() - // - // await expect(dbConnection.getRepository(PartyTypeEntity).delete({ id: savedParty.partyType.id })).rejects.toThrowError( - // 'FOREIGN KEY constraint failed' - // ) - // }) - // - // it('Should save party with existing party type', async (): Promise => { - // const partyType: NonPersistedPartyType = { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // } - // - // const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) - // const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) - // - // const party: NonPersistedParty = { - // uri: 'example.com', - // partyType: savedPartyType, - // contact: { - // firstName: 'example_first_name', - // middleName: 'example_middle_name', - // lastName: 'example_last_name', - // displayName: 'example_display_name', - // }, - // } - // - // const partyEntity: PartyEntity = partyEntityFrom(party) - // partyEntity.partyType = savedPartyType - // await dbConnection.getRepository(PartyEntity).save(partyEntity, { - // transaction: true, - // }) - // - // const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ - // where: { id: partyEntity.id }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.partyType).toBeDefined() - // expect(fromDb?.partyType.id).toEqual(savedPartyType.id) - // expect(fromDb?.partyType.type).toEqual(savedPartyType.type) - // expect(fromDb?.partyType.tenantId).toEqual(savedPartyType.tenantId) - // expect(fromDb?.partyType.name).toEqual(savedPartyType.name) - // }) - // - // it('Should not update creation date when saving party type', async (): Promise => { - // const partyType: NonPersistedPartyType = { - // type: PartyTypeEnum.NATURAL_PERSON, - // tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', - // name: 'example_name', - // } - // - // const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) - // const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) - // await dbConnection.getRepository(PartyTypeEntity).save({ ...savedPartyType, type: PartyTypeEnum.ORGANIZATION }) - // - // const fromDb: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).findOne({ - // where: { - // type: PartyTypeEnum.ORGANIZATION, - // }, - // }) - // - // expect(fromDb).toBeDefined() - // expect(fromDb?.createdAt).toEqual(savedPartyType?.createdAt) - // }) + it('should throw error when saving organization party with blank legal name', async (): Promise => { + const party: NonPersistedParty = { + uri: 'example.com', + partyType: { + type: PartyTypeEnum.ORGANIZATION, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contact: { + legalName: '', + displayName: 'example_legal_name', + }, + } + + const partyEntity: PartyEntity = partyEntityFrom(party) + + await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank legal names are not allowed') + }) + + it('should throw error when saving organization party with blank display name', async (): Promise => { + const party: NonPersistedParty = { + uri: 'example.com', + partyType: { + type: PartyTypeEnum.ORGANIZATION, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contact: { + legalName: 'example_first_name', + displayName: '', + }, + } + + const partyEntity: PartyEntity = partyEntityFrom(party) + + await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank display names are not allowed') + }) + + it('should throw error when saving party with blank party type name', async (): Promise => { + const party: NonPersistedParty = { + uri: 'example.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: '', + }, + contact: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const partyEntity: PartyEntity = partyEntityFrom(party) + + await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank names are not allowed') + }) + + it('should throw error when saving party with blank party type description', async (): Promise => { + const party: NonPersistedParty = { + uri: 'example.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + description: '', + }, + contact: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const partyEntity: PartyEntity = partyEntityFrom(party) + + await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError('Blank descriptions are not allowed') + }) + + it('should throw error when saving party with blank party type tenant id', async (): Promise => { + const party: NonPersistedParty = { + uri: 'example.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '', + name: 'example_name', + }, + contact: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const partyEntity: PartyEntity = partyEntityFrom(party) + + await expect(dbConnection.getRepository(PartyEntity).save(partyEntity)).rejects.toThrowError("Blank tenant id's are not allowed") + }) + + it('Should enforce unique alias for an identity', async (): Promise => { + const alias = 'non_unique_alias' + const identity1: NonPersistedIdentity = { + alias, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId: 'unique_correlationId1', + }, + } + const identity1Entity: IdentityEntity = identityEntityFrom(identity1) + await dbConnection.getRepository(IdentityEntity).save(identity1Entity) + + const identity2: NonPersistedIdentity = { + alias: alias, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId: 'unique_correlationId2', + }, + } + const identity2Entity: IdentityEntity = identityEntityFrom(identity2) + await expect(dbConnection.getRepository(IdentityEntity).save(identity2Entity)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: Identity.alias' + ) + }) + + it('Should enforce unique correlationId for a identity', async (): Promise => { + const correlationId = 'non_unique_correlationId' + const identity1: NonPersistedIdentity = { + alias: 'unique_alias1', + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId, + }, + } + const identity1Entity: IdentityEntity = identityEntityFrom(identity1) + await dbConnection.getRepository(IdentityEntity).save(identity1Entity) + + const identity2: NonPersistedIdentity = { + alias: 'unique_alias2', + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId, + }, + } + const identity2Entity: IdentityEntity = identityEntityFrom(identity2) + await expect(dbConnection.getRepository(IdentityEntity).save(identity2Entity)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: CorrelationIdentifier.correlation_id' + ) + }) + + it('Should save identity to database', async (): Promise => { + const correlationId = 'example_did' + const identity: NonPersistedIdentity = { + alias: correlationId, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId, + }, + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + + await dbConnection.getRepository(IdentityEntity).save(identityEntity) + + const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ + where: { + identifier: { + correlationId, + }, + }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.connection).toBeNull() + expect(fromDb?.identifier).toBeDefined() + expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) + expect(fromDb?.identifier.type).toEqual(identity.identifier.type) + }) + + it('should throw error when saving identity with blank alias', async (): Promise => { + const identity: NonPersistedIdentity = { + alias: '', + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId: 'example_did', + }, + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + + await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank aliases are not allowed') + }) + + it('should throw error when saving identity with blank correlation id', async (): Promise => { + const identity: NonPersistedIdentity = { + alias: 'example_did', + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId: '', + }, + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + + await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank correlation ids are not allowed') + }) + + it('should throw error when saving identity with blank metadata label', async (): Promise => { + const correlationId = 'example_did' + const identity: NonPersistedIdentity = { + alias: correlationId, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId, + }, + metadata: [ + { + label: '', + value: 'example_value', + }, + ], + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + + await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank metadata labels are not allowed') + }) + + it('should throw error when saving identity with blank metadata value', async (): Promise => { + const correlationId = 'example_did' + const identity: NonPersistedIdentity = { + alias: correlationId, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId, + }, + metadata: [ + { + label: 'example_label', + value: '', + }, + ], + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + + await expect(dbConnection.getRepository(IdentityEntity).save(identityEntity)).rejects.toThrowError('Blank metadata values are not allowed') + }) + + it('Should save identity with openid connection to database', async (): Promise => { + const correlationId = 'example.com' + const identity: NonPersistedIdentity = { + alias: correlationId, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.URL, + correlationId, + }, + connection: { + type: ConnectionTypeEnum.OPENID_CONNECT, + config: { + clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', + clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', + scopes: ['auth'], + issuer: 'https://example.com/app-test', + redirectUrl: 'app:/callback', + dangerouslyAllowInsecureHttpRequests: true, + clientAuthMethod: 'post', + }, + }, + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + + await dbConnection.getRepository(IdentityEntity).save(identityEntity) + + const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ + where: { + identifier: { + correlationId, + }, + }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.connection).toBeDefined() + expect(fromDb?.identifier).toBeDefined() + expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) + expect(fromDb?.identifier.type).toEqual(identity.identifier.type) + expect(fromDb?.connection?.type).toEqual(identity.connection?.type) + expect(fromDb?.connection?.config).toBeDefined() + expect((fromDb?.connection?.config).clientId).toEqual((identity.connection?.config).clientId) + }) + + it('Should save identity with didauth connection to database', async (): Promise => { + const correlationId = 'example.com' + const identity: NonPersistedIdentity = { + alias: correlationId, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.URL, + correlationId, + }, + connection: { + type: ConnectionTypeEnum.SIOPv2, + config: { + identifier: { + did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + provider: 'test_provider', + keys: [], + services: [], + }, + redirectUrl: 'https://example.com', + stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', + sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + }, + }, + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + + await dbConnection.getRepository(IdentityEntity).save(identityEntity) + + const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ + where: { + identifier: { + correlationId, + }, + }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.connection).toBeDefined() + expect(fromDb?.identifier).toBeDefined() + expect(fromDb?.identifier.correlationId).toEqual(identity.identifier.correlationId) + expect(fromDb?.identifier.type).toEqual(identity.identifier.type) + expect(fromDb?.connection?.type).toEqual(identity.connection?.type) + expect(fromDb?.connection?.config).toBeDefined() + expect((fromDb?.connection?.config).identifier).toEqual( + (identity.connection?.config).identifier.did + ) + }) + + it('Should save connection with openid config to database', async (): Promise => { + const connection: NonPersistedConnection = { + type: ConnectionTypeEnum.OPENID_CONNECT, + config: { + clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', + clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', + scopes: ['auth'], + issuer: 'https://example.com/app-test', + redirectUrl: 'app:/callback', + dangerouslyAllowInsecureHttpRequests: true, + clientAuthMethod: 'post', + }, + } + const connectionEntity: ConnectionEntity = connectionEntityFrom(connection) + await dbConnection.getRepository(ConnectionEntity).save(connectionEntity, { + transaction: true, + }) + + const fromDb: ConnectionEntity | null = await dbConnection.getRepository(ConnectionEntity).findOne({ + where: { type: connection.type }, + }) + + expect(fromDb).toBeDefined() + + const fromDbConfig: OpenIdConfigEntity | null = await dbConnection.getRepository(OpenIdConfigEntity).findOne({ + where: { id: fromDb?.id }, + }) + + expect(fromDbConfig).toBeDefined() + expect(fromDb?.type).toEqual(connection.type) + expect(fromDb?.config).toBeDefined() + expect((fromDb?.config).clientId).toEqual((connection.config).clientId) + }) + + it('Should save connection with didauth config to database', async (): Promise => { + const connection: NonPersistedConnection = { + type: ConnectionTypeEnum.SIOPv2, + config: { + identifier: { + did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + provider: 'test_provider', + keys: [], + services: [], + }, + redirectUrl: 'https://example.com', + stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', + sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + }, + } + const connectionEntity: ConnectionEntity = connectionEntityFrom(connection) + await dbConnection.getRepository(ConnectionEntity).save(connectionEntity, { + transaction: true, + }) + + const fromDb: ConnectionEntity | null = await dbConnection.getRepository(ConnectionEntity).findOne({ + where: { type: connection.type }, + }) + + expect(fromDb).toBeDefined() + + const fromDbConfig: DidAuthConfigEntity | null = await dbConnection.getRepository(DidAuthConfigEntity).findOne({ + where: { id: fromDb?.id }, + }) + + expect(fromDbConfig).toBeDefined() + expect(fromDb?.type).toEqual(connection.type) + expect(fromDb?.config).toBeDefined() + expect((fromDb?.config).identifier).toEqual((connection.config).identifier.did) + }) + + it('Should save openid config to database', async (): Promise => { + const clientId = '138d7bf8-c930-4c6e-b928-97d3a4928b01' + const config: NonPersistedOpenIdConfig = { + clientId, + clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', + scopes: ['auth'], + issuer: 'https://example.com/app-test', + redirectUrl: 'app:/callback', + dangerouslyAllowInsecureHttpRequests: true, + clientAuthMethod: 'post', + } + + const configEntity: OpenIdConfigEntity = openIdConfigEntityFrom(config) + await dbConnection.getRepository(OpenIdConfigEntity).save(configEntity, { + transaction: true, + }) + + const fromDb: OpenIdConfigEntity | null = await dbConnection.getRepository(OpenIdConfigEntity).findOne({ + where: { clientId: config.clientId }, + }) + + expect(fromDb).toBeDefined() + expect((fromDb).clientId).toEqual(config.clientId) + }) + + it('Should save didauth config to database', async (): Promise => { + const sessionId = 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01' + const config: NonPersistedDidAuthConfig = { + identifier: { + did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + provider: 'test_provider', + keys: [], + services: [], + }, + redirectUrl: 'https://example.com', + stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', + sessionId, + } + + const configEntity: DidAuthConfigEntity = didAuthConfigEntityFrom(config) + await dbConnection.getRepository(DidAuthConfigEntity).save(configEntity, { + transaction: true, + }) + + const fromDb: DidAuthConfigEntity | null = await dbConnection.getRepository(DidAuthConfigEntity).findOne({ + where: { sessionId: config.sessionId }, + }) + + expect(fromDb).toBeDefined() + expect((fromDb).identifier).toEqual(config.identifier.did) + }) + + it('Should delete party and all child relations', async (): Promise => { + const party1: NonPersistedParty = { + uri: 'example.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contact: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const partyEntity1: PartyEntity = partyEntityFrom(party1) + const savedParty1: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity1) + + expect(savedParty1).toBeDefined() + + const party2: NonPersistedParty = { + uri: 'example.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contact: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + + const partyEntity2: PartyEntity = partyEntityFrom(party2) + const savedParty2: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity2) + + expect(savedParty2).toBeDefined() + + const correlationId = 'relation_example.com' + const identity: NonPersistedIdentity = { + alias: correlationId, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.URL, + correlationId, + }, + connection: { + type: ConnectionTypeEnum.OPENID_CONNECT, + config: { + clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01', + clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0', + scopes: ['auth'], + issuer: 'https://example.com/app-test', + redirectUrl: 'app:/callback', + dangerouslyAllowInsecureHttpRequests: true, + clientAuthMethod: 'post', + }, + }, + metadata: [ + { + label: 'example_label', + value: 'example_value', + }, + ], + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + identityEntity.party = savedParty1 + + const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) + + expect(savedIdentity).toBeDefined() + + const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ + leftId: savedParty1.id, + rightId: savedParty2.id, + }) + + const savedRelationship: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { + transaction: true, + }) + + expect(savedRelationship).toBeDefined() + + expect( + await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: savedParty1.id }, + }) + ).toBeDefined() + + await dbConnection.getRepository(PartyEntity).delete({ id: savedParty1.id }) + + // check party + await expect( + await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: savedParty1.id }, + }) + ).toBeNull() + + // check identity + expect( + await dbConnection.getRepository(IdentityEntity).findOne({ + where: { id: savedParty1.id }, + }) + ).toBeNull() + + // check identity identifier + expect( + await dbConnection.getRepository(CorrelationIdentifierEntity).findOne({ + where: { id: savedIdentity.identifier.id }, + }) + ).toBeNull() + + // check identity connection + expect( + await dbConnection.getRepository(ConnectionEntity).findOne({ + where: { id: savedIdentity.connection!.id }, + }) + ).toBeNull() + + // check connection config + expect( + await dbConnection.getRepository(OpenIdConfigEntity).findOne({ + where: { id: savedIdentity.connection!.config.id }, + }) + ).toBeNull() + + // check identity metadata + expect( + await dbConnection.getRepository(IdentityMetadataItemEntity).findOne({ + where: { id: savedIdentity.metadata![0].id }, + }) + ).toBeNull() + + // check contact + expect( + await dbConnection.getRepository(BaseContactEntity).findOne({ + where: { id: savedParty1.contact.id }, + }) + ).toBeNull() + + // check party type + expect( + await dbConnection.getRepository(PartyTypeEntity).findOne({ + where: { id: savedParty1.partyType.id }, + }) + ).toBeDefined() + + // check relation + expect( + await dbConnection.getRepository(PartyRelationshipEntity).findOne({ + where: { id: savedRelationship.id }, + }) + ).toBeNull() + }) + + it('Should delete identity and all child relations', async (): Promise => { + const party: NonPersistedParty = { + uri: 'example.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contact: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const partyEntity: PartyEntity = partyEntityFrom(party) + const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) + + expect(savedParty).toBeDefined() + + const correlationId = 'relation_example.com' + const identity: NonPersistedIdentity = { + alias: correlationId, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.URL, + correlationId, + }, + connection: { + type: ConnectionTypeEnum.SIOPv2, + config: { + identifier: { + did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + provider: 'test_provider', + keys: [], + services: [], + }, + redirectUrl: 'https://example.com', + stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', + sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + }, + }, + metadata: [ + { + label: 'example_label', + value: 'example_value', + }, + ], + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + identityEntity.party = savedParty + + const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) + + expect( + await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: savedParty.id }, + }) + ).toBeDefined() + + await dbConnection.getRepository(IdentityEntity).delete({ id: savedIdentity.id }) + + // check identity + expect( + await dbConnection.getRepository(IdentityEntity).findOne({ + where: { alias: correlationId }, + }) + ).toBeNull() + + // check identity identifier + expect( + await dbConnection.getRepository(CorrelationIdentifierEntity).findOne({ + where: { id: savedIdentity.identifier.id }, + }) + ).toBeNull() + + // check identity connection + expect( + await dbConnection.getRepository(ConnectionEntity).findOne({ + where: { id: savedIdentity.connection!.id }, + }) + ).toBeNull() + + // check connection config + expect( + await dbConnection.getRepository(OpenIdConfigEntity).findOne({ + where: { id: savedIdentity.connection!.config.id }, + }) + ).toBeNull() + + // check identity metadata + expect( + await dbConnection.getRepository(IdentityMetadataItemEntity).findOne({ + where: { id: savedIdentity.metadata![0].id }, + }) + ).toBeNull() + }) + + it('Should not delete party when deleting identity', async (): Promise => { + const party: NonPersistedParty = { + uri: 'example.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contact: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const partyEntity: PartyEntity = partyEntityFrom(party) + const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) + + expect(savedParty).toBeDefined() + + const correlationId = 'relation_example.com' + const identity: NonPersistedIdentity = { + alias: correlationId, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.URL, + correlationId, + }, + connection: { + type: ConnectionTypeEnum.SIOPv2, + config: { + identifier: { + did: 'did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + provider: 'test_provider', + keys: [], + services: [], + }, + redirectUrl: 'https://example.com', + stateId: 'e91f3510-5ce9-42ee-83b7-fa68ff323d27', + sessionId: 'https://example.com/did:test:138d7bf8-c930-4c6e-b928-97d3a4928b01', + }, + }, + metadata: [ + { + label: 'example_label', + value: 'example_value', + }, + ], + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + identityEntity.party = savedParty + + const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) + + expect(savedIdentity).toBeDefined() + + await dbConnection.getRepository(IdentityEntity).delete({ id: savedIdentity.id }) + + // check identity + expect( + await dbConnection.getRepository(IdentityEntity).findOne({ + where: { id: savedIdentity.id }, + }) + ).toBeNull() + + // check party + expect( + await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: savedParty.id }, + }) + ).toBeDefined() + }) + + it('Should set creation date when saving party', async (): Promise => { + const party: NonPersistedParty = { + uri: 'example.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contact: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const partyEntity: PartyEntity = partyEntityFrom(party) + const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) + + const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: savedParty.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.createdAt).toBeDefined() + }) + + it('Should not update creation date when updating party', async (): Promise => { + const party: NonPersistedParty = { + uri: 'example.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contact: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const partyEntity: PartyEntity = partyEntityFrom(party) + const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) + + expect(savedParty).toBeDefined() + + const newContactFirstName = 'new_first_name' + await dbConnection.getRepository(PartyEntity).save({ + ...savedParty, + contact: { + ...savedParty.contact, + firstName: newContactFirstName, + }, + }) + + const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: savedParty.id }, + }) + + expect(fromDb).toBeDefined() + expect((fromDb?.contact).firstName).toEqual(newContactFirstName) + expect(fromDb?.createdAt).toEqual(savedParty?.createdAt) + }) + + it('Should set creation date when saving identity', async (): Promise => { + const correlationId = 'example_did' + const identity: NonPersistedIdentity = { + alias: correlationId, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId, + }, + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + await dbConnection.getRepository(IdentityEntity).save(identityEntity) + + const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ + where: { + identifier: { + correlationId, + }, + }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.createdAt).toBeDefined() + }) + + it('Should not update creation date when saving identity', async (): Promise => { + const correlationId = 'example_did' + const identity: NonPersistedIdentity = { + alias: correlationId, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId, + }, + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + const savedIdentity: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).save(identityEntity) + const newCorrelationId = 'new_example_did' + await dbConnection + .getRepository(IdentityEntity) + .save({ ...savedIdentity, identifier: { ...savedIdentity.identifier, correlationId: newCorrelationId } }) + + const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ + where: { + identifier: { + correlationId: newCorrelationId, + }, + }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.createdAt).toEqual(savedIdentity?.createdAt) + }) + + it('Should set last updated date when saving party', async (): Promise => { + const party: NonPersistedParty = { + uri: 'example.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contact: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const partyEntity: PartyEntity = partyEntityFrom(party) + const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) + + const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: savedParty.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.lastUpdatedAt).toBeDefined() + }) + + it('Should update last updated date when updating party', async (): Promise => { + const party: NonPersistedParty = { + uri: 'example.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contact: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const partyEntity: PartyEntity = partyEntityFrom(party) + const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity) + expect(savedParty).toBeDefined() + + // waiting here to get a different timestamp + await new Promise((resolve) => setTimeout(resolve, 2000)) + + const newContactFirstName = 'new_first_name' + await dbConnection.getRepository(PartyEntity).save({ + ...savedParty, + // FIXME there is still an issue when updating nested objects, the parent does not update + // https://github.com/typeorm/typeorm/issues/5378 + uri: 'new uri', // TODO remove this to trigger the bug + contact: { + ...savedParty.contact, + firstName: newContactFirstName, + }, + }) + + const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: savedParty.id }, + }) + + expect(fromDb).toBeDefined() + expect((fromDb?.contact).firstName).toEqual(newContactFirstName) + expect(fromDb?.lastUpdatedAt).not.toEqual(savedParty?.lastUpdatedAt) + }) + + it('Should set last updated date when saving party type', async (): Promise => { + const partyType: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + } + + const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) + const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) + + const fromDb: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).findOne({ + where: { id: savedPartyType.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.lastUpdatedAt).toBeDefined() + }) + + it('Should set last creation date when saving party type', async (): Promise => { + const partyType: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + } + + const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) + const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) + + const fromDb: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).findOne({ + where: { id: savedPartyType.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.createdAt).toBeDefined() + }) + + it('Should set last updated date when saving identity', async (): Promise => { + const correlationId = 'example_did' + const identity: NonPersistedIdentity = { + alias: correlationId, + roles: [IdentityRoleEnum.ISSUER, IdentityRoleEnum.VERIFIER], + identifier: { + type: CorrelationIdentifierEnum.DID, + correlationId, + }, + } + + const identityEntity: IdentityEntity = identityEntityFrom(identity) + await dbConnection.getRepository(IdentityEntity).save(identityEntity) + + const fromDb: IdentityEntity | null = await dbConnection.getRepository(IdentityEntity).findOne({ + where: { + identifier: { + correlationId, + }, + }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.lastUpdatedAt).toBeDefined() + }) + + it('Should enforce unique type and tenant id combination when saving party type', async (): Promise => { + const tenantId = 'non_unique_value' + const name = 'non_unique_value' + const partyType1: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId, + name, + } + + const partyTypeEntity1: PartyTypeEntity = partyTypeEntityFrom(partyType1) + const savedPartyType1: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity1) + + expect(savedPartyType1).toBeDefined() + + const partyType2: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId, + name, + } + + const partyTypeEntity2: PartyTypeEntity = partyTypeEntityFrom(partyType2) + await expect(dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity2)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: PartyType.type, PartyType.tenant_id' + ) + }) + + it('Should enforce unique name when saving party type', async (): Promise => { + const name = 'non_unique_value' + const partyType1: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name, + } + + const partyTypeEntity1: PartyTypeEntity = partyTypeEntityFrom(partyType1) + const savedPartyType1: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity1) + + expect(savedPartyType1).toBeDefined() + + const partyType2: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name, + } + + const partyTypeEntity2: PartyTypeEntity = partyTypeEntityFrom(partyType2) + await expect(dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity2)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: PartyType.name' + ) + }) + + it('Should enforce unique legal name when saving organization', async (): Promise => { + const legalName = 'non_unique_value' + const organization1: NonPersistedOrganization = { + legalName, + displayName: 'example_display_name', + } + + const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) + const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { + transaction: true, + }) + + expect(savedOrganization1).toBeDefined() + + const organization2: NonPersistedOrganization = { + legalName, + displayName: 'example_display_name', + } + + const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) + await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: BaseContact.legal_name' + ) + }) + + it('Should enforce unique legal name when saving organization', async (): Promise => { + const legalName = 'example_legal_name' + const organization1: NonPersistedOrganization = { + legalName, + displayName: 'example_display_name', + } + + const organizationEntity1: OrganizationEntity = organizationEntityFrom(organization1) + const savedOrganization1: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity1, { + transaction: true, + }) + + expect(savedOrganization1).toBeDefined() + + const organization2: NonPersistedOrganization = { + legalName, + displayName: 'example_display_name', + } + + const organizationEntity2: OrganizationEntity = organizationEntityFrom(organization2) + await expect(dbConnection.getRepository(OrganizationEntity).save(organizationEntity2)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: BaseContact.legal_name' + ) + }) + + it('Should save party relationship to database', async (): Promise => { + const party1: NonPersistedParty = { + uri: 'example1.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contact: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const partyEntity1: PartyEntity = partyEntityFrom(party1) + const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { + transaction: true, + }) + + expect(savedParty1).toBeDefined() + + const party2: NonPersistedParty = { + uri: 'example2.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contact: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + + const partyEntity2: PartyEntity = partyEntityFrom(party2) + const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { + transaction: true, + }) + + expect(savedParty2).toBeDefined() + + const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ + leftId: savedParty1.id, + rightId: savedParty2.id, + }) + + await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { + transaction: true, + }) + + // TODO check the relation field + const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: partyEntity1.id }, + }) + + expect(fromDb).toBeDefined() + }) + + it('Should set last updated date when saving party relationship', async (): Promise => { + const party1: NonPersistedParty = { + uri: 'example1.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contact: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const partyEntity1: PartyEntity = partyEntityFrom(party1) + const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { + transaction: true, + }) + + const party2: NonPersistedParty = { + uri: 'example2.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contact: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + + const partyEntity2: PartyEntity = partyEntityFrom(party2) + const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { + transaction: true, + }) + + const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ + leftId: savedParty1.id, + rightId: savedParty2.id, + }) + + await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { + transaction: true, + }) + + const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: partyEntity1.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.lastUpdatedAt).toBeDefined() + }) + + it('Should set creation date when saving party relationship', async (): Promise => { + const party1: NonPersistedParty = { + uri: 'example1.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contact: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const partyEntity1: PartyEntity = partyEntityFrom(party1) + const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { + transaction: true, + }) + + const party2: NonPersistedParty = { + uri: 'example2.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contact: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + + const partyEntity2: PartyEntity = partyEntityFrom(party2) + const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { + transaction: true, + }) + + const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ + leftId: savedParty1.id, + rightId: savedParty2.id, + }) + + await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { + transaction: true, + }) + + const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: partyEntity1.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.createdAt).toBeDefined() + }) + + it('Should save bidirectional party relationships to database', async (): Promise => { + const party1: NonPersistedParty = { + uri: 'example1.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contact: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const partyEntity1: PartyEntity = partyEntityFrom(party1) + const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { + transaction: true, + }) + + expect(savedParty1).toBeDefined() + + const party2: NonPersistedParty = { + uri: 'example2.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contact: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + + const partyEntity2: PartyEntity = partyEntityFrom(party2) + const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { + transaction: true, + }) + + expect(savedParty2).toBeDefined() + + const relationship1: PartyRelationshipEntity = partyRelationshipEntityFrom({ + leftId: savedParty1.id, + rightId: savedParty2.id, + }) + + const savedRelationship1: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship1, { + transaction: true, + }) + + expect(savedRelationship1).toBeDefined() + + const relationship2: PartyRelationshipEntity = partyRelationshipEntityFrom({ + leftId: savedParty2.id, + rightId: savedParty1.id, + }) + + const savedRelationship2: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship2, { + transaction: true, + }) + + expect(savedRelationship2).toBeDefined() + + const fromDb: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).findOne({ + where: { id: savedRelationship2.id }, + }) + + expect(fromDb).toBeDefined() + }) + + it('Should enforce unique owner combination for party relationship', async (): Promise => { + const party1: NonPersistedParty = { + uri: 'example1.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contact: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const partyEntity1: PartyEntity = partyEntityFrom(party1) + const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { + transaction: true, + }) + + expect(savedParty1).toBeDefined() + + const party2: NonPersistedParty = { + uri: 'example2.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contact: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + + const partyEntity2: PartyEntity = partyEntityFrom(party2) + const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { + transaction: true, + }) + + expect(savedParty2).toBeDefined() + + const relationship1: PartyRelationshipEntity = partyRelationshipEntityFrom({ + leftId: savedParty1.id, + rightId: savedParty2.id, + }) + + const savedRelationship1: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship1, { + transaction: true, + }) + + expect(savedRelationship1).toBeDefined() + + const relationship2: PartyRelationshipEntity = partyRelationshipEntityFrom({ + leftId: savedParty1.id, + rightId: savedParty2.id, + }) + + await expect(dbConnection.getRepository(PartyRelationshipEntity).save(relationship2)).rejects.toThrowError( + 'SQLITE_CONSTRAINT: UNIQUE constraint failed: PartyRelationship.left_id, PartyRelationship.right_id' + ) + }) + + it('Should save party type to database', async (): Promise => { + const partyType: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + } + + const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) + const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) + + const fromDb: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).findOne({ + where: { id: savedPartyType.id }, + }) + + expect(fromDb).toBeDefined() + }) + + it('Should save person to database', async (): Promise => { + const person: NonPersistedNaturalPerson = { + firstName: 'example_first_name', + lastName: 'lastName2', + displayName: 'displayName', + } + + const personEntity: NaturalPersonEntity = naturalPersonEntityFrom(person) + const savedPerson: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).save(personEntity, { + transaction: true, + }) + + const fromDb: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).findOne({ + where: { id: savedPerson.id }, + }) + + expect(fromDb).toBeDefined() + }) + + it('Should set last updated date when saving person', async (): Promise => { + const person: NonPersistedNaturalPerson = { + firstName: 'example_first_name', + lastName: 'lastName2', + displayName: 'displayName', + } + + const personEntity: NaturalPersonEntity = naturalPersonEntityFrom(person) + const savedPerson: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).save(personEntity, { + transaction: true, + }) + + const fromDb: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).findOne({ + where: { id: savedPerson.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.lastUpdatedAt).toBeDefined() + }) + + it('Should set creation date when saving person', async (): Promise => { + const person: NonPersistedNaturalPerson = { + firstName: 'example_first_name', + lastName: 'lastName2', + displayName: 'displayName', + } + + const personEntity: NaturalPersonEntity = naturalPersonEntityFrom(person) + const savedPerson: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).save(personEntity, { + transaction: true, + }) + + const fromDb: NaturalPersonEntity | null = await dbConnection.getRepository(NaturalPersonEntity).findOne({ + where: { id: savedPerson.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.createdAt).toBeDefined() + }) + + it('Should save organization to database', async (): Promise => { + const organization: NonPersistedOrganization = { + legalName: 'example_legal_name', + displayName: 'example_display_name', + } + + const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) + const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { + transaction: true, + }) + + const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ + where: { id: savedOrganization.id }, + }) + + expect(fromDb).toBeDefined() + }) + + it('Should set last updated date when saving organization', async (): Promise => { + const organization: NonPersistedOrganization = { + legalName: 'example_legal_name', + displayName: 'example_display_name', + } + + const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) + const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { + transaction: true, + }) + + const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ + where: { id: savedOrganization.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.lastUpdatedAt).toBeDefined() + }) + + it('Should set creation date when saving organization', async (): Promise => { + const organization: NonPersistedOrganization = { + legalName: 'example_legal_name', + displayName: 'example_display_name', + } + + const organizationEntity: OrganizationEntity = organizationEntityFrom(organization) + const savedOrganization: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).save(organizationEntity, { + transaction: true, + }) + + const fromDb: OrganizationEntity | null = await dbConnection.getRepository(OrganizationEntity).findOne({ + where: { id: savedOrganization.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.createdAt).toBeDefined() + }) + + it('Should get party based on person information', async (): Promise => { + const firstName = 'example_first_name' + const party: NonPersistedParty = { + uri: 'example.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contact: { + firstName, + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const partyEntity: PartyEntity = partyEntityFrom(party) + await dbConnection.getRepository(PartyEntity).save(partyEntity, { + transaction: true, + }) + + const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { + contact: { + firstName, + } as FindOptionsWhere, //NaturalPersonEntity | OrganizationEntity + }, + }) + + expect(fromDb).toBeDefined() + }) + + it('Should get party based on organization information', async (): Promise => { + const legalName = 'example_legal_name' + const party: NonPersistedParty = { + uri: 'example.com', + partyType: { + type: PartyTypeEnum.ORGANIZATION, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contact: { + legalName, + displayName: 'example_display_name', + }, + } + + const partyEntity: PartyEntity = partyEntityFrom(party) + await dbConnection.getRepository(PartyEntity).save(partyEntity, { + transaction: true, + }) + + const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { + contact: { + legalName, + } as FindOptionsWhere, //NaturalPersonEntity | OrganizationEntity + }, + }) + + expect(fromDb).toBeDefined() + }) + + it("Should enforce unique party id's for relationship sides", async (): Promise => { + const party: NonPersistedParty = { + uri: 'example.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contact: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const partyEntity: PartyEntity = partyEntityFrom(party) + const savedParty: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity, { + transaction: true, + }) + + expect(savedParty).toBeDefined() + + const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ + leftId: savedParty.id, + rightId: savedParty.id, + }) + + await expect(dbConnection.getRepository(PartyRelationshipEntity).save(relationship)).rejects.toThrowError( + 'Cannot use the same id for both sides of the relationship' + ) + }) + + it('Should delete party relationship', async (): Promise => { + const party1: NonPersistedParty = { + uri: 'example1.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name1', + }, + contact: { + firstName: 'example_first_name1', + middleName: 'example_middle_name1', + lastName: 'example_last_name1', + displayName: 'example_display_name1', + }, + } + + const partyEntity1: PartyEntity = partyEntityFrom(party1) + const savedParty1: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity1, { + transaction: true, + }) + + expect(savedParty1).toBeDefined() + + const party2: NonPersistedParty = { + uri: 'example2.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d288', + name: 'example_name2', + }, + contact: { + firstName: 'example_first_name2', + middleName: 'example_middle_name2', + lastName: 'example_last_name2', + displayName: 'example_display_name2', + }, + } + + const partyEntity2: PartyEntity = partyEntityFrom(party2) + const savedParty2: PartyEntity = await dbConnection.getRepository(PartyEntity).save(partyEntity2, { + transaction: true, + }) + + expect(savedParty2).toBeDefined() + + const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({ + leftId: savedParty1.id, + rightId: savedParty2.id, + }) + + const savedRelationship: PartyRelationshipEntity | null = await dbConnection.getRepository(PartyRelationshipEntity).save(relationship, { + transaction: true, + }) + + expect(savedRelationship).toBeDefined() + + await dbConnection.getRepository(PartyRelationshipEntity).delete({ id: savedRelationship.id }) + + await expect( + await dbConnection.getRepository(PartyRelationshipEntity).findOne({ + where: { id: savedRelationship.id }, + }) + ).toBeNull() + }) + + it('Should delete party type', async (): Promise => { + const partyType: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + } + + const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) + const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) + + expect(savedPartyType).toBeDefined() + + await dbConnection.getRepository(PartyTypeEntity).delete({ id: savedPartyType.id }) + + await expect( + await dbConnection.getRepository(PartyTypeEntity).findOne({ + where: { id: savedPartyType.id }, + }) + ).toBeNull() + }) + + it('Should not be able to remove party type when used by parties', async (): Promise => { + const party: NonPersistedParty = { + uri: 'example.com', + partyType: { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + }, + contact: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const partyEntity: PartyEntity = partyEntityFrom(party) + const savedParty: PartyEntity | null = await dbConnection.getRepository(PartyEntity).save(partyEntity, { + transaction: true, + }) + + expect(savedParty).toBeDefined() + + await expect(dbConnection.getRepository(PartyTypeEntity).delete({ id: savedParty.partyType.id })).rejects.toThrowError( + 'FOREIGN KEY constraint failed' + ) + }) + + it('Should save party with existing party type', async (): Promise => { + const partyType: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + } + + const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) + const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) + + const party: NonPersistedParty = { + uri: 'example.com', + partyType: savedPartyType, + contact: { + firstName: 'example_first_name', + middleName: 'example_middle_name', + lastName: 'example_last_name', + displayName: 'example_display_name', + }, + } + + const partyEntity: PartyEntity = partyEntityFrom(party) + partyEntity.partyType = savedPartyType + await dbConnection.getRepository(PartyEntity).save(partyEntity, { + transaction: true, + }) + + const fromDb: PartyEntity | null = await dbConnection.getRepository(PartyEntity).findOne({ + where: { id: partyEntity.id }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.partyType).toBeDefined() + expect(fromDb?.partyType.id).toEqual(savedPartyType.id) + expect(fromDb?.partyType.type).toEqual(savedPartyType.type) + expect(fromDb?.partyType.tenantId).toEqual(savedPartyType.tenantId) + expect(fromDb?.partyType.name).toEqual(savedPartyType.name) + }) + + it('Should not update creation date when saving party type', async (): Promise => { + const partyType: NonPersistedPartyType = { + type: PartyTypeEnum.NATURAL_PERSON, + tenantId: '0605761c-4113-4ce5-a6b2-9cbae2f9d289', + name: 'example_name', + } + + const partyTypeEntity: PartyTypeEntity = partyTypeEntityFrom(partyType) + const savedPartyType: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).save(partyTypeEntity) + await dbConnection.getRepository(PartyTypeEntity).save({ ...savedPartyType, type: PartyTypeEnum.ORGANIZATION }) + + const fromDb: PartyTypeEntity | null = await dbConnection.getRepository(PartyTypeEntity).findOne({ + where: { + type: PartyTypeEnum.ORGANIZATION, + }, + }) + + expect(fromDb).toBeDefined() + expect(fromDb?.createdAt).toEqual(savedPartyType?.createdAt) + }) }) From 05d6cc5c6f9885f5ff241ce336382bccd34cab7c Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Tue, 5 Sep 2023 11:45:57 +0200 Subject: [PATCH 26/35] DPP-1 cleanup --- .../shared/contactManagerAgentLogic.ts | 27 ++-- .../src/agent/ContactManager.ts | 13 +- .../src/types/IContactManager.ts | 10 +- .../src/__tests__/contact.entities.test.ts | 2 +- .../src/__tests__/contact.store.test.ts | 37 ++--- .../src/entities/contact/IdentityEntity.ts | 2 - .../src/entities/contact/PartyEntity.ts | 4 +- .../src/entities/contact/PartyTypeEntity.ts | 2 +- .../src/migrations/generic/index.ts | 4 +- .../postgres/1690925872592-CreateContacts.ts | 83 ++++++++--- .../sqlite/1690925872693-CreateContacts.ts | 140 +++++++++++++----- .../types/contact/IAbstractContactStore.ts | 3 +- 12 files changed, 213 insertions(+), 114 deletions(-) diff --git a/packages/contact-manager/__tests__/shared/contactManagerAgentLogic.ts b/packages/contact-manager/__tests__/shared/contactManagerAgentLogic.ts index e6a6b3c7e..a4628a83e 100644 --- a/packages/contact-manager/__tests__/shared/contactManagerAgentLogic.ts +++ b/packages/contact-manager/__tests__/shared/contactManagerAgentLogic.ts @@ -24,7 +24,8 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro await testContext.setup() agent = testContext.getAgent() - const contact: AddContactArgs = { //NonPersistedParty + const contact: AddContactArgs = { + //NonPersistedParty firstName: 'default_first_name', middleName: 'default_middle_name', lastName: 'default_last_name', @@ -137,7 +138,8 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro }) it('should add contact', async (): Promise => { - const contact: AddContactArgs = { //NonPersistedParty + const contact: AddContactArgs = { + //NonPersistedParty firstName: 'new_first_name', middleName: 'new_middle_name', lastName: 'new_last_name', @@ -156,10 +158,12 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro // }, uri: 'example.com', // TODO create better tests for electronicAddresses - electronicAddresses: [{ - type: 'email', - electronicAddress: 'sphereon@sphereon.com' - }] + electronicAddresses: [ + { + type: 'email', + electronicAddress: 'sphereon@sphereon.com', + }, + ], } const result: Party = await agent.cmAddContact(contact) @@ -303,7 +307,8 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro }) it('should add relationship', async (): Promise => { - const contact: AddContactArgs = { //NonPersistedParty + const contact: AddContactArgs = { + //NonPersistedParty firstName: 'relation_first_name', middleName: 'relation_middle_name', lastName: 'relation_last_name', @@ -346,10 +351,7 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro // TODO why does this filter not work on only first name? const args2: GetPartiesArgs = { - filter: [ - { contact: { firstName: 'relation_first_name' } }, - { contact: { middleName: 'relation_middle_name' } }, - ], + filter: [{ contact: { firstName: 'relation_first_name' } }, { contact: { middleName: 'relation_middle_name' } }], } const result: Array = await agent.cmGetContacts(args2) @@ -360,7 +362,8 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro }) it('should remove relationship', async (): Promise => { - const contact: AddContactArgs = { //NonPersistedParty + const contact: AddContactArgs = { + //NonPersistedParty firstName: 'remove_relation_first_name', middleName: 'remove_relation_middle_name', lastName: 'remove_relation_last_name', diff --git a/packages/contact-manager/src/agent/ContactManager.ts b/packages/contact-manager/src/agent/ContactManager.ts index b8ac7b718..c522102e5 100644 --- a/packages/contact-manager/src/agent/ContactManager.ts +++ b/packages/contact-manager/src/agent/ContactManager.ts @@ -29,7 +29,7 @@ import { Party as Contact, Identity, PartyRelationship as ContactRelationship, - PartyType as ContactType + PartyType as ContactType, } from '@sphereon/ssi-sdk.data-store' /** @@ -79,16 +79,17 @@ export class ContactManager implements IAgentPlugin { /** {@inheritDoc IContactManager.cmAddContact} */ private async cmAddContact(args: AddContactArgs, context: RequiredContext): Promise { // TODO this needs to be improved - const contact = ('firstName' in args && 'lastName' in args) - ? { firstName: args.firstName, middleName: args.middleName, lastName: args.lastName, displayName: args.displayName} - : { legalName: args.legalName, displayName: args.displayName } + const contact = + 'firstName' in args && 'lastName' in args + ? { firstName: args.firstName, middleName: args.middleName, lastName: args.lastName, displayName: args.displayName } + : { legalName: args.legalName, displayName: args.displayName } return this.store.addParty({ uri: args.uri, partyType: args.contactType, contact, identities: args.identities, - electronicAddresses: args.electronicAddresses + electronicAddresses: args.electronicAddresses, }) } @@ -169,7 +170,7 @@ export class ContactManager implements IAgentPlugin { /** {@inheritDoc IContactManager.cmUpdateContactType} */ private async cmUpdateContactType(args: UpdateContactTypeArgs, context: RequiredContext): Promise { - return this.store.updatePartyType({partyType: args.contactType}) + return this.store.updatePartyType({ partyType: args.contactType }) } /** {@inheritDoc IContactManager.cmRemoveContactType} */ diff --git a/packages/contact-manager/src/types/IContactManager.ts b/packages/contact-manager/src/types/IContactManager.ts index 752ffb3c5..ad5d4b044 100644 --- a/packages/contact-manager/src/types/IContactManager.ts +++ b/packages/contact-manager/src/types/IContactManager.ts @@ -11,7 +11,8 @@ import { FindPartyArgs as FindContactArgs, PartyRelationship as ContactRelationship, PartyType as ContactType, - Party as Contact, NonPersistedParty + Party as Contact, + NonPersistedParty, } from '@sphereon/ssi-sdk.data-store' export interface IContactManager extends IPluginMethodMap { @@ -51,9 +52,10 @@ export type GetContactsArgs = { // identities?: Array // } & NonPersistedNaturalPerson | NonPersistedOrganization -export type AddContactArgs = Omit & NonPersistedContact & { - contactType: NonPersistedContactType -} +export type AddContactArgs = Omit & + NonPersistedContact & { + contactType: NonPersistedContactType + } export type UpdateContactArgs = { contact: Contact diff --git a/packages/data-store/src/__tests__/contact.entities.test.ts b/packages/data-store/src/__tests__/contact.entities.test.ts index 99d6c101e..e79eb1910 100644 --- a/packages/data-store/src/__tests__/contact.entities.test.ts +++ b/packages/data-store/src/__tests__/contact.entities.test.ts @@ -1,4 +1,4 @@ -import { DataSource, FindOptionsWhere} from 'typeorm' +import { DataSource, FindOptionsWhere } from 'typeorm' import { DataStoreContactEntities, DataStoreMigrations } from '../index' import { NaturalPersonEntity } from '../entities/contact/NaturalPersonEntity' diff --git a/packages/data-store/src/__tests__/contact.store.test.ts b/packages/data-store/src/__tests__/contact.store.test.ts index 7c2055d03..ad3931718 100644 --- a/packages/data-store/src/__tests__/contact.store.test.ts +++ b/packages/data-store/src/__tests__/contact.store.test.ts @@ -1,6 +1,6 @@ import { DataSource } from 'typeorm' -import { DataStoreContactEntities } from '../index' +import { DataStoreMigrations, DataStoreContactEntities } from '../index' import { ContactStore } from '../contact/ContactStore' import { IdentityRoleEnum, @@ -29,32 +29,17 @@ describe('Contact store tests', (): void => { dbConnection = await new DataSource({ type: 'sqlite', database: ':memory:', - //logging: 'all', + logging: 'all', migrationsRun: false, - // migrations: DataStoreMigrations, - synchronize: true, //false + migrations: DataStoreMigrations, + synchronize: false, entities: DataStoreContactEntities, }).initialize() - // await dbConnection.runMigrations() - // expect(await dbConnection.showMigrations()).toBeFalsy() + await dbConnection.runMigrations() + expect(await dbConnection.showMigrations()).toBeFalsy() contactStore = new ContactStore(dbConnection) }) - // beforeEach(async (): Promise => { - // dbConnection = await new DataSource({ - // type: 'sqlite', - // database: ':memory:', - // //logging: 'all', - // migrationsRun: false, - // migrations: DataStoreMigrations, - // synchronize: false, - // entities: DataStoreContactEntities, - // }).initialize() - // await dbConnection.runMigrations() - // expect(await dbConnection.showMigrations()).toBeFalsy() - // contactStore = new ContactStore(dbConnection) - // }) - afterEach(async (): Promise => { await (await dbConnection).destroy() }) @@ -217,10 +202,12 @@ describe('Contact store tests', (): void => { }, }, ], - electronicAddresses: [{ - type: 'email', - electronicAddress: 'sphereon@sphereon.com' - }] + electronicAddresses: [ + { + type: 'email', + electronicAddress: 'sphereon@sphereon.com', + }, + ], } const savedParty: Party = await contactStore.addParty(party) expect(savedParty).toBeDefined() diff --git a/packages/data-store/src/entities/contact/IdentityEntity.ts b/packages/data-store/src/entities/contact/IdentityEntity.ts index 72dccc41a..e3db4ba5c 100644 --- a/packages/data-store/src/entities/contact/IdentityEntity.ts +++ b/packages/data-store/src/entities/contact/IdentityEntity.ts @@ -72,8 +72,6 @@ export class IdentityEntity extends BaseEntity { }) party!: PartyEntity - // TODO name should be party_id - // TODO add reverse side column name to owning side party @Column({ name: 'partyId', nullable: true }) partyId!: string diff --git a/packages/data-store/src/entities/contact/PartyEntity.ts b/packages/data-store/src/entities/contact/PartyEntity.ts index fe41d1572..db7adc9de 100644 --- a/packages/data-store/src/entities/contact/PartyEntity.ts +++ b/packages/data-store/src/entities/contact/PartyEntity.ts @@ -35,7 +35,7 @@ export class PartyEntity extends BaseEntity { eager: true, nullable: false, }) - @JoinColumn({ name: 'identity_id' }) // TODO check this in the db file + @JoinColumn({ name: 'identity_id' }) identities!: Array @OneToMany(() => ElectronicAddressEntity, (electronicAddress: ElectronicAddressEntity) => electronicAddress.party, { @@ -44,7 +44,7 @@ export class PartyEntity extends BaseEntity { eager: true, nullable: false, }) - @JoinColumn({ name: 'electronic_address_id' }) // TODO check this in the db file + @JoinColumn({ name: 'electronic_address_id' }) electronicAddresses!: Array @ManyToOne(() => PartyTypeEntity, (contactType: PartyTypeEntity) => contactType.parties, { diff --git a/packages/data-store/src/entities/contact/PartyTypeEntity.ts b/packages/data-store/src/entities/contact/PartyTypeEntity.ts index 058ea2085..472628203 100644 --- a/packages/data-store/src/entities/contact/PartyTypeEntity.ts +++ b/packages/data-store/src/entities/contact/PartyTypeEntity.ts @@ -6,7 +6,7 @@ import { IsNonEmptyStringConstraint } from '../validators' import { getConstraint } from '../../utils/ValidatorUtils' @Entity('PartyType') -@Index('IDX_PartyType_type_tenant_id', ['type', 'tenantId'], { unique: true }) // TODO use name for migrations +@Index('IDX_PartyType_type_tenant_id', ['type', 'tenantId'], { unique: true }) export class PartyTypeEntity { @PrimaryGeneratedColumn('uuid') id!: string diff --git a/packages/data-store/src/migrations/generic/index.ts b/packages/data-store/src/migrations/generic/index.ts index f81e36086..cb9034231 100644 --- a/packages/data-store/src/migrations/generic/index.ts +++ b/packages/data-store/src/migrations/generic/index.ts @@ -1,6 +1,6 @@ import { CreateContacts1659463079429 } from './1-CreateContacts' import { CreateContacts1690925872318 } from './2-CreateContacts' -//import { CreateIssuanceBranding1659463079429 } from './1-CreateIssuanceBranding' +import { CreateIssuanceBranding1659463079429 } from './1-CreateIssuanceBranding' /** * The migrations array that SHOULD be used when initializing a TypeORM database connection. @@ -9,4 +9,4 @@ import { CreateContacts1690925872318 } from './2-CreateContacts' * * @public */ -export const DataStoreMigrations = [CreateContacts1659463079429, CreateContacts1690925872318] //CreateIssuanceBranding1659463079429 +export const DataStoreMigrations = [CreateContacts1659463079429, CreateContacts1690925872318, CreateIssuanceBranding1659463079429] diff --git a/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts b/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts index dbd74b480..6ed56b57a 100644 --- a/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts +++ b/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts @@ -11,40 +11,77 @@ export class CreateContacts1690925872592 implements MigrationInterface { await queryRunner.query(`ALTER TABLE "CorrelationIdentifier" RENAME COLUMN "identityId" TO "identity_id"`) await queryRunner.query(`ALTER TABLE "Connection" RENAME COLUMN "identityId" TO "identity_id"`) await queryRunner.query(`CREATE TYPE "public"."PartyType_type_enum" AS ENUM('naturalPerson', 'organization')`) - await queryRunner.query(`CREATE TABLE "PartyType" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "type" "public"."PartyType_type_enum" NOT NULL, "name" character varying(255) NOT NULL, "description" character varying(255), "tenant_id" character varying(255) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "UQ_PartyType_name" UNIQUE ("name"), CONSTRAINT "PK_PartyType_id" PRIMARY KEY ("id"))`) + await queryRunner.query( + `CREATE TABLE "PartyType" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "type" "public"."PartyType_type_enum" NOT NULL, "name" character varying(255) NOT NULL, "description" character varying(255), "tenant_id" character varying(255) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "UQ_PartyType_name" UNIQUE ("name"), CONSTRAINT "PK_PartyType_id" PRIMARY KEY ("id"))` + ) await queryRunner.query(`CREATE UNIQUE INDEX "IDX_PartyType_type_tenant_id" ON "PartyType" ("type", "tenant_id")`) - await queryRunner.query(`CREATE TABLE "BaseContact" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), "legal_name" character varying(255), "display_name" character varying(255), "first_name" character varying(255), "middle_name" character varying(255), "last_name" character varying(255), "type" character varying NOT NULL, "party_id" uuid, CONSTRAINT "UQ_BaseContact_legal_name" UNIQUE ("legal_name"), CONSTRAINT "REL_BaseContact_party_id" UNIQUE ("party_id"), CONSTRAINT "PK_BaseContact_id" PRIMARY KEY ("id"))`) + await queryRunner.query( + `CREATE TABLE "BaseContact" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), "legal_name" character varying(255), "display_name" character varying(255), "first_name" character varying(255), "middle_name" character varying(255), "last_name" character varying(255), "type" character varying NOT NULL, "party_id" uuid, CONSTRAINT "UQ_BaseContact_legal_name" UNIQUE ("legal_name"), CONSTRAINT "REL_BaseContact_party_id" UNIQUE ("party_id"), CONSTRAINT "PK_BaseContact_id" PRIMARY KEY ("id"))` + ) await queryRunner.query(`CREATE INDEX "IDX_BaseContact_type" ON "BaseContact" ("type")`) - await queryRunner.query(`CREATE TABLE "PartyRelationship" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "left_id" uuid NOT NULL, "right_id" uuid NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_PartyRelationship_id" PRIMARY KEY ("id"))`) + await queryRunner.query( + `CREATE TABLE "PartyRelationship" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "left_id" uuid NOT NULL, "right_id" uuid NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_PartyRelationship_id" PRIMARY KEY ("id"))` + ) await queryRunner.query(`CREATE UNIQUE INDEX "IDX_PartyRelationship_left_right" ON "PartyRelationship" ("left_id", "right_id")`) - await queryRunner.query(`CREATE TABLE "ElectronicAddress" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "type" character varying(255) NOT NULL, "electronic_address" character varying(255) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), "partyId" uuid, CONSTRAINT "PK_ElectronicAddress_id" PRIMARY KEY ("id"))`) - await queryRunner.query(`CREATE TABLE "Party" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "uri" character varying(255) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), "party_type_id" uuid NOT NULL, CONSTRAINT "PK_Party_id" PRIMARY KEY ("id"))`) - await queryRunner.query(`CREATE TABLE "BaseConfig" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "identifier" character varying(255), "redirect_url" character varying(255), "session_id" character varying(255), "client_id" character varying(255), "client_secret" character varying(255), "scopes" text, "issuer" character varying(255), "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "type" character varying NOT NULL, "connection_id" uuid, CONSTRAINT "REL_BaseConfig_connection_id" UNIQUE ("connection_id"), CONSTRAINT "PK_BaseConfig_id" PRIMARY KEY ("id"))`) + await queryRunner.query( + `CREATE TABLE "ElectronicAddress" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "type" character varying(255) NOT NULL, "electronic_address" character varying(255) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), "partyId" uuid, CONSTRAINT "PK_ElectronicAddress_id" PRIMARY KEY ("id"))` + ) + await queryRunner.query( + `CREATE TABLE "Party" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "uri" character varying(255) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), "party_type_id" uuid NOT NULL, CONSTRAINT "PK_Party_id" PRIMARY KEY ("id"))` + ) + await queryRunner.query( + `CREATE TABLE "BaseConfig" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "identifier" character varying(255), "redirect_url" character varying(255), "session_id" character varying(255), "client_id" character varying(255), "client_secret" character varying(255), "scopes" text, "issuer" character varying(255), "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "type" character varying NOT NULL, "connection_id" uuid, CONSTRAINT "REL_BaseConfig_connection_id" UNIQUE ("connection_id"), CONSTRAINT "PK_BaseConfig_id" PRIMARY KEY ("id"))` + ) await queryRunner.query(`CREATE INDEX "IDX_BaseConfig_type" ON "BaseConfig" ("type")`) - // await queryRunner.query(`ALTER TABLE "Identity" DROP COLUMN "contactId"`) // TODO we need rename this column - // await queryRunner.query(`ALTER TABLE "Identity" ADD "partyId" uuid`) await queryRunner.query(`ALTER TABLE "Identity" RENAME COLUMN "contactId" TO "partyId"`) - await queryRunner.query(`ALTER TABLE "Identity" ALTER COLUMN "roles" SET NOT NULL`) - await queryRunner.query(`ALTER TABLE "CorrelationIdentifier" ADD CONSTRAINT "FK_CorrelationIdentifier_identity_id" FOREIGN KEY ("identity_id") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) - await queryRunner.query(`ALTER TABLE "IdentityMetadata" ADD CONSTRAINT "FK_IdentityMetadata_identityId" FOREIGN KEY ("identityId") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) - await queryRunner.query(`ALTER TABLE "BaseContact" ADD CONSTRAINT "FK_BaseContact_party_id" FOREIGN KEY ("party_id") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) - await queryRunner.query(`ALTER TABLE "PartyRelationship" ADD CONSTRAINT "FK_PartyRelationship_left_id" FOREIGN KEY ("left_id") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) - await queryRunner.query(`ALTER TABLE "PartyRelationship" ADD CONSTRAINT "FK_PartyRelationship_right_id" FOREIGN KEY ("right_id") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) - await queryRunner.query(`ALTER TABLE "ElectronicAddress" ADD CONSTRAINT "FK_ElectronicAddress_partyId" FOREIGN KEY ("partyId") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) - await queryRunner.query(`ALTER TABLE "Party" ADD CONSTRAINT "FK_Party_party_type_id" FOREIGN KEY ("party_type_id") REFERENCES "PartyType"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) - await queryRunner.query(`ALTER TABLE "Identity" ADD CONSTRAINT "FK_Identity_partyId" FOREIGN KEY ("partyId") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) - await queryRunner.query(`ALTER TABLE "Connection" ADD CONSTRAINT "FK_Connection_identity_id" FOREIGN KEY ("identity_id") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) - await queryRunner.query(`ALTER TABLE "BaseConfig" ADD CONSTRAINT "FK_BaseConfig_connection_id" FOREIGN KEY ("connection_id") REFERENCES "Connection"("id") ON DELETE CASCADE ON UPDATE NO ACTION`) + await queryRunner.query( + `ALTER TABLE "CorrelationIdentifier" ADD CONSTRAINT "FK_CorrelationIdentifier_identity_id" FOREIGN KEY ("identity_id") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + ) + await queryRunner.query( + `ALTER TABLE "IdentityMetadata" ADD CONSTRAINT "FK_IdentityMetadata_identityId" FOREIGN KEY ("identityId") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + ) + await queryRunner.query( + `ALTER TABLE "BaseContact" ADD CONSTRAINT "FK_BaseContact_party_id" FOREIGN KEY ("party_id") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + ) + await queryRunner.query( + `ALTER TABLE "PartyRelationship" ADD CONSTRAINT "FK_PartyRelationship_left_id" FOREIGN KEY ("left_id") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + ) + await queryRunner.query( + `ALTER TABLE "PartyRelationship" ADD CONSTRAINT "FK_PartyRelationship_right_id" FOREIGN KEY ("right_id") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + ) + await queryRunner.query( + `ALTER TABLE "ElectronicAddress" ADD CONSTRAINT "FK_ElectronicAddress_partyId" FOREIGN KEY ("partyId") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + ) + await queryRunner.query( + `ALTER TABLE "Party" ADD CONSTRAINT "FK_Party_party_type_id" FOREIGN KEY ("party_type_id") REFERENCES "PartyType"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ) + await queryRunner.query( + `ALTER TABLE "Identity" ADD CONSTRAINT "FK_Identity_partyId" FOREIGN KEY ("partyId") REFERENCES "Party"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + ) + await queryRunner.query( + `ALTER TABLE "Connection" ADD CONSTRAINT "FK_Connection_identity_id" FOREIGN KEY ("identity_id") REFERENCES "Identity"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + ) + await queryRunner.query( + `ALTER TABLE "BaseConfig" ADD CONSTRAINT "FK_BaseConfig_connection_id" FOREIGN KEY ("connection_id") REFERENCES "Connection"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + ) // migrate existing data await queryRunner.query(`ALTER TABLE "CorrelationIdentifier" RENAME CONSTRAINT "UQ_Correlation_id" TO "UQ_CorrelationIdentifier_correlation_id"`) await queryRunner.query(`ALTER TABLE "Identity" RENAME CONSTRAINT "UQ_Identity_Alias" TO "UQ_Identity_alias"`) - await queryRunner.query(`INSERT INTO "BaseConfig"("id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id") SELECT "id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connectionId" FROM "BaseConfigEntity"`) + await queryRunner.query( + `INSERT INTO "BaseConfig"("id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id") SELECT "id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connectionId" FROM "BaseConfigEntity"` + ) await queryRunner.query(`DROP TABLE "BaseConfigEntity"`) - await queryRunner.query(`INSERT INTO "PartyType"(id, type, name, description, tenant_id, created_at, last_updated_at) VALUES ('3875c12e-fdaa-4ef6-a340-c936e054b627', 'organization', 'Sphereon_default_type', 'sphereon_default_organization', '95e09cfc-c974-4174-86aa-7bf1d5251fb4', now(), now())`) - await queryRunner.query(`INSERT INTO "Party"(id, uri, created_at, last_updated_at, party_type_id) SELECT id, uri, created_at, last_updated_at, '3875c12e-fdaa-4ef6-a340-c936e054b627' FROM "Contact"`) - await queryRunner.query(`INSERT INTO "BaseContact"(id, legal_name, display_name, party_id, created_at, last_updated_at, type) SELECT id, name, alias, id, created_at, last_updated_at, 'Organization' FROM "Contact"`) + await queryRunner.query( + `INSERT INTO "PartyType"(id, type, name, description, tenant_id, created_at, last_updated_at) VALUES ('3875c12e-fdaa-4ef6-a340-c936e054b627', 'organization', 'Sphereon_default_type', 'sphereon_default_organization', '95e09cfc-c974-4174-86aa-7bf1d5251fb4', now(), now())` + ) + await queryRunner.query( + `INSERT INTO "Party"(id, uri, created_at, last_updated_at, party_type_id) SELECT id, uri, created_at, last_updated_at, '3875c12e-fdaa-4ef6-a340-c936e054b627' FROM "Contact"` + ) + await queryRunner.query( + `INSERT INTO "BaseContact"(id, legal_name, display_name, party_id, created_at, last_updated_at, type) SELECT id, name, alias, id, created_at, last_updated_at, 'Organization' FROM "Contact"` + ) await queryRunner.query(`DROP TABLE "Contact"`) } diff --git a/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts b/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts index 155724f8b..77df025f7 100644 --- a/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts +++ b/packages/data-store/src/migrations/sqlite/1690925872693-CreateContacts.ts @@ -4,85 +4,155 @@ export class CreateContacts1690925872693 implements MigrationInterface { name = 'CreateContacts1690925872693' public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identityId" varchar, CONSTRAINT "REL_CorrelationIdentifier_identityId" UNIQUE ("identityId"), CONSTRAINT "UQ_CorrelationIdentifier_correlation_id" UNIQUE ("correlation_id"))`) - await queryRunner.query(`INSERT INTO "temporary_CorrelationIdentifier"("id", "type", "correlation_id", "identityId") SELECT "id", "type", "correlation_id", "identityId" FROM "CorrelationIdentifier"`) + await queryRunner.query( + `CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identityId" varchar, CONSTRAINT "REL_CorrelationIdentifier_identityId" UNIQUE ("identityId"), CONSTRAINT "UQ_CorrelationIdentifier_correlation_id" UNIQUE ("correlation_id"))` + ) + await queryRunner.query( + `INSERT INTO "temporary_CorrelationIdentifier"("id", "type", "correlation_id", "identityId") SELECT "id", "type", "correlation_id", "identityId" FROM "CorrelationIdentifier"` + ) await queryRunner.query(`DROP TABLE "CorrelationIdentifier"`) await queryRunner.query(`ALTER TABLE "temporary_CorrelationIdentifier" RENAME TO "CorrelationIdentifier"`) - await queryRunner.query(`CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Identity_alias" UNIQUE ("alias"))`) - await queryRunner.query(`INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"`) + await queryRunner.query( + `CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "contactId" varchar, CONSTRAINT "UQ_Identity_alias" UNIQUE ("alias"))` + ) + await queryRunner.query( + `INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "contactId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"` + ) await queryRunner.query(`DROP TABLE "Identity"`) await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) - await queryRunner.query(`CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identityId" varchar, CONSTRAINT "REL_Connection_identityId" UNIQUE ("identityId"))`) + await queryRunner.query( + `CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identityId" varchar, CONSTRAINT "REL_Connection_identityId" UNIQUE ("identityId"))` + ) await queryRunner.query(`INSERT INTO "temporary_Connection"("id", "type", "identityId") SELECT "id", "type", "identityId" FROM "Connection"`) await queryRunner.query(`DROP TABLE "Connection"`) await queryRunner.query(`ALTER TABLE "temporary_Connection" RENAME TO "Connection"`) - await queryRunner.query(`CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identity_id" varchar, CONSTRAINT "REL_CorrelationIdentifier_identityId" UNIQUE ("identity_id"), CONSTRAINT "UQ_CorrelationIdentifier_correlation_id" UNIQUE ("correlation_id"))`) - await queryRunner.query(`INSERT INTO "temporary_CorrelationIdentifier"("id", "type", "correlation_id", "identity_id") SELECT "id", "type", "correlation_id", "identityId" FROM "CorrelationIdentifier"`) + await queryRunner.query( + `CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identity_id" varchar, CONSTRAINT "REL_CorrelationIdentifier_identityId" UNIQUE ("identity_id"), CONSTRAINT "UQ_CorrelationIdentifier_correlation_id" UNIQUE ("correlation_id"))` + ) + await queryRunner.query( + `INSERT INTO "temporary_CorrelationIdentifier"("id", "type", "correlation_id", "identity_id") SELECT "id", "type", "correlation_id", "identityId" FROM "CorrelationIdentifier"` + ) await queryRunner.query(`DROP TABLE "CorrelationIdentifier"`) await queryRunner.query(`ALTER TABLE "temporary_CorrelationIdentifier" RENAME TO "CorrelationIdentifier"`) - await queryRunner.query(`CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "partyId" varchar, CONSTRAINT "UQ_Identity_alias" UNIQUE ("alias"))`) - await queryRunner.query(`INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "partyId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"`) + await queryRunner.query( + `CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "partyId" varchar, CONSTRAINT "UQ_Identity_alias" UNIQUE ("alias"))` + ) + await queryRunner.query( + `INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "partyId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "contactId" FROM "Identity"` + ) await queryRunner.query(`DROP TABLE "Identity"`) await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) - await queryRunner.query(`CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identity_id" varchar, CONSTRAINT "REL_Connection_identityId" UNIQUE ("identity_id"))`) + await queryRunner.query( + `CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identity_id" varchar, CONSTRAINT "REL_Connection_identityId" UNIQUE ("identity_id"))` + ) await queryRunner.query(`INSERT INTO "temporary_Connection"("id", "type", "identity_id") SELECT "id", "type", "identityId" FROM "Connection"`) await queryRunner.query(`DROP TABLE "Connection"`) await queryRunner.query(`ALTER TABLE "temporary_Connection" RENAME TO "Connection"`) - await queryRunner.query(`CREATE TABLE "PartyType" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('naturalPerson','organization') ) NOT NULL, "name" varchar(255) NOT NULL, "description" varchar(255), "tenant_id" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "UQ_PartyType_name" UNIQUE ("name"))`) + await queryRunner.query( + `CREATE TABLE "PartyType" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('naturalPerson','organization') ) NOT NULL, "name" varchar(255) NOT NULL, "description" varchar(255), "tenant_id" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "UQ_PartyType_name" UNIQUE ("name"))` + ) await queryRunner.query(`CREATE UNIQUE INDEX "IDX_PartyType_type_tenant_id" ON "PartyType" ("type", "tenant_id")`) - await queryRunner.query(`CREATE TABLE "BaseContact" ("id" varchar PRIMARY KEY NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "legal_name" varchar(255), "display_name" varchar(255), "first_name" varchar(255), "middle_name" varchar(255), "last_name" varchar(255), "type" varchar NOT NULL, "party_id" varchar, CONSTRAINT "UQ_BaseContact_legal_name" UNIQUE ("legal_name"), CONSTRAINT "REL_BaseContact_party_id" UNIQUE ("party_id"))`) + await queryRunner.query( + `CREATE TABLE "BaseContact" ("id" varchar PRIMARY KEY NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "legal_name" varchar(255), "display_name" varchar(255), "first_name" varchar(255), "middle_name" varchar(255), "last_name" varchar(255), "type" varchar NOT NULL, "party_id" varchar, CONSTRAINT "UQ_BaseContact_legal_name" UNIQUE ("legal_name"), CONSTRAINT "REL_BaseContact_party_id" UNIQUE ("party_id"))` + ) await queryRunner.query(`CREATE INDEX "IDX_BaseContact_type" ON "BaseContact" ("type")`) - await queryRunner.query(`CREATE TABLE "PartyRelationship" ("id" varchar PRIMARY KEY NOT NULL, "left_id" varchar NOT NULL, "right_id" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')))`) + await queryRunner.query( + `CREATE TABLE "PartyRelationship" ("id" varchar PRIMARY KEY NOT NULL, "left_id" varchar NOT NULL, "right_id" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')))` + ) await queryRunner.query(`CREATE UNIQUE INDEX "IDX_PartyRelationship_left_right" ON "PartyRelationship" ("left_id", "right_id")`) - await queryRunner.query(`CREATE TABLE "ElectronicAddress" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar(255) NOT NULL, "electronic_address" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "partyId" varchar)`) - await queryRunner.query(`CREATE TABLE "Party" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "party_type_id" varchar NOT NULL)`) - await queryRunner.query(`CREATE TABLE "BaseConfig" ("id" varchar PRIMARY KEY NOT NULL, "identifier" varchar(255), "redirect_url" varchar(255), "session_id" varchar(255), "client_id" varchar(255), "client_secret" varchar(255), "scopes" text, "issuer" varchar(255), "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "type" varchar NOT NULL, "connection_id" varchar, CONSTRAINT "REL_BaseConfig_connection_id" UNIQUE ("connection_id"))`) + await queryRunner.query( + `CREATE TABLE "ElectronicAddress" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar(255) NOT NULL, "electronic_address" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "partyId" varchar)` + ) + await queryRunner.query( + `CREATE TABLE "Party" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "party_type_id" varchar NOT NULL)` + ) + await queryRunner.query( + `CREATE TABLE "BaseConfig" ("id" varchar PRIMARY KEY NOT NULL, "identifier" varchar(255), "redirect_url" varchar(255), "session_id" varchar(255), "client_id" varchar(255), "client_secret" varchar(255), "scopes" text, "issuer" varchar(255), "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "type" varchar NOT NULL, "connection_id" varchar, CONSTRAINT "REL_BaseConfig_connection_id" UNIQUE ("connection_id"))` + ) await queryRunner.query(`CREATE INDEX "IDX_BaseConfig_type" ON "BaseConfig" ("type")`) - await queryRunner.query(`CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identity_id" varchar, CONSTRAINT "REL_CorrelationIdentifier_identity_id" UNIQUE ("identity_id"), CONSTRAINT "UQ_CorrelationIdentifier_correlation_id" UNIQUE ("correlation_id"), CONSTRAINT "FK_CorrelationIdentifier_identity_id" FOREIGN KEY ("identity_id") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) - await queryRunner.query(`INSERT INTO "temporary_CorrelationIdentifier"("id", "type", "correlation_id", "identity_id") SELECT "id", "type", "correlation_id", "identity_id" FROM "CorrelationIdentifier"`) + await queryRunner.query( + `CREATE TABLE "temporary_CorrelationIdentifier" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('did','url') ) NOT NULL, "correlation_id" text NOT NULL, "identity_id" varchar, CONSTRAINT "REL_CorrelationIdentifier_identity_id" UNIQUE ("identity_id"), CONSTRAINT "UQ_CorrelationIdentifier_correlation_id" UNIQUE ("correlation_id"), CONSTRAINT "FK_CorrelationIdentifier_identity_id" FOREIGN KEY ("identity_id") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + ) + await queryRunner.query( + `INSERT INTO "temporary_CorrelationIdentifier"("id", "type", "correlation_id", "identity_id") SELECT "id", "type", "correlation_id", "identity_id" FROM "CorrelationIdentifier"` + ) await queryRunner.query(`DROP TABLE "CorrelationIdentifier"`) await queryRunner.query(`ALTER TABLE "temporary_CorrelationIdentifier" RENAME TO "CorrelationIdentifier"`) await queryRunner.query(`DROP INDEX "IDX_BaseContact_type"`) - await queryRunner.query(`CREATE TABLE "temporary_BaseContact" ("id" varchar PRIMARY KEY NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "legal_name" varchar(255), "display_name" varchar(255), "first_name" varchar(255), "middle_name" varchar(255), "last_name" varchar(255), "type" varchar NOT NULL, "party_id" varchar, CONSTRAINT "UQ_BaseContact_legal_name" UNIQUE ("legal_name"), CONSTRAINT "REL_BaseContact_party_id" UNIQUE ("party_id"), CONSTRAINT "FK_BaseContact_party_id" FOREIGN KEY ("party_id") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) - await queryRunner.query(`INSERT INTO "temporary_BaseContact"("id", "created_at", "last_updated_at", "legal_name", "display_name", "first_name", "middle_name", "last_name", "type", "party_id") SELECT "id", "created_at", "last_updated_at", "legal_name", "display_name", "first_name", "middle_name", "last_name", "type", "party_id" FROM "BaseContact"`) + await queryRunner.query( + `CREATE TABLE "temporary_BaseContact" ("id" varchar PRIMARY KEY NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "legal_name" varchar(255), "display_name" varchar(255), "first_name" varchar(255), "middle_name" varchar(255), "last_name" varchar(255), "type" varchar NOT NULL, "party_id" varchar, CONSTRAINT "UQ_BaseContact_legal_name" UNIQUE ("legal_name"), CONSTRAINT "REL_BaseContact_party_id" UNIQUE ("party_id"), CONSTRAINT "FK_BaseContact_party_id" FOREIGN KEY ("party_id") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + ) + await queryRunner.query( + `INSERT INTO "temporary_BaseContact"("id", "created_at", "last_updated_at", "legal_name", "display_name", "first_name", "middle_name", "last_name", "type", "party_id") SELECT "id", "created_at", "last_updated_at", "legal_name", "display_name", "first_name", "middle_name", "last_name", "type", "party_id" FROM "BaseContact"` + ) await queryRunner.query(`DROP TABLE "BaseContact"`) await queryRunner.query(`ALTER TABLE "temporary_BaseContact" RENAME TO "BaseContact"`) await queryRunner.query(`CREATE INDEX "IDX_BaseContact_type" ON "BaseContact" ("type")`) await queryRunner.query(`DROP INDEX "IDX_PartyRelationship_left_right"`) - await queryRunner.query(`CREATE TABLE "temporary_PartyRelationship" ("id" varchar PRIMARY KEY NOT NULL, "left_id" varchar NOT NULL, "right_id" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "FK_PartyRelationship_left_id" FOREIGN KEY ("left_id") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "FK_PartyRelationship_right_id" FOREIGN KEY ("right_id") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) - await queryRunner.query(`INSERT INTO "temporary_PartyRelationship"("id", "left_id", "right_id", "created_at", "last_updated_at") SELECT "id", "left_id", "right_id", "created_at", "last_updated_at" FROM "PartyRelationship"`) + await queryRunner.query( + `CREATE TABLE "temporary_PartyRelationship" ("id" varchar PRIMARY KEY NOT NULL, "left_id" varchar NOT NULL, "right_id" varchar NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "FK_PartyRelationship_left_id" FOREIGN KEY ("left_id") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "FK_PartyRelationship_right_id" FOREIGN KEY ("right_id") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + ) + await queryRunner.query( + `INSERT INTO "temporary_PartyRelationship"("id", "left_id", "right_id", "created_at", "last_updated_at") SELECT "id", "left_id", "right_id", "created_at", "last_updated_at" FROM "PartyRelationship"` + ) await queryRunner.query(`DROP TABLE "PartyRelationship"`) await queryRunner.query(`ALTER TABLE "temporary_PartyRelationship" RENAME TO "PartyRelationship"`) await queryRunner.query(`CREATE UNIQUE INDEX "IDX_PartyRelationship_left_right" ON "PartyRelationship" ("left_id", "right_id")`) - await queryRunner.query(`CREATE TABLE "temporary_ElectronicAddress" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar(255) NOT NULL, "electronic_address" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "partyId" varchar, CONSTRAINT "FK_ElectronicAddress_partyId" FOREIGN KEY ("partyId") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) - await queryRunner.query(`INSERT INTO "temporary_ElectronicAddress"("id", "type", "electronic_address", "created_at", "last_updated_at", "partyId") SELECT "id", "type", "electronic_address", "created_at", "last_updated_at", "partyId" FROM "ElectronicAddress"`) + await queryRunner.query( + `CREATE TABLE "temporary_ElectronicAddress" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar(255) NOT NULL, "electronic_address" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "partyId" varchar, CONSTRAINT "FK_ElectronicAddress_partyId" FOREIGN KEY ("partyId") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + ) + await queryRunner.query( + `INSERT INTO "temporary_ElectronicAddress"("id", "type", "electronic_address", "created_at", "last_updated_at", "partyId") SELECT "id", "type", "electronic_address", "created_at", "last_updated_at", "partyId" FROM "ElectronicAddress"` + ) await queryRunner.query(`DROP TABLE "ElectronicAddress"`) await queryRunner.query(`ALTER TABLE "temporary_ElectronicAddress" RENAME TO "ElectronicAddress"`) - await queryRunner.query(`CREATE TABLE "temporary_Party" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "party_type_id" varchar NOT NULL, CONSTRAINT "FK_Party_party_type_id" FOREIGN KEY ("party_type_id") REFERENCES "PartyType" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`) - await queryRunner.query(`INSERT INTO "temporary_Party"("id", "uri", "created_at", "last_updated_at", "party_type_id") SELECT "id", "uri", "created_at", "last_updated_at", "party_type_id" FROM "Party"`) + await queryRunner.query( + `CREATE TABLE "temporary_Party" ("id" varchar PRIMARY KEY NOT NULL, "uri" varchar(255) NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "party_type_id" varchar NOT NULL, CONSTRAINT "FK_Party_party_type_id" FOREIGN KEY ("party_type_id") REFERENCES "PartyType" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)` + ) + await queryRunner.query( + `INSERT INTO "temporary_Party"("id", "uri", "created_at", "last_updated_at", "party_type_id") SELECT "id", "uri", "created_at", "last_updated_at", "party_type_id" FROM "Party"` + ) await queryRunner.query(`DROP TABLE "Party"`) await queryRunner.query(`ALTER TABLE "temporary_Party" RENAME TO "Party"`) - await queryRunner.query(`CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "partyId" varchar, CONSTRAINT "UQ_Identity_alias" UNIQUE ("alias"), CONSTRAINT "FK_Identity_partyId" FOREIGN KEY ("partyId") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) - await queryRunner.query(`INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "partyId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "partyId" FROM "Identity"`) + await queryRunner.query( + `CREATE TABLE "temporary_Identity" ("id" varchar PRIMARY KEY NOT NULL, "alias" varchar(255) NOT NULL, "roles" text NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), "partyId" varchar, CONSTRAINT "UQ_Identity_alias" UNIQUE ("alias"), CONSTRAINT "FK_Identity_partyId" FOREIGN KEY ("partyId") REFERENCES "Party" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + ) + await queryRunner.query( + `INSERT INTO "temporary_Identity"("id", "alias", "roles", "created_at", "last_updated_at", "partyId") SELECT "id", "alias", "roles", "created_at", "last_updated_at", "partyId" FROM "Identity"` + ) await queryRunner.query(`DROP TABLE "Identity"`) await queryRunner.query(`ALTER TABLE "temporary_Identity" RENAME TO "Identity"`) - await queryRunner.query(`CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identity_id" varchar, CONSTRAINT "REL_Connection_identity_id" UNIQUE ("identity_id"), CONSTRAINT "FK_Connection_identity_id" FOREIGN KEY ("identity_id") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) + await queryRunner.query( + `CREATE TABLE "temporary_Connection" ("id" varchar PRIMARY KEY NOT NULL, "type" varchar CHECK( "type" IN ('OIDC','SIOPv2','SIOPv2+OpenID4VP') ) NOT NULL, "identity_id" varchar, CONSTRAINT "REL_Connection_identity_id" UNIQUE ("identity_id"), CONSTRAINT "FK_Connection_identity_id" FOREIGN KEY ("identity_id") REFERENCES "Identity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + ) await queryRunner.query(`INSERT INTO "temporary_Connection"("id", "type", "identity_id") SELECT "id", "type", "identity_id" FROM "Connection"`) await queryRunner.query(`DROP TABLE "Connection"`) await queryRunner.query(`ALTER TABLE "temporary_Connection" RENAME TO "Connection"`) await queryRunner.query(`DROP INDEX "IDX_BaseConfig_type"`) - await queryRunner.query(`CREATE TABLE "temporary_BaseConfig" ("id" varchar PRIMARY KEY NOT NULL, "identifier" varchar(255), "redirect_url" varchar(255), "session_id" varchar(255), "client_id" varchar(255), "client_secret" varchar(255), "scopes" text, "issuer" varchar(255), "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "type" varchar NOT NULL, "connection_id" varchar, CONSTRAINT "REL_BaseConfig_connection_id" UNIQUE ("connection_id"), CONSTRAINT "FK_BaseConfig_connection_id" FOREIGN KEY ("connection_id") REFERENCES "Connection" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`) - await queryRunner.query(`INSERT INTO "temporary_BaseConfig"("id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id") SELECT "id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id" FROM "BaseConfig"`) + await queryRunner.query( + `CREATE TABLE "temporary_BaseConfig" ("id" varchar PRIMARY KEY NOT NULL, "identifier" varchar(255), "redirect_url" varchar(255), "session_id" varchar(255), "client_id" varchar(255), "client_secret" varchar(255), "scopes" text, "issuer" varchar(255), "dangerously_allow_insecure_http_requests" boolean, "client_auth_method" text, "type" varchar NOT NULL, "connection_id" varchar, CONSTRAINT "REL_BaseConfig_connection_id" UNIQUE ("connection_id"), CONSTRAINT "FK_BaseConfig_connection_id" FOREIGN KEY ("connection_id") REFERENCES "Connection" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + ) + await queryRunner.query( + `INSERT INTO "temporary_BaseConfig"("id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id") SELECT "id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id" FROM "BaseConfig"` + ) await queryRunner.query(`DROP TABLE "BaseConfig"`) await queryRunner.query(`ALTER TABLE "temporary_BaseConfig" RENAME TO "BaseConfig"`) await queryRunner.query(`CREATE INDEX "IDX_BaseConfig_type" ON "BaseConfig" ("type")`) // migrate existing data - await queryRunner.query(`INSERT INTO "BaseConfig"("id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id") SELECT "id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id" FROM "BaseConfigEntity"`) + await queryRunner.query( + `INSERT INTO "BaseConfig"("id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id") SELECT "id", "identifier", "redirect_url", "session_id", "client_id", "client_secret", "scopes", "issuer", "dangerously_allow_insecure_http_requests", "client_auth_method", "type", "connection_id" FROM "BaseConfigEntity"` + ) await queryRunner.query(`DROP TABLE "BaseConfigEntity"`) - await queryRunner.query(`INSERT INTO "PartyType"(id, type, name, description, tenant_id, created_at, last_updated_at) VALUES ('3875c12e-fdaa-4ef6-a340-c936e054b627', 'organization', 'Sphereon_default_type', 'sphereon_default_organization', '95e09cfc-c974-4174-86aa-7bf1d5251fb4', datetime('now'), datetime('now'))`) - await queryRunner.query(`INSERT INTO "Party"(id, uri, created_at, last_updated_at, party_type_id) SELECT id, uri, created_at, last_updated_at, '3875c12e-fdaa-4ef6-a340-c936e054b627' FROM "Contact"`) - await queryRunner.query(`INSERT INTO "BaseContact"(id, legal_name, display_name, party_id, created_at, last_updated_at, type) SELECT id, name, alias, id, created_at, last_updated_at, 'Organization' FROM "Contact"`) + await queryRunner.query( + `INSERT INTO "PartyType"(id, type, name, description, tenant_id, created_at, last_updated_at) VALUES ('3875c12e-fdaa-4ef6-a340-c936e054b627', 'organization', 'Sphereon_default_type', 'sphereon_default_organization', '95e09cfc-c974-4174-86aa-7bf1d5251fb4', datetime('now'), datetime('now'))` + ) + await queryRunner.query( + `INSERT INTO "Party"(id, uri, created_at, last_updated_at, party_type_id) SELECT id, uri, created_at, last_updated_at, '3875c12e-fdaa-4ef6-a340-c936e054b627' FROM "Contact"` + ) + await queryRunner.query( + `INSERT INTO "BaseContact"(id, legal_name, display_name, party_id, created_at, last_updated_at, type) SELECT id, name, alias, id, created_at, last_updated_at, 'Organization' FROM "Contact"` + ) await queryRunner.query(`DROP TABLE "Contact"`) } diff --git a/packages/data-store/src/types/contact/IAbstractContactStore.ts b/packages/data-store/src/types/contact/IAbstractContactStore.ts index 76e1cb323..dc5e413cc 100644 --- a/packages/data-store/src/types/contact/IAbstractContactStore.ts +++ b/packages/data-store/src/types/contact/IAbstractContactStore.ts @@ -10,7 +10,8 @@ import { PartyType, PartyRelationship, PartialPartyRelationship, - PartialPartyType, NonPersistedElectronicAddress + PartialPartyType, + NonPersistedElectronicAddress, } from './contact' export type FindPartyArgs = Array From 4c4216ba98f5c7e045d759ea2aa822ba0e32aa8d Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Tue, 5 Sep 2023 12:32:29 +0200 Subject: [PATCH 27/35] DPP-1 cleanup --- .../src/agent/ContactManager.ts | 22 ++++++++++----- packages/data-store/src/index.ts | 27 +------------------ 2 files changed, 16 insertions(+), 33 deletions(-) diff --git a/packages/contact-manager/src/agent/ContactManager.ts b/packages/contact-manager/src/agent/ContactManager.ts index c522102e5..561e7d43a 100644 --- a/packages/contact-manager/src/agent/ContactManager.ts +++ b/packages/contact-manager/src/agent/ContactManager.ts @@ -30,6 +30,9 @@ import { Identity, PartyRelationship as ContactRelationship, PartyType as ContactType, + NonPersistedContact, + isNaturalPerson, + isOrganization, } from '@sphereon/ssi-sdk.data-store' /** @@ -78,16 +81,10 @@ export class ContactManager implements IAgentPlugin { /** {@inheritDoc IContactManager.cmAddContact} */ private async cmAddContact(args: AddContactArgs, context: RequiredContext): Promise { - // TODO this needs to be improved - const contact = - 'firstName' in args && 'lastName' in args - ? { firstName: args.firstName, middleName: args.middleName, lastName: args.lastName, displayName: args.displayName } - : { legalName: args.legalName, displayName: args.displayName } - return this.store.addParty({ uri: args.uri, partyType: args.contactType, - contact, + contact: this.getContactInformationFrom(args), identities: args.identities, electronicAddresses: args.electronicAddresses, }) @@ -177,4 +174,15 @@ export class ContactManager implements IAgentPlugin { private async cmRemoveContactType(args: RemoveContactTypeArgs, context: RequiredContext): Promise { return this.store.removePartyType({ partyTypeId: args.contactTypeId }).then(() => true) } + + private getContactInformationFrom(contact: any): NonPersistedContact { + if (isNaturalPerson(contact)) { + return { firstName: contact.firstName, middleName: contact.middleName, lastName: contact.lastName, displayName: contact.displayName } + } else if (isOrganization(contact)) { + return { legalName: contact.legalName, displayName: contact.displayName } + } + + throw new Error('Contact not supported') + } + } diff --git a/packages/data-store/src/index.ts b/packages/data-store/src/index.ts index a84bb6802..d32e6534c 100644 --- a/packages/data-store/src/index.ts +++ b/packages/data-store/src/index.ts @@ -21,26 +21,13 @@ import { PartyTypeEntity } from './entities/contact/PartyTypeEntity' import { OrganizationEntity } from './entities/contact/OrganizationEntity' import { NaturalPersonEntity } from './entities/contact/NaturalPersonEntity' import { ElectronicAddressEntity } from './entities/contact/ElectronicAddressEntity' -import { - connectionEntityFrom, - correlationIdentifierEntityFrom, - didAuthConfigEntityFrom, - electronicAddressEntityFrom, - identityEntityFrom, - metadataItemEntityFrom, - naturalPersonEntityFrom, - openIdConfigEntityFrom, - organizationEntityFrom, - partyEntityFrom, - partyRelationshipEntityFrom, - partyTypeEntityFrom, -} from './utils/contact/MappingUtils' export { ContactStore } from './contact/ContactStore' export { AbstractContactStore } from './contact/AbstractContactStore' export { AbstractIssuanceBrandingStore } from './issuanceBranding/AbstractIssuanceBrandingStore' export { IssuanceBrandingStore } from './issuanceBranding/IssuanceBrandingStore' export { DataStoreMigrations } from './migrations' export * from './types' +export * from './utils/contact/MappingUtils' export const DataStoreContactEntities = [ BaseConfigEntity, @@ -90,13 +77,6 @@ export { CredentialLocaleBrandingEntity, IssuerLocaleBrandingEntity, ElectronicAddressEntity, - metadataItemEntityFrom, - connectionEntityFrom, - partyEntityFrom, - correlationIdentifierEntityFrom, - identityEntityFrom, - didAuthConfigEntityFrom, - openIdConfigEntityFrom, backgroundAttributesEntityFrom, credentialBrandingEntityFrom, imageAttributesEntityFrom, @@ -105,9 +85,4 @@ export { textAttributesEntityFrom, issuerLocaleBrandingEntityFrom, credentialLocaleBrandingEntityFrom, - partyRelationshipEntityFrom, - partyTypeEntityFrom, - organizationEntityFrom, - naturalPersonEntityFrom, - electronicAddressEntityFrom, } From 78b58e50cb2217597071607b3f9bdb50202a20d9 Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Tue, 5 Sep 2023 12:37:08 +0200 Subject: [PATCH 28/35] DPP-1 cleanup --- packages/contact-manager/agent.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/contact-manager/agent.yml b/packages/contact-manager/agent.yml index 3b4a79505..fb3806515 100644 --- a/packages/contact-manager/agent.yml +++ b/packages/contact-manager/agent.yml @@ -30,10 +30,10 @@ dbConnection: $args: - type: sqlite database: ':memory:' - synchronize: true #false - migrationsRun: true #true - # migrations: - # $require: './packages/data-store?t=object#DataStoreMigrations' + synchronize: false + migrationsRun: true + migrations: + $require: './packages/data-store?t=object#DataStoreMigrations' entities: $require: './packages/data-store?t=object#DataStoreContactEntities' From 7f34679440dd8a3c4c4c5a2061df7816b58a9b6e Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Tue, 5 Sep 2023 12:39:29 +0200 Subject: [PATCH 29/35] DPP-1 cleanup --- packages/contact-manager/package.json | 4 ++-- packages/data-store/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/contact-manager/package.json b/packages/contact-manager/package.json index 475542996..d46767072 100644 --- a/packages/contact-manager/package.json +++ b/packages/contact-manager/package.json @@ -14,13 +14,13 @@ "build:clean": "tsc --build --clean && tsc --build" }, "dependencies": { - "@sphereon/ssi-sdk.data-store": "file://C:\\ssi-sdk\\packages\\data-store\\sphereon-ssi-sdk.data-store-0.23.0-bram.tgz", + "@sphereon/ssi-sdk.data-store": "workspace:^", "cross-fetch": "^3.1.5", "typeorm": "^0.3.12" }, "devDependencies": { "@sphereon/ssi-sdk.agent-config": "workspace:*", - "@sphereon/ssi-sdk.data-store": "file://C:\\ssi-sdk\\packages\\data-store\\sphereon-ssi-sdk.data-store-0.23.0-bram.tgz", + "@sphereon/ssi-sdk.data-store": "workspace:^", "@veramo/remote-client": "4.2.0", "@veramo/remote-server": "4.2.0" }, diff --git a/packages/data-store/package.json b/packages/data-store/package.json index 87763b054..db9220cc1 100644 --- a/packages/data-store/package.json +++ b/packages/data-store/package.json @@ -1,6 +1,6 @@ { "name": "@sphereon/ssi-sdk.data-store", - "version": "0.23.0-bram", + "version": "0.13.0", "source": "src/index.ts", "main": "dist/index.js", "types": "dist/index.d.ts", From 321ea7686e70d5560fedc906a21610096176a547 Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Tue, 5 Sep 2023 12:47:32 +0200 Subject: [PATCH 30/35] DPP-1 lock file update --- packages/data-store/package.json | 2 +- pnpm-lock.yaml | 117 +++++++++++++++++++++++++++---- 2 files changed, 104 insertions(+), 15 deletions(-) diff --git a/packages/data-store/package.json b/packages/data-store/package.json index 038fe559f..3a0e55e38 100644 --- a/packages/data-store/package.json +++ b/packages/data-store/package.json @@ -17,10 +17,10 @@ "@veramo/core": "4.2.0", "class-validator": "^0.14.0", "debug": "^4.3.4", - "pg": "^8.11.3", "typeorm": "^0.3.12" }, "devDependencies": { + "pg": "^8.11.3", "sqlite3": "^5.1.6" }, "files": [ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 03a68c0a4..ac477ae6e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '6.0' +lockfileVersion: '6.1' settings: autoInstallPeers: true @@ -173,7 +173,7 @@ importers: version: 5.0.1 typeorm: specifier: ^0.3.12 - version: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) url-parse: specifier: ^1.5.10 version: 1.5.10 @@ -195,7 +195,7 @@ importers: version: 3.1.8 typeorm: specifier: ^0.3.12 - version: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) devDependencies: '@sphereon/ssi-sdk.agent-config': specifier: workspace:^ @@ -223,8 +223,11 @@ importers: version: 4.3.4 typeorm: specifier: ^0.3.12 - version: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) devDependencies: + pg: + specifier: ^8.11.3 + version: 8.11.3 sqlite3: specifier: ^5.1.6 version: 5.1.6 @@ -300,7 +303,7 @@ importers: version: 4.3.4 typeorm: specifier: ^0.3.12 - version: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) devDependencies: '@sphereon/ssi-sdk.agent-config': specifier: workspace:^ @@ -328,7 +331,7 @@ importers: version: 3.0.1 typeorm: specifier: ^0.3.12 - version: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) uint8arrays: specifier: ^3.1.1 version: 3.1.1 @@ -460,7 +463,7 @@ importers: version: 27.1.5(@babel/core@7.22.11)(@types/jest@27.5.2)(jest@27.5.1)(typescript@4.9.5) typeorm: specifier: ^0.3.12 - version: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) typescript: specifier: 4.9.5 version: 4.9.5 @@ -681,7 +684,7 @@ importers: version: 10.9.1(@types/node@18.16.3)(typescript@4.9.5) typeorm: specifier: ^0.3.12 - version: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) web-did-resolver: specifier: ^2.0.24 version: 2.0.27 @@ -1190,7 +1193,7 @@ importers: version: 10.9.1(@types/node@18.16.3)(typescript@4.9.5) typeorm: specifier: ^0.3.12 - version: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) packages/siopv2-oid4vp-rp-rest-client: dependencies: @@ -1525,7 +1528,7 @@ importers: version: 10.9.1(@types/node@18.16.3)(typescript@4.9.5) typeorm: specifier: ^0.3.12 - version: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) web-did-resolver: specifier: ^2.0.27 version: 2.0.27 @@ -1912,7 +1915,7 @@ importers: version: 10.9.1(@types/node@18.16.3)(typescript@4.9.5) typeorm: specifier: ^0.3.12 - version: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) packages/web3-provider-headless: dependencies: @@ -2072,7 +2075,7 @@ importers: version: 3.1.3 typeorm: specifier: ^0.3.12 - version: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) uuid: specifier: ^8.3.2 version: 8.3.2 @@ -8074,7 +8077,7 @@ packages: '@veramo/key-manager': 4.2.0 '@veramo/utils': 4.2.0 debug: 4.3.4 - typeorm: 0.3.12(sqlite3@5.1.6)(ts-node@10.9.1) + typeorm: 0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) transitivePeerDependencies: - '@google-cloud/spanner' - '@sap/hana-client' @@ -9357,6 +9360,10 @@ packages: /buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + /buffer-writer@2.0.0: + resolution: {integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==} + engines: {node: '>=4'} + /buffer-xor@1.0.3: resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} dev: true @@ -17306,6 +17313,9 @@ packages: p-reduce: 2.1.0 dev: true + /packet-reader@1.0.0: + resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==} + /pacote@13.6.2: resolution: {integrity: sha512-Gu8fU3GsvOPkak2CkbojR7vjs3k3P9cA6uazKTHdsdV0gpCEQq2opelnEv30KRQWgVzP5Vd/5umjcedma3MKtg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} @@ -17562,6 +17572,62 @@ packages: /pause@0.0.1: resolution: {integrity: sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==} + /pg-cloudflare@1.1.1: + resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==} + requiresBuild: true + optional: true + + /pg-connection-string@2.6.2: + resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==} + + /pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + + /pg-pool@3.6.1(pg@8.11.3): + resolution: {integrity: sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==} + peerDependencies: + pg: '>=8.0' + dependencies: + pg: 8.11.3 + + /pg-protocol@1.6.0: + resolution: {integrity: sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==} + + /pg-types@2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} + dependencies: + pg-int8: 1.0.1 + postgres-array: 2.0.0 + postgres-bytea: 1.0.0 + postgres-date: 1.0.7 + postgres-interval: 1.2.0 + + /pg@8.11.3: + resolution: {integrity: sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==} + engines: {node: '>= 8.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + dependencies: + buffer-writer: 2.0.0 + packet-reader: 1.0.0 + pg-connection-string: 2.6.2 + pg-pool: 3.6.1(pg@8.11.3) + pg-protocol: 1.6.0 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.1.1 + + /pgpass@1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + dependencies: + split2: 4.2.0 + /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} @@ -17647,6 +17713,24 @@ packages: picocolors: 1.0.0 source-map-js: 1.0.2 + /postgres-array@2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} + + /postgres-bytea@1.0.0: + resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} + engines: {node: '>=0.10.0'} + + /postgres-date@1.0.7: + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} + + /postgres-interval@1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} + dependencies: + xtend: 4.0.2 + /prelude-ls@1.1.2: resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} engines: {node: '>= 0.8.0'} @@ -18989,6 +19073,10 @@ packages: readable-stream: 3.6.2 dev: true + /split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + /split@1.0.1: resolution: {integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==} dependencies: @@ -19964,7 +20052,7 @@ packages: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} dev: true - /typeorm@0.3.12(sqlite3@5.1.6)(ts-node@10.9.1): + /typeorm@0.3.12(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1): resolution: {integrity: sha512-sYSxBmCf1nJLLTcYtwqZ+lQIRtLPyUoO93rHTOKk9vJCyT4UfRtU7oRsJvfvKP3nnZTD1hzz2SEy2zwPEN6OyA==} engines: {node: '>= 12.9.0'} hasBin: true @@ -20033,6 +20121,7 @@ packages: glob: 8.1.0 js-yaml: 4.1.0 mkdirp: 2.1.6 + pg: 8.11.3 reflect-metadata: 0.1.13 sha.js: 2.4.11 sqlite3: 5.1.6 From 28ee8b2f4d7fe7bce4002abca761b80998b81920 Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Tue, 12 Sep 2023 09:55:01 +0200 Subject: [PATCH 31/35] DPP-1 migration uuid fix --- packages/data-store/src/migrations/generic/index.ts | 2 +- .../src/migrations/postgres/1690925872592-CreateContacts.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/data-store/src/migrations/generic/index.ts b/packages/data-store/src/migrations/generic/index.ts index c2b73ec69..dbfce8eac 100644 --- a/packages/data-store/src/migrations/generic/index.ts +++ b/packages/data-store/src/migrations/generic/index.ts @@ -17,4 +17,4 @@ export const DataStoreIssuanceBrandingMigrations = [CreateIssuanceBranding165946 export const DataStoreStatusListMigrations = [CreateStatusList1693866470000] // All migrations together -export const DataStoreMigrations = [CreateContacts1659463079429, CreateContacts1690925872318, CreateIssuanceBranding1659463079429, CreateStatusList1693866470000] +export const DataStoreMigrations = [...DataStoreContactMigrations, ...DataStoreIssuanceBrandingMigrations, ...DataStoreStatusListMigrations] diff --git a/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts b/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts index 6ed56b57a..b928cb5cc 100644 --- a/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts +++ b/packages/data-store/src/migrations/postgres/1690925872592-CreateContacts.ts @@ -1,9 +1,11 @@ import { MigrationInterface, QueryRunner } from 'typeorm' +import { enableUuidv4 } from './uuid' export class CreateContacts1690925872592 implements MigrationInterface { name = 'CreateContacts1690925872592' public async up(queryRunner: QueryRunner): Promise { + await enableUuidv4(queryRunner) await queryRunner.query(`ALTER TABLE "CorrelationIdentifier" DROP CONSTRAINT "FK_CorrelationIdentifier_identityId"`) await queryRunner.query(`ALTER TABLE "IdentityMetadata" DROP CONSTRAINT "FK_IdentityMetadata_identityId"`) await queryRunner.query(`ALTER TABLE "Identity" DROP CONSTRAINT "FK_Identity_contactId"`) From c485e7f7628ea7db28cd3dfb88d284512e4c07bc Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Tue, 12 Sep 2023 09:58:20 +0200 Subject: [PATCH 32/35] DPP-1 pnpm lock --- pnpm-lock.yaml | 121 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 105 insertions(+), 16 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4f8d91928..9738d930e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '6.0' +lockfileVersion: '6.1' settings: autoInstallPeers: true @@ -177,7 +177,7 @@ importers: version: 5.0.1 typeorm: specifier: 0.3.17 - version: 0.3.17(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.17(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) url-parse: specifier: ^1.5.10 version: 1.5.10 @@ -205,7 +205,7 @@ importers: version: 3.1.8 typeorm: specifier: 0.3.17 - version: 0.3.17(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.17(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) devDependencies: '@sphereon/ssi-sdk.agent-config': specifier: workspace:* @@ -233,8 +233,11 @@ importers: version: 4.3.4 typeorm: specifier: 0.3.17 - version: 0.3.17(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.17(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) devDependencies: + pg: + specifier: ^8.11.3 + version: 8.11.3 sqlite3: specifier: ^5.1.6 version: 5.1.6 @@ -310,7 +313,7 @@ importers: version: 4.3.4 typeorm: specifier: 0.3.17 - version: 0.3.17(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.17(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) devDependencies: '@sphereon/ssi-sdk.agent-config': specifier: workspace:* @@ -338,7 +341,7 @@ importers: version: 3.0.1 typeorm: specifier: 0.3.17 - version: 0.3.17(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.17(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) uint8arrays: specifier: ^3.1.1 version: 3.1.1 @@ -470,7 +473,7 @@ importers: version: 27.1.5(@babel/core@7.22.15)(@types/jest@27.5.2)(jest@27.5.1)(typescript@4.9.5) typeorm: specifier: 0.3.17 - version: 0.3.17(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.17(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) typescript: specifier: 4.9.5 version: 4.9.5 @@ -691,7 +694,7 @@ importers: version: 10.9.1(@types/node@18.16.3)(typescript@4.9.5) typeorm: specifier: 0.3.17 - version: 0.3.17(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.17(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) web-did-resolver: specifier: ^2.0.24 version: 2.0.27 @@ -1200,7 +1203,7 @@ importers: version: 10.9.1(@types/node@18.16.3)(typescript@4.9.5) typeorm: specifier: 0.3.17 - version: 0.3.17(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.17(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) packages/siopv2-oid4vp-rp-rest-client: dependencies: @@ -1535,7 +1538,7 @@ importers: version: 10.9.1(@types/node@18.16.3)(typescript@4.9.5) typeorm: specifier: 0.3.17 - version: 0.3.17(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.17(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) web-did-resolver: specifier: ^2.0.27 version: 2.0.27 @@ -1825,7 +1828,7 @@ importers: version: 4.3.4 typeorm: specifier: 0.3.17 - version: 0.3.17(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.17(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) uint8arrays: specifier: ^3.1.1 version: 3.1.1 @@ -1883,7 +1886,7 @@ importers: version: 0.1.13 typeorm: specifier: 0.3.17 - version: 0.3.17(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.17(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) uint8arrays: specifier: ^3.1.1 version: 3.1.1 @@ -2134,7 +2137,7 @@ importers: version: 10.9.1(@types/node@18.16.3)(typescript@4.9.5) typeorm: specifier: 0.3.17 - version: 0.3.17(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.17(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) packages/web3-provider-headless: dependencies: @@ -2294,7 +2297,7 @@ importers: version: 3.1.3 typeorm: specifier: 0.3.17 - version: 0.3.17(sqlite3@5.1.6)(ts-node@10.9.1) + version: 0.3.17(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) uuid: specifier: ^8.3.2 version: 8.3.2 @@ -9338,7 +9341,7 @@ packages: '@veramo/key-manager': 4.2.0 '@veramo/utils': 4.2.0 debug: 4.3.4 - typeorm: 0.3.17(sqlite3@5.1.6)(ts-node@10.9.1) + typeorm: 0.3.17(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1) transitivePeerDependencies: - '@google-cloud/spanner' - '@sap/hana-client' @@ -10749,6 +10752,10 @@ packages: /buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + /buffer-writer@2.0.0: + resolution: {integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==} + engines: {node: '>=4'} + /buffer-xor@1.0.3: resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} dev: true @@ -19212,6 +19219,9 @@ packages: p-reduce: 2.1.0 dev: true + /packet-reader@1.0.0: + resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==} + /pacote@13.6.2: resolution: {integrity: sha512-Gu8fU3GsvOPkak2CkbojR7vjs3k3P9cA6uazKTHdsdV0gpCEQq2opelnEv30KRQWgVzP5Vd/5umjcedma3MKtg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} @@ -19479,6 +19489,62 @@ packages: /pause@0.0.1: resolution: {integrity: sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==} + /pg-cloudflare@1.1.1: + resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==} + requiresBuild: true + optional: true + + /pg-connection-string@2.6.2: + resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==} + + /pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + + /pg-pool@3.6.1(pg@8.11.3): + resolution: {integrity: sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==} + peerDependencies: + pg: '>=8.0' + dependencies: + pg: 8.11.3 + + /pg-protocol@1.6.0: + resolution: {integrity: sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==} + + /pg-types@2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} + dependencies: + pg-int8: 1.0.1 + postgres-array: 2.0.0 + postgres-bytea: 1.0.0 + postgres-date: 1.0.7 + postgres-interval: 1.2.0 + + /pg@8.11.3: + resolution: {integrity: sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==} + engines: {node: '>= 8.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + dependencies: + buffer-writer: 2.0.0 + packet-reader: 1.0.0 + pg-connection-string: 2.6.2 + pg-pool: 3.6.1(pg@8.11.3) + pg-protocol: 1.6.0 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.1.1 + + /pgpass@1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + dependencies: + split2: 4.2.0 + /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} @@ -19570,6 +19636,24 @@ packages: picocolors: 1.0.0 source-map-js: 1.0.2 + /postgres-array@2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} + + /postgres-bytea@1.0.0: + resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} + engines: {node: '>=0.10.0'} + + /postgres-date@1.0.7: + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} + + /postgres-interval@1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} + dependencies: + xtend: 4.0.2 + /prelude-ls@1.1.2: resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} engines: {node: '>= 0.8.0'} @@ -21041,6 +21125,10 @@ packages: readable-stream: 3.6.2 dev: true + /split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + /split@1.0.1: resolution: {integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==} dependencies: @@ -22053,7 +22141,7 @@ packages: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} dev: true - /typeorm@0.3.17(sqlite3@5.1.6)(ts-node@10.9.1): + /typeorm@0.3.17(pg@8.11.3)(sqlite3@5.1.6)(ts-node@10.9.1): resolution: {integrity: sha512-UDjUEwIQalO9tWw9O2A4GU+sT3oyoUXheHJy4ft+RFdnRdQctdQ34L9SqE2p7LdwzafHx1maxT+bqXON+Qnmig==} engines: {node: '>= 12.9.0'} hasBin: true @@ -22121,6 +22209,7 @@ packages: dotenv: 16.3.1 glob: 8.1.0 mkdirp: 2.1.6 + pg: 8.11.3 reflect-metadata: 0.1.13 sha.js: 2.4.11 sqlite3: 5.1.6 From 84229452fcb454f0b52f56aeaaf2ba36f6c91247 Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Tue, 12 Sep 2023 10:02:05 +0200 Subject: [PATCH 33/35] DPP-1 formatting fix --- packages/data-store/src/types/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/data-store/src/types/index.ts b/packages/data-store/src/types/index.ts index a3d837261..f74232faf 100644 --- a/packages/data-store/src/types/index.ts +++ b/packages/data-store/src/types/index.ts @@ -3,5 +3,6 @@ export * from './issuanceBranding/IAbstractIssuanceBrandingStore' export * from './contact/contact' export * from './contact/IAbstractContactStore' -export * from './validation/validation'export * from './statusList/statusList' +export * from './validation/validation' +export * from './statusList/statusList' export * from './statusList/IAbstractStatusListStore' From dd09f386eba4ced6bf0cb5b26b36d338b22db411 Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Tue, 12 Sep 2023 10:48:10 +0200 Subject: [PATCH 34/35] DPP-1 test fix --- packages/data-store/src/__tests__/contact.store.test.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/data-store/src/__tests__/contact.store.test.ts b/packages/data-store/src/__tests__/contact.store.test.ts index ad3931718..2ade64899 100644 --- a/packages/data-store/src/__tests__/contact.store.test.ts +++ b/packages/data-store/src/__tests__/contact.store.test.ts @@ -1,5 +1,4 @@ import { DataSource } from 'typeorm' - import { DataStoreMigrations, DataStoreContactEntities } from '../index' import { ContactStore } from '../contact/ContactStore' import { @@ -1676,12 +1675,15 @@ describe('Contact store tests', (): void => { const resultPartyType: PartyType = await contactStore.getPartyType({ partyTypeId: savedPartyType.id }) expect(resultPartyType).toBeDefined() + const includingMigrationPartyTypes: Array = await contactStore.getPartyTypes() + expect(includingMigrationPartyTypes.length).toEqual(2) + await contactStore.removePartyType({ partyTypeId: savedPartyType.id }) const result: Array = await contactStore.getPartyTypes() expect(result).toBeDefined() - expect(result.length).toEqual(0) + expect(result.length).toEqual(1) }) it('should throw error when removing party type attached to contact', async (): Promise => { From 7ed1d99101613d6a2e00d4c534d70ac0305c8841 Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Tue, 12 Sep 2023 11:04:57 +0200 Subject: [PATCH 35/35] DPP-1 test fixes --- .../src/entities/contact/BaseContactEntity.ts | 11 ++++++++++- .../src/entities/contact/ElectronicAddressEntity.ts | 7 +++++++ .../data-store/src/entities/contact/IdentityEntity.ts | 7 +++++++ .../data-store/src/entities/contact/PartyEntity.ts | 7 +++++++ .../src/entities/contact/PartyRelationshipEntity.ts | 7 +++++++ .../src/entities/contact/PartyTypeEntity.ts | 7 +++++++ .../issuanceBranding/BaseLocaleBrandingEntity.ts | 7 +++++++ .../issuanceBranding/CredentialBrandingEntity.ts | 7 +++++++ .../entities/issuanceBranding/IssuerBrandingEntity.ts | 7 +++++++ 9 files changed, 66 insertions(+), 1 deletion(-) diff --git a/packages/data-store/src/entities/contact/BaseContactEntity.ts b/packages/data-store/src/entities/contact/BaseContactEntity.ts index 64f219243..d0f548eb0 100644 --- a/packages/data-store/src/entities/contact/BaseContactEntity.ts +++ b/packages/data-store/src/entities/contact/BaseContactEntity.ts @@ -1,4 +1,6 @@ -import { BaseEntity, CreateDateColumn, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn, TableInheritance, UpdateDateColumn } from 'typeorm' +import { BaseEntity, + BeforeInsert, + BeforeUpdate, CreateDateColumn, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn, TableInheritance, UpdateDateColumn } from 'typeorm' import { PartyEntity } from './PartyEntity' @Entity('BaseContact') @@ -18,4 +20,11 @@ export abstract class BaseContactEntity extends BaseEntity { }) @JoinColumn({ name: 'party_id' }) party!: PartyEntity + + // By default, @UpdateDateColumn in TypeORM updates the timestamp only when the entity's top-level properties change. + @BeforeInsert() + @BeforeUpdate() + updateUpdatedDate(): void { + this.lastUpdatedAt = new Date() + } } diff --git a/packages/data-store/src/entities/contact/ElectronicAddressEntity.ts b/packages/data-store/src/entities/contact/ElectronicAddressEntity.ts index d2d60914e..ba633bd99 100644 --- a/packages/data-store/src/entities/contact/ElectronicAddressEntity.ts +++ b/packages/data-store/src/entities/contact/ElectronicAddressEntity.ts @@ -38,6 +38,13 @@ export class ElectronicAddressEntity extends BaseEntity { @UpdateDateColumn({ name: 'last_updated_at', nullable: false }) lastUpdatedAt!: Date + // By default, @UpdateDateColumn in TypeORM updates the timestamp only when the entity's top-level properties change. + @BeforeInsert() + @BeforeUpdate() + updateUpdatedDate(): void { + this.lastUpdatedAt = new Date() + } + @BeforeInsert() @BeforeUpdate() async validate(): Promise { diff --git a/packages/data-store/src/entities/contact/IdentityEntity.ts b/packages/data-store/src/entities/contact/IdentityEntity.ts index e3db4ba5c..356f528f0 100644 --- a/packages/data-store/src/entities/contact/IdentityEntity.ts +++ b/packages/data-store/src/entities/contact/IdentityEntity.ts @@ -75,6 +75,13 @@ export class IdentityEntity extends BaseEntity { @Column({ name: 'partyId', nullable: true }) partyId!: string + // By default, @UpdateDateColumn in TypeORM updates the timestamp only when the entity's top-level properties change. + @BeforeInsert() + @BeforeUpdate() + updateUpdatedDate(): void { + this.lastUpdatedAt = new Date() + } + @BeforeInsert() @BeforeUpdate() async validate(): Promise { diff --git a/packages/data-store/src/entities/contact/PartyEntity.ts b/packages/data-store/src/entities/contact/PartyEntity.ts index db7adc9de..43bb09279 100644 --- a/packages/data-store/src/entities/contact/PartyEntity.ts +++ b/packages/data-store/src/entities/contact/PartyEntity.ts @@ -78,6 +78,13 @@ export class PartyEntity extends BaseEntity { @UpdateDateColumn({ name: 'last_updated_at', nullable: false }) lastUpdatedAt!: Date + // By default, @UpdateDateColumn in TypeORM updates the timestamp only when the entity's top-level properties change. + @BeforeInsert() + @BeforeUpdate() + updateUpdatedDate(): void { + this.lastUpdatedAt = new Date() + } + @BeforeInsert() @BeforeUpdate() async checkUniqueTenantId(): Promise { diff --git a/packages/data-store/src/entities/contact/PartyRelationshipEntity.ts b/packages/data-store/src/entities/contact/PartyRelationshipEntity.ts index 7807b2058..2cc482262 100644 --- a/packages/data-store/src/entities/contact/PartyRelationshipEntity.ts +++ b/packages/data-store/src/entities/contact/PartyRelationshipEntity.ts @@ -44,6 +44,13 @@ export class PartyRelationshipEntity { @UpdateDateColumn({ name: 'last_updated_at', nullable: false }) lastUpdatedAt!: Date + // By default, @UpdateDateColumn in TypeORM updates the timestamp only when the entity's top-level properties change. + @BeforeInsert() + @BeforeUpdate() + updateUpdatedDate(): void { + this.lastUpdatedAt = new Date() + } + @BeforeInsert() @BeforeUpdate() async checkRelationshipSides(): Promise { diff --git a/packages/data-store/src/entities/contact/PartyTypeEntity.ts b/packages/data-store/src/entities/contact/PartyTypeEntity.ts index 472628203..8436b615d 100644 --- a/packages/data-store/src/entities/contact/PartyTypeEntity.ts +++ b/packages/data-store/src/entities/contact/PartyTypeEntity.ts @@ -37,6 +37,13 @@ export class PartyTypeEntity { @UpdateDateColumn({ name: 'last_updated_at', nullable: false }) lastUpdatedAt!: Date + // By default, @UpdateDateColumn in TypeORM updates the timestamp only when the entity's top-level properties change. + @BeforeInsert() + @BeforeUpdate() + updateUpdatedDate(): void { + this.lastUpdatedAt = new Date() + } + @BeforeInsert() @BeforeUpdate() async validate(): Promise { diff --git a/packages/data-store/src/entities/issuanceBranding/BaseLocaleBrandingEntity.ts b/packages/data-store/src/entities/issuanceBranding/BaseLocaleBrandingEntity.ts index f60a96101..6435f9e83 100644 --- a/packages/data-store/src/entities/issuanceBranding/BaseLocaleBrandingEntity.ts +++ b/packages/data-store/src/entities/issuanceBranding/BaseLocaleBrandingEntity.ts @@ -67,6 +67,13 @@ export class BaseLocaleBrandingEntity extends BaseEntity { @UpdateDateColumn({ name: 'last_updated_at', nullable: false }) lastUpdatedAt!: Date + // By default, @UpdateDateColumn in TypeORM updates the timestamp only when the entity's top-level properties change. + @BeforeInsert() + @BeforeUpdate() + updateUpdatedDate(): void { + this.lastUpdatedAt = new Date() + } + @BeforeInsert() @BeforeUpdate() async validate(): Promise { diff --git a/packages/data-store/src/entities/issuanceBranding/CredentialBrandingEntity.ts b/packages/data-store/src/entities/issuanceBranding/CredentialBrandingEntity.ts index 178d01521..b1161044a 100644 --- a/packages/data-store/src/entities/issuanceBranding/CredentialBrandingEntity.ts +++ b/packages/data-store/src/entities/issuanceBranding/CredentialBrandingEntity.ts @@ -48,6 +48,13 @@ export class CredentialBrandingEntity extends BaseEntity { @UpdateDateColumn({ name: 'last_updated_at', nullable: false }) lastUpdatedAt!: Date + // By default, @UpdateDateColumn in TypeORM updates the timestamp only when the entity's top-level properties change. + @BeforeInsert() + @BeforeUpdate() + updateUpdatedDate(): void { + this.lastUpdatedAt = new Date() + } + @BeforeInsert() @BeforeUpdate() async validate(): Promise { diff --git a/packages/data-store/src/entities/issuanceBranding/IssuerBrandingEntity.ts b/packages/data-store/src/entities/issuanceBranding/IssuerBrandingEntity.ts index e3e83ba44..404e94d2d 100644 --- a/packages/data-store/src/entities/issuanceBranding/IssuerBrandingEntity.ts +++ b/packages/data-store/src/entities/issuanceBranding/IssuerBrandingEntity.ts @@ -43,6 +43,13 @@ export class IssuerBrandingEntity extends BaseEntity { @UpdateDateColumn({ name: 'last_updated_at', nullable: false }) lastUpdatedAt!: Date + // By default, @UpdateDateColumn in TypeORM updates the timestamp only when the entity's top-level properties change. + @BeforeInsert() + @BeforeUpdate() + updateUpdatedDate(): void { + this.lastUpdatedAt = new Date() + } + @BeforeInsert() @BeforeUpdate() async validate(): Promise {