@sphereon/ssi-sdk.data-store 0.30.1-unstable.4 → 0.30.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +77 -77
  3. package/dist/contact/ContactStore.d.ts.map +1 -1
  4. package/dist/digitalCredential/DigitalCredentialStore.d.ts.map +1 -1
  5. package/dist/eventLogger/EventLoggerStore.d.ts.map +1 -1
  6. package/dist/issuanceBranding/IssuanceBrandingStore.d.ts.map +1 -1
  7. package/dist/migrations/internal-migrations-ormconfig.d.ts.map +1 -1
  8. package/dist/migrations/postgres/1708525189001-CreateDigitalCredential.js +33 -33
  9. package/dist/migrations/postgres/1708797018115-CreateMachineStateStore.js +16 -16
  10. package/dist/migrations/postgres/1715761125001-CreateContacts.js +33 -33
  11. package/dist/migrations/postgres/1716475165345-CreatePresentationDefinitions.js +12 -12
  12. package/dist/migrations/sqlite/1708525189002-CreateDigitalCredential.js +32 -32
  13. package/dist/migrations/sqlite/1708796002272-CreateMachineStateStore.js +15 -15
  14. package/dist/migrations/sqlite/1710438363002-CreateContacts.js +13 -13
  15. package/dist/migrations/sqlite/1715761125002-CreateContacts.js +32 -32
  16. package/dist/migrations/sqlite/1716475165344-CreatePresentationDefinitions.js +9 -9
  17. package/dist/presentationDefinition/PDStore.d.ts.map +1 -1
  18. package/dist/utils/SortingUtils.d.ts.map +1 -1
  19. package/dist/utils/contact/MappingUtils.d.ts.map +1 -1
  20. package/dist/utils/digitalCredential/MappingUtils.d.ts.map +1 -1
  21. package/dist/utils/digitalCredential/MappingUtils.js +4 -4
  22. package/dist/utils/digitalCredential/MappingUtils.js.map +1 -1
  23. package/dist/utils/presentationDefinition/MappingUtils.js +2 -2
  24. package/dist/utils/presentationDefinition/MappingUtils.js.map +1 -1
  25. package/package.json +8 -8
  26. package/src/__tests__/contact.entities.test.ts +2642 -2642
  27. package/src/__tests__/contact.store.test.ts +2649 -2649
  28. package/src/__tests__/digitalCredential.entities.test.ts +274 -274
  29. package/src/__tests__/digitalCredential.store.test.ts +330 -330
  30. package/src/__tests__/eventLogger.entities.test.ts +76 -76
  31. package/src/__tests__/eventLogger.store.test.ts +130 -130
  32. package/src/__tests__/issuanceBranding.entities.test.ts +846 -846
  33. package/src/__tests__/issuanceBranding.store.test.ts +1886 -1886
  34. package/src/__tests__/machineState.entities.test.ts +53 -53
  35. package/src/__tests__/machineState.store.test.ts +176 -176
  36. package/src/__tests__/pd-manager.entities.test.ts +73 -73
  37. package/src/__tests__/pd-manager.store.test.ts +193 -193
  38. package/src/contact/AbstractContactStore.ts +71 -71
  39. package/src/contact/ContactStore.ts +768 -768
  40. package/src/digitalCredential/AbstractDigitalCredentialStore.ts +21 -21
  41. package/src/digitalCredential/DigitalCredentialStore.ts +189 -189
  42. package/src/entities/contact/BaseContactEntity.ts +51 -51
  43. package/src/entities/contact/ConnectionEntity.ts +35 -35
  44. package/src/entities/contact/ContactMetadataItemEntity.ts +51 -51
  45. package/src/entities/contact/CorrelationIdentifierEntity.ts +43 -43
  46. package/src/entities/contact/DidAuthConfigEntity.ts +20 -20
  47. package/src/entities/contact/ElectronicAddressEntity.ts +70 -70
  48. package/src/entities/contact/IdentityEntity.ts +107 -107
  49. package/src/entities/contact/IdentityMetadataItemEntity.ts +48 -48
  50. package/src/entities/contact/NaturalPersonEntity.ts +44 -44
  51. package/src/entities/contact/OpenIdConfigEntity.ts +32 -32
  52. package/src/entities/contact/OrganizationEntity.ts +35 -35
  53. package/src/entities/contact/PartyEntity.ts +117 -117
  54. package/src/entities/contact/PartyRelationshipEntity.ts +68 -68
  55. package/src/entities/contact/PartyTypeEntity.ts +63 -63
  56. package/src/entities/contact/PhysicalAddressEntity.ts +95 -95
  57. package/src/entities/digitalCredential/DigitalCredentialEntity.ts +98 -98
  58. package/src/entities/eventLogger/AuditEventEntity.ts +92 -92
  59. package/src/entities/issuanceBranding/BackgroundAttributesEntity.ts +42 -42
  60. package/src/entities/issuanceBranding/BaseLocaleBrandingEntity.ts +87 -87
  61. package/src/entities/issuanceBranding/CredentialBrandingEntity.ts +79 -79
  62. package/src/entities/issuanceBranding/CredentialLocaleBrandingEntity.ts +33 -33
  63. package/src/entities/issuanceBranding/ImageAttributesEntity.ts +57 -57
  64. package/src/entities/issuanceBranding/ImageDimensionsEntity.ts +22 -22
  65. package/src/entities/issuanceBranding/IssuerBrandingEntity.ts +73 -73
  66. package/src/entities/issuanceBranding/IssuerLocaleBrandingEntity.ts +33 -33
  67. package/src/entities/issuanceBranding/TextAttributesEntity.ts +31 -31
  68. package/src/entities/machineState/MachineStateInfoEntity.ts +59 -59
  69. package/src/entities/presentationDefinition/PresentationDefinitionItemEntity.ts +44 -44
  70. package/src/entities/statusList2021/StatusList2021Entity.ts +96 -96
  71. package/src/entities/statusList2021/StatusList2021EntryEntity.ts +29 -29
  72. package/src/eventLogger/AbstractEventLoggerStore.ts +7 -7
  73. package/src/eventLogger/EventLoggerStore.ts +62 -62
  74. package/src/index.ts +160 -160
  75. package/src/issuanceBranding/IssuanceBrandingStore.ts +559 -559
  76. package/src/machineState/IAbstractMachineStateStore.ts +65 -65
  77. package/src/machineState/MachineStateStore.ts +149 -149
  78. package/src/migrations/generic/1-CreateContacts.ts +66 -66
  79. package/src/migrations/generic/10-CreatePresentationDefinitions.ts +66 -66
  80. package/src/migrations/generic/2-CreateIssuanceBranding.ts +64 -64
  81. package/src/migrations/generic/3-CreateContacts.ts +66 -66
  82. package/src/migrations/generic/4-CreateStatusList.ts +54 -54
  83. package/src/migrations/generic/5-CreateAuditEvents.ts +66 -66
  84. package/src/migrations/generic/6-CreateDigitalCredential.ts +66 -66
  85. package/src/migrations/generic/7-CreateMachineStateStore.ts +66 -66
  86. package/src/migrations/generic/8-CreateContacts.ts +66 -66
  87. package/src/migrations/generic/9-CreateContacts.ts +66 -66
  88. package/src/migrations/generic/index.ts +43 -43
  89. package/src/migrations/index.ts +10 -10
  90. package/src/migrations/postgres/1659463079428-CreateContacts.ts +63 -63
  91. package/src/migrations/postgres/1685628974232-CreateIssuanceBranding.ts +85 -85
  92. package/src/migrations/postgres/1690925872592-CreateContacts.ts +158 -158
  93. package/src/migrations/postgres/1693866470001-CreateStatusList.ts +24 -24
  94. package/src/migrations/postgres/1701634812183-CreateAuditEvents.ts +33 -33
  95. package/src/migrations/postgres/1708525189001-CreateDigitalCredential.ts +61 -61
  96. package/src/migrations/postgres/1708797018115-CreateMachineStateStore.ts +29 -29
  97. package/src/migrations/postgres/1710438363001-CreateContacts.ts +63 -63
  98. package/src/migrations/postgres/1715761125001-CreateContacts.ts +60 -60
  99. package/src/migrations/postgres/1716475165345-CreatePresentationDefinitions.ts +25 -25
  100. package/src/migrations/sqlite/1659463069549-CreateContacts.ts +110 -110
  101. package/src/migrations/sqlite/1685628973231-CreateIssuanceBranding.ts +119 -119
  102. package/src/migrations/sqlite/1690925872693-CreateContacts.ts +228 -228
  103. package/src/migrations/sqlite/1693866470000-CreateStatusList.ts +24 -24
  104. package/src/migrations/sqlite/1701634819487-CreateAuditEvents.ts +15 -15
  105. package/src/migrations/sqlite/1708525189002-CreateDigitalCredential.ts +46 -46
  106. package/src/migrations/sqlite/1708796002272-CreateMachineStateStore.ts +28 -28
  107. package/src/migrations/sqlite/1710438363002-CreateContacts.ts +83 -83
  108. package/src/migrations/sqlite/1715761125002-CreateContacts.ts +59 -59
  109. package/src/migrations/sqlite/1716475165344-CreatePresentationDefinitions.ts +24 -24
  110. package/src/presentationDefinition/AbstractPDStore.ts +20 -20
  111. package/src/presentationDefinition/PDStore.ts +185 -185
  112. package/src/statusList/IStatusListStore.ts +44 -44
  113. package/src/statusList/StatusListStore.ts +236 -236
  114. package/src/types/contact/IAbstractContactStore.ts +161 -161
  115. package/src/types/contact/contact.ts +295 -295
  116. package/src/types/digitalCredential/IAbstractDigitalCredentialStore.ts +42 -42
  117. package/src/types/digitalCredential/digitalCredential.ts +102 -102
  118. package/src/types/eventLogger/IAbstractEventLoggerStore.ts +12 -12
  119. package/src/types/eventLogger/eventLogger.ts +3 -3
  120. package/src/types/index.ts +14 -14
  121. package/src/types/machineState/IAbstractMachineStateStore.ts +68 -68
  122. package/src/types/presentationDefinition/IAbstractPDStore.ts +25 -25
  123. package/src/types/presentationDefinition/presentationDefinition.ts +17 -17
  124. package/src/utils/SortingUtils.ts +16 -16
  125. package/src/utils/contact/MappingUtils.ts +506 -506
  126. package/src/utils/digitalCredential/MappingUtils.ts +160 -160
  127. package/src/utils/hasher.ts +19 -19
  128. package/src/utils/presentationDefinition/MappingUtils.ts +52 -52
  129. package/dist/entities/contact/IMetadataEntity.d.ts +0 -8
  130. package/dist/entities/contact/IMetadataEntity.d.ts.map +0 -1
  131. package/dist/entities/contact/IMetadataEntity.js +0 -2
  132. package/dist/entities/contact/IMetadataEntity.js.map +0 -1
  133. package/dist/migrations/generic/8-CreatePresentationDefinitions.d.ts +0 -7
  134. package/dist/migrations/generic/8-CreatePresentationDefinitions.d.ts.map +0 -1
  135. package/dist/migrations/generic/8-CreatePresentationDefinitions.js +0 -78
  136. package/dist/migrations/generic/8-CreatePresentationDefinitions.js.map +0 -1
@@ -1,768 +1,768 @@
1
- import { OrPromise } from '@sphereon/ssi-types'
2
- import { BaseEntity, DataSource, FindOptionsWhere, In, Repository } from 'typeorm'
3
- import Debug from 'debug'
4
- import { AbstractContactStore } from './AbstractContactStore'
5
- import { PartyEntity } from '../entities/contact/PartyEntity'
6
- import { IdentityEntity } from '../entities/contact/IdentityEntity'
7
- import { IdentityMetadataItemEntity } from '../entities/contact/IdentityMetadataItemEntity'
8
- import { CorrelationIdentifierEntity } from '../entities/contact/CorrelationIdentifierEntity'
9
- import { ConnectionEntity } from '../entities/contact/ConnectionEntity'
10
- import { BaseConfigEntity } from '../entities/contact/BaseConfigEntity'
11
- import { PartyRelationshipEntity } from '../entities/contact/PartyRelationshipEntity'
12
- import { PartyTypeEntity } from '../entities/contact/PartyTypeEntity'
13
- import { BaseContactEntity } from '../entities/contact/BaseContactEntity'
14
- import { ElectronicAddressEntity } from '../entities/contact/ElectronicAddressEntity'
15
- import { PhysicalAddressEntity } from '../entities/contact/PhysicalAddressEntity'
16
- import {
17
- electronicAddressEntityFrom,
18
- electronicAddressFrom,
19
- identityEntityFrom,
20
- identityFrom,
21
- isDidAuthConfig,
22
- isNaturalPerson,
23
- isOpenIdConfig,
24
- isOrganization,
25
- partyEntityFrom,
26
- partyFrom,
27
- partyRelationshipEntityFrom,
28
- partyRelationshipFrom,
29
- partyTypeEntityFrom,
30
- partyTypeFrom,
31
- physicalAddressEntityFrom,
32
- physicalAddressFrom,
33
- } from '../utils/contact/MappingUtils'
34
- import {
35
- AddElectronicAddressArgs,
36
- AddIdentityArgs,
37
- AddPartyArgs,
38
- AddPartyTypeArgs,
39
- AddPhysicalAddressArgs,
40
- AddRelationshipArgs,
41
- ConnectionType,
42
- CorrelationIdentifierType,
43
- ElectronicAddress,
44
- GetElectronicAddressArgs,
45
- GetElectronicAddressesArgs,
46
- GetIdentitiesArgs,
47
- GetIdentityArgs,
48
- GetPartiesArgs,
49
- GetPartyArgs,
50
- GetPartyTypeArgs,
51
- GetPartyTypesArgs,
52
- GetPhysicalAddressArgs,
53
- GetPhysicalAddressesArgs,
54
- GetRelationshipArgs,
55
- GetRelationshipsArgs,
56
- IMetadataEntity,
57
- Identity,
58
- MetadataItem,
59
- MetadataTypes,
60
- NonPersistedConnectionConfig,
61
- NonPersistedContact,
62
- Party,
63
- PartyRelationship,
64
- PartyType,
65
- PartyTypeType,
66
- PhysicalAddress,
67
- RemoveElectronicAddressArgs,
68
- RemoveIdentityArgs,
69
- RemovePartyArgs,
70
- RemovePartyTypeArgs,
71
- RemovePhysicalAddressArgs,
72
- RemoveRelationshipArgs,
73
- UpdateElectronicAddressArgs,
74
- UpdateIdentityArgs,
75
- UpdatePartyArgs,
76
- UpdatePartyTypeArgs,
77
- UpdatePhysicalAddressArgs,
78
- UpdateRelationshipArgs,
79
- } from '../types'
80
-
81
- const debug: Debug.Debugger = Debug('sphereon:ssi-sdk:contact-store')
82
-
83
- export class ContactStore extends AbstractContactStore {
84
- private readonly dbConnection: OrPromise<DataSource>
85
-
86
- constructor(dbConnection: OrPromise<DataSource>) {
87
- super()
88
- this.dbConnection = dbConnection
89
- }
90
-
91
- getParty = async (args: GetPartyArgs): Promise<Party> => {
92
- const { partyId } = args
93
- const result: PartyEntity | null = await (await this.dbConnection).getRepository(PartyEntity).findOne({
94
- where: { id: partyId },
95
- })
96
-
97
- if (!result) {
98
- return Promise.reject(Error(`No party found for id: ${partyId}`))
99
- }
100
-
101
- return partyFrom(result)
102
- }
103
-
104
- getParties = async (args?: GetPartiesArgs): Promise<Array<Party>> => {
105
- debug('getParties()', args)
106
- const { filter } = args ?? {}
107
- const partyRepository = (await this.dbConnection).getRepository(PartyEntity)
108
- const filterConditions = this.buildFilters(filter)
109
- const initialResult = await partyRepository.find({ select: ['id'], where: filterConditions })
110
-
111
- // Fetch the complete entities based on the initial result IDs
112
- const result = await partyRepository.find({ where: { id: In(initialResult.map((party) => party.id)) } })
113
- debug(`getParties() resulted in ${result.length} parties`)
114
- return result.map(partyFrom)
115
- }
116
-
117
- addParty = async (args: AddPartyArgs): Promise<Party> => {
118
- const { identities, contact, partyType } = args
119
-
120
- const partyRepository: Repository<PartyEntity> = (await this.dbConnection).getRepository(PartyEntity)
121
-
122
- if (!this.hasCorrectPartyType(partyType.type, contact)) {
123
- return Promise.reject(Error(`Party type ${partyType.type}, does not match for provided contact`))
124
- }
125
-
126
- for (const identity of identities ?? []) {
127
- if (identity.identifier.type === CorrelationIdentifierType.URL) {
128
- if (!identity.connection) {
129
- return Promise.reject(Error(`Identity with correlation type ${CorrelationIdentifierType.URL} should contain a connection`))
130
- }
131
-
132
- if (!this.hasCorrectConnectionConfig(identity.connection.type, identity.connection.config)) {
133
- return Promise.reject(Error(`Connection type ${identity.connection.type}, does not match for provided config`))
134
- }
135
- }
136
- }
137
-
138
- const partyEntity: PartyEntity = partyEntityFrom(args)
139
- debug('Adding party', args)
140
- const createdResult: PartyEntity = await partyRepository.save(partyEntity)
141
-
142
- return partyFrom(createdResult)
143
- }
144
-
145
- updateParty = async (args: UpdatePartyArgs): Promise<Party> => {
146
- const { party } = args
147
- const partyRepository: Repository<PartyEntity> = (await this.dbConnection).getRepository(PartyEntity)
148
- const result: PartyEntity | null = await partyRepository.findOne({
149
- where: { id: party.id },
150
- })
151
-
152
- if (!result) {
153
- return Promise.reject(Error(`No party found for id: ${party.id}`))
154
- }
155
-
156
- const updatedParty = {
157
- ...party,
158
- identities: result.identities,
159
- type: result.partyType,
160
- relationships: result.relationships,
161
- electronicAddresses: result.electronicAddresses,
162
- }
163
-
164
- debug('Updating party', party)
165
- const updatedResult: PartyEntity = await partyRepository.save(updatedParty, { transaction: true })
166
-
167
- return partyFrom(updatedResult)
168
- }
169
-
170
- removeParty = async (args: RemovePartyArgs): Promise<void> => {
171
- const { partyId } = args
172
- const partyRepository: Repository<PartyEntity> = (await this.dbConnection).getRepository(PartyEntity)
173
- debug('Removing party', partyId)
174
- partyRepository
175
- .findOneById(partyId)
176
- .then(async (party: PartyEntity | null): Promise<void> => {
177
- if (!party) {
178
- await Promise.reject(Error(`Unable to find the party with id to remove: ${partyId}`))
179
- } else {
180
- await this.deleteIdentities(party.identities)
181
- await this.deleteElectronicAddresses(party.electronicAddresses)
182
- await this.deletePhysicalAddresses(party.physicalAddresses)
183
-
184
- await partyRepository
185
- .delete({ id: partyId })
186
- .catch((error) => Promise.reject(Error(`Unable to remove party with id: ${partyId}. ${error}`)))
187
-
188
- const partyContactRepository: Repository<BaseContactEntity> = (await this.dbConnection).getRepository(BaseContactEntity)
189
- await partyContactRepository
190
- .delete({ id: party.contact.id })
191
- .catch((error) => Promise.reject(Error(`Unable to remove party contact with id: ${party.contact.id}. ${error}`)))
192
- }
193
- })
194
- .catch((error) => Promise.reject(Error(`Unable to remove party with id: ${partyId}. ${error}`)))
195
- }
196
-
197
- getIdentity = async (args: GetIdentityArgs): Promise<Identity> => {
198
- const { identityId } = args
199
- const result: IdentityEntity | null = await (await this.dbConnection).getRepository(IdentityEntity).findOne({
200
- where: { id: identityId },
201
- })
202
-
203
- if (!result) {
204
- return Promise.reject(Error(`No identity found for id: ${identityId}`))
205
- }
206
-
207
- return identityFrom(result)
208
- }
209
-
210
- getIdentities = async (args?: GetIdentitiesArgs): Promise<Array<Identity>> => {
211
- const { filter } = args ?? {}
212
- const identityRepository = (await this.dbConnection).getRepository(IdentityEntity)
213
- const filterConditions = this.buildFilters(filter)
214
- const initialResult = await identityRepository.find({ select: ['id'], where: filterConditions })
215
-
216
- const result = await identityRepository.find({ where: { id: In(initialResult.map((identity) => identity.id)) } })
217
- return result.map(identityFrom)
218
- }
219
-
220
- addIdentity = async (args: AddIdentityArgs): Promise<Identity> => {
221
- const { identity, partyId } = args
222
- const party: PartyEntity | null = await (await this.dbConnection).getRepository(PartyEntity).findOne({
223
- where: { id: partyId },
224
- })
225
-
226
- if (!party) {
227
- return Promise.reject(Error(`No party found for id: ${partyId}`))
228
- }
229
-
230
- if (identity.identifier.type === CorrelationIdentifierType.URL) {
231
- if (!identity.connection) {
232
- return Promise.reject(Error(`Identity with correlation type ${CorrelationIdentifierType.URL} should contain a connection`))
233
- }
234
-
235
- if (!this.hasCorrectConnectionConfig(identity.connection.type, identity.connection.config)) {
236
- return Promise.reject(Error(`Connection type ${identity.connection.type}, does not match for provided config`))
237
- }
238
- }
239
-
240
- const identityEntity: IdentityEntity = identityEntityFrom(identity)
241
- identityEntity.party = party
242
- debug('Adding identity', identity)
243
- const result: IdentityEntity = await (await this.dbConnection).getRepository(IdentityEntity).save(identityEntity, {
244
- transaction: true,
245
- })
246
-
247
- return identityFrom(result)
248
- }
249
-
250
- updateIdentity = async (args: UpdateIdentityArgs): Promise<Identity> => {
251
- const { identity } = args
252
- const identityRepository: Repository<IdentityEntity> = (await this.dbConnection).getRepository(IdentityEntity)
253
- const result: IdentityEntity | null = await identityRepository.findOne({
254
- where: { id: identity.id },
255
- })
256
-
257
- if (!result) {
258
- return Promise.reject(Error(`No identity found for id: ${identity.id}`))
259
- }
260
-
261
- if (identity.identifier.type === CorrelationIdentifierType.URL) {
262
- if (!identity.connection) {
263
- return Promise.reject(Error(`Identity with correlation type ${CorrelationIdentifierType.URL} should contain a connection`))
264
- }
265
-
266
- if (!this.hasCorrectConnectionConfig(identity.connection.type, identity.connection.config)) {
267
- return Promise.reject(Error(`Connection type ${identity.connection.type}, does not match for provided config`))
268
- }
269
- }
270
-
271
- debug('Updating identity', identity)
272
- const updatedResult: IdentityEntity = await identityRepository.save(identity, { transaction: true })
273
-
274
- return identityFrom(updatedResult)
275
- }
276
-
277
- removeIdentity = async (args: RemoveIdentityArgs): Promise<void> => {
278
- const { identityId } = args
279
- const identity: IdentityEntity | null = await (await this.dbConnection).getRepository(IdentityEntity).findOne({
280
- where: { id: identityId },
281
- })
282
-
283
- if (!identity) {
284
- return Promise.reject(Error(`No identity found for id: ${identityId}`))
285
- }
286
-
287
- debug('Removing identity', identityId)
288
-
289
- await this.deleteIdentities([identity])
290
- }
291
-
292
- addRelationship = async (args: AddRelationshipArgs): Promise<PartyRelationship> => {
293
- const { leftId, rightId } = args
294
- return this.assertRelationshipSides(leftId, rightId).then(async (): Promise<PartyRelationship> => {
295
- const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({
296
- leftId,
297
- rightId,
298
- })
299
- debug('Adding party relationship', relationship)
300
-
301
- const createdResult: PartyRelationshipEntity = await (await this.dbConnection).getRepository(PartyRelationshipEntity).save(relationship)
302
-
303
- return partyRelationshipFrom(createdResult)
304
- })
305
- }
306
-
307
- getRelationship = async (args: GetRelationshipArgs): Promise<PartyRelationship> => {
308
- const { relationshipId } = args
309
- const result: PartyRelationshipEntity | null = await (await this.dbConnection).getRepository(PartyRelationshipEntity).findOne({
310
- where: { id: relationshipId },
311
- })
312
-
313
- if (!result) {
314
- return Promise.reject(Error(`No relationship found for id: ${relationshipId}`))
315
- }
316
-
317
- return partyRelationshipFrom(result)
318
- }
319
-
320
- getRelationships = async (args?: GetRelationshipsArgs): Promise<Array<PartyRelationship>> => {
321
- const { filter } = args ?? {}
322
- const partyRelationshipRepository: Repository<PartyRelationshipEntity> = (await this.dbConnection).getRepository(PartyRelationshipEntity)
323
- const initialResult: Array<PartyRelationshipEntity> = await partyRelationshipRepository.find({
324
- ...(filter && { where: filter }),
325
- })
326
-
327
- const result: Array<PartyRelationshipEntity> = await partyRelationshipRepository.find({
328
- where: {
329
- id: In(initialResult.map((partyRelationship: PartyRelationshipEntity) => partyRelationship.id)),
330
- },
331
- })
332
-
333
- return result.map((partyRelationship: PartyRelationshipEntity) => partyRelationshipFrom(partyRelationship))
334
- }
335
-
336
- updateRelationship = async (args: UpdateRelationshipArgs): Promise<PartyRelationship> => {
337
- const { relationship } = args
338
- const partyRelationshipRepository: Repository<PartyRelationshipEntity> = (await this.dbConnection).getRepository(PartyRelationshipEntity)
339
- const result: PartyRelationshipEntity | null = await partyRelationshipRepository.findOne({
340
- where: { id: relationship.id },
341
- })
342
-
343
- if (!result) {
344
- return Promise.reject(Error(`No party relationship found for id: ${relationship.id}`))
345
- }
346
-
347
- return this.assertRelationshipSides(relationship.leftId, relationship.rightId).then(async (): Promise<PartyRelationship> => {
348
- debug('Updating party relationship', relationship)
349
- const updatedResult: PartyRelationshipEntity = await partyRelationshipRepository.save(relationship, { transaction: true })
350
-
351
- return partyRelationshipFrom(updatedResult)
352
- })
353
- }
354
-
355
- removeRelationship = async (args: RemoveRelationshipArgs): Promise<void> => {
356
- const { relationshipId } = args
357
- const partyRelationshipRepository: Repository<PartyRelationshipEntity> = (await this.dbConnection).getRepository(PartyRelationshipEntity)
358
- const relationship: PartyRelationshipEntity | null = await partyRelationshipRepository.findOne({
359
- where: { id: relationshipId },
360
- })
361
-
362
- if (!relationship) {
363
- return Promise.reject(Error(`No relationship found for id: ${relationshipId}`))
364
- }
365
-
366
- debug('Removing relationship', relationshipId)
367
-
368
- await partyRelationshipRepository.delete(relationshipId)
369
- }
370
-
371
- addPartyType = async (args: AddPartyTypeArgs): Promise<PartyType> => {
372
- const partyEntity: PartyTypeEntity = partyTypeEntityFrom(args)
373
- debug('Adding party type', args)
374
- const createdResult: PartyTypeEntity = await (await this.dbConnection).getRepository(PartyTypeEntity).save(partyEntity)
375
-
376
- return partyTypeFrom(createdResult)
377
- }
378
-
379
- getPartyType = async (args: GetPartyTypeArgs): Promise<PartyType> => {
380
- const { partyTypeId } = args
381
- const result: PartyTypeEntity | null = await (await this.dbConnection).getRepository(PartyTypeEntity).findOne({
382
- where: { id: partyTypeId },
383
- })
384
-
385
- if (!result) {
386
- return Promise.reject(Error(`No party type found for id: ${partyTypeId}`))
387
- }
388
-
389
- return partyTypeFrom(result)
390
- }
391
-
392
- getPartyTypes = async (args?: GetPartyTypesArgs): Promise<Array<PartyType>> => {
393
- const { filter } = args ?? {}
394
- const partyTypeRepository: Repository<PartyTypeEntity> = (await this.dbConnection).getRepository(PartyTypeEntity)
395
- const initialResult: Array<PartyTypeEntity> = await partyTypeRepository.find({
396
- ...(filter && { where: filter }),
397
- })
398
-
399
- const result: Array<PartyTypeEntity> = await partyTypeRepository.find({
400
- where: {
401
- id: In(initialResult.map((partyType: PartyTypeEntity) => partyType.id)),
402
- },
403
- })
404
-
405
- return result.map((partyType: PartyTypeEntity) => partyTypeFrom(partyType))
406
- }
407
-
408
- updatePartyType = async (args: UpdatePartyTypeArgs): Promise<PartyType> => {
409
- const { partyType } = args
410
- const partyTypeRepository: Repository<PartyTypeEntity> = (await this.dbConnection).getRepository(PartyTypeEntity)
411
- const result: PartyTypeEntity | null = await partyTypeRepository.findOne({
412
- where: { id: partyType.id },
413
- })
414
-
415
- if (!result) {
416
- return Promise.reject(Error(`No party type found for id: ${partyType.id}`))
417
- }
418
-
419
- debug('Updating party type', partyType)
420
- const updatedResult: PartyTypeEntity = await partyTypeRepository.save(partyType, { transaction: true })
421
-
422
- return partyTypeFrom(updatedResult)
423
- }
424
-
425
- removePartyType = async (args: RemovePartyTypeArgs): Promise<void> => {
426
- const { partyTypeId } = args
427
- const parties: Array<PartyEntity> = await (await this.dbConnection).getRepository(PartyEntity).find({
428
- where: {
429
- partyType: {
430
- id: partyTypeId,
431
- },
432
- },
433
- })
434
-
435
- if (parties.length > 0) {
436
- return Promise.reject(Error(`Unable to remove party type with id: ${partyTypeId}. Party type is in use`))
437
- }
438
-
439
- const partyTypeRepository: Repository<PartyTypeEntity> = (await this.dbConnection).getRepository(PartyTypeEntity)
440
- const partyType: PartyTypeEntity | null = await partyTypeRepository.findOne({
441
- where: { id: partyTypeId },
442
- })
443
-
444
- if (!partyType) {
445
- return Promise.reject(Error(`No party type found for id: ${partyTypeId}`))
446
- }
447
-
448
- debug('Removing party type', partyTypeId)
449
-
450
- await partyTypeRepository.delete(partyTypeId)
451
- }
452
-
453
- getElectronicAddress = async (args: GetElectronicAddressArgs): Promise<ElectronicAddress> => {
454
- const { electronicAddressId } = args
455
- const result: ElectronicAddressEntity | null = await (await this.dbConnection).getRepository(ElectronicAddressEntity).findOne({
456
- where: { id: electronicAddressId },
457
- })
458
-
459
- if (!result) {
460
- return Promise.reject(Error(`No electronic address found for id: ${electronicAddressId}`))
461
- }
462
-
463
- return electronicAddressFrom(result)
464
- }
465
-
466
- getElectronicAddresses = async (args?: GetElectronicAddressesArgs): Promise<Array<ElectronicAddress>> => {
467
- const { filter } = args ?? {}
468
- const electronicAddressRepository: Repository<ElectronicAddressEntity> = (await this.dbConnection).getRepository(ElectronicAddressEntity)
469
- const initialResult: Array<ElectronicAddressEntity> = await electronicAddressRepository.find({
470
- ...(filter && { where: filter }),
471
- })
472
-
473
- const result: Array<ElectronicAddressEntity> = await electronicAddressRepository.find({
474
- where: {
475
- id: In(initialResult.map((electronicAddress: ElectronicAddressEntity) => electronicAddress.id)),
476
- },
477
- })
478
-
479
- return result.map((electronicAddress: ElectronicAddressEntity) => electronicAddressFrom(electronicAddress))
480
- }
481
-
482
- addElectronicAddress = async (args: AddElectronicAddressArgs): Promise<ElectronicAddress> => {
483
- const { electronicAddress, partyId } = args
484
- const party: PartyEntity | null = await (await this.dbConnection).getRepository(PartyEntity).findOne({
485
- where: { id: partyId },
486
- })
487
-
488
- if (!party) {
489
- return Promise.reject(Error(`No party found for id: ${partyId}`))
490
- }
491
-
492
- const electronicAddressEntity: ElectronicAddressEntity = electronicAddressEntityFrom(electronicAddress)
493
- electronicAddressEntity.party = party
494
- debug('Adding electronic address', electronicAddress)
495
- const result: ElectronicAddressEntity = await (await this.dbConnection).getRepository(ElectronicAddressEntity).save(electronicAddressEntity, {
496
- transaction: true,
497
- })
498
-
499
- return electronicAddressFrom(result)
500
- }
501
-
502
- updateElectronicAddress = async (args: UpdateElectronicAddressArgs): Promise<ElectronicAddress> => {
503
- const { electronicAddress } = args
504
- const electronicAddressRepository: Repository<ElectronicAddressEntity> = (await this.dbConnection).getRepository(ElectronicAddressEntity)
505
- const result: ElectronicAddressEntity | null = await electronicAddressRepository.findOne({
506
- where: { id: electronicAddress.id },
507
- })
508
-
509
- if (!result) {
510
- return Promise.reject(Error(`No electronic address found for id: ${electronicAddress.id}`))
511
- }
512
-
513
- debug('Updating electronic address', electronicAddress)
514
- const updatedResult: ElectronicAddressEntity = await electronicAddressRepository.save(electronicAddress, { transaction: true })
515
-
516
- return electronicAddressFrom(updatedResult)
517
- }
518
-
519
- removeElectronicAddress = async (args: RemoveElectronicAddressArgs): Promise<void> => {
520
- const { electronicAddressId } = args
521
- const electronicAddressRepository: Repository<ElectronicAddressEntity> = (await this.dbConnection).getRepository(ElectronicAddressEntity)
522
- const electronicAddress: ElectronicAddressEntity | null = await electronicAddressRepository.findOne({
523
- where: { id: electronicAddressId },
524
- })
525
-
526
- if (!electronicAddress) {
527
- return Promise.reject(Error(`No electronic address found for id: ${electronicAddressId}`))
528
- }
529
-
530
- debug('Removing electronic address', electronicAddressId)
531
-
532
- await electronicAddressRepository.delete(electronicAddressId)
533
- }
534
-
535
- getPhysicalAddress = async (args: GetPhysicalAddressArgs): Promise<PhysicalAddress> => {
536
- const { physicalAddressId } = args
537
- const result: PhysicalAddressEntity | null = await (await this.dbConnection).getRepository(PhysicalAddressEntity).findOne({
538
- where: { id: physicalAddressId },
539
- })
540
-
541
- if (!result) {
542
- return Promise.reject(Error(`No physical address found for id: ${physicalAddressId}`))
543
- }
544
-
545
- return physicalAddressFrom(result)
546
- }
547
-
548
- getPhysicalAddresses = async (args?: GetPhysicalAddressesArgs): Promise<Array<PhysicalAddress>> => {
549
- const { filter } = args ?? {}
550
- const physicalAddressRepository: Repository<PhysicalAddressEntity> = (await this.dbConnection).getRepository(PhysicalAddressEntity)
551
- const initialResult: Array<PhysicalAddressEntity> = await physicalAddressRepository.find({
552
- ...(filter && { where: filter }),
553
- })
554
-
555
- const result: Array<PhysicalAddressEntity> = await physicalAddressRepository.find({
556
- where: {
557
- id: In(initialResult.map((physicalAddress: PhysicalAddressEntity) => physicalAddress.id)),
558
- },
559
- })
560
-
561
- return result.map((physicalAddress: PhysicalAddressEntity) => physicalAddressFrom(physicalAddress))
562
- }
563
-
564
- addPhysicalAddress = async (args: AddPhysicalAddressArgs): Promise<PhysicalAddress> => {
565
- const { physicalAddress, partyId } = args
566
- const party: PartyEntity | null = await (await this.dbConnection).getRepository(PartyEntity).findOne({
567
- where: { id: partyId },
568
- })
569
-
570
- if (!party) {
571
- return Promise.reject(Error(`No party found for id: ${partyId}`))
572
- }
573
-
574
- const physicalAddressEntity: PhysicalAddressEntity = physicalAddressEntityFrom(physicalAddress)
575
- physicalAddressEntity.party = party
576
- debug('Adding physical address', physicalAddress)
577
- const result: PhysicalAddressEntity = await (await this.dbConnection).getRepository(PhysicalAddressEntity).save(physicalAddressEntity, {
578
- transaction: true,
579
- })
580
-
581
- return physicalAddressFrom(result)
582
- }
583
-
584
- updatePhysicalAddress = async (args: UpdatePhysicalAddressArgs): Promise<PhysicalAddress> => {
585
- const { physicalAddress } = args
586
- const physicalAddressRepository: Repository<PhysicalAddressEntity> = (await this.dbConnection).getRepository(PhysicalAddressEntity)
587
- const result: PhysicalAddressEntity | null = await physicalAddressRepository.findOne({
588
- where: { id: physicalAddress.id },
589
- })
590
-
591
- if (!result) {
592
- return Promise.reject(Error(`No physical address found for id: ${physicalAddress.id}`))
593
- }
594
-
595
- debug('Updating physical address', physicalAddress)
596
- const updatedResult: PhysicalAddressEntity = await physicalAddressRepository.save(physicalAddress, { transaction: true })
597
-
598
- return physicalAddressFrom(updatedResult)
599
- }
600
-
601
- removePhysicalAddress = async (args: RemovePhysicalAddressArgs): Promise<void> => {
602
- const { physicalAddressId } = args
603
- const physicalAddressRepository: Repository<PhysicalAddressEntity> = (await this.dbConnection).getRepository(PhysicalAddressEntity)
604
- const physicalAddress: PhysicalAddressEntity | null = await physicalAddressRepository.findOne({
605
- where: { id: physicalAddressId },
606
- })
607
-
608
- if (!physicalAddress) {
609
- return Promise.reject(Error(`No physical address found for id: ${physicalAddressId}`))
610
- }
611
-
612
- debug('Removing physical address', physicalAddressId)
613
-
614
- await physicalAddressRepository.delete(physicalAddressId)
615
- }
616
-
617
- private hasCorrectConnectionConfig = (type: ConnectionType, config: NonPersistedConnectionConfig): boolean => {
618
- switch (type) {
619
- case ConnectionType.OPENID_CONNECT:
620
- return isOpenIdConfig(config)
621
- case ConnectionType.SIOPv2:
622
- return isDidAuthConfig(config)
623
- default:
624
- throw new Error('Connection type not supported')
625
- }
626
- }
627
-
628
- private hasCorrectPartyType = (type: PartyTypeType, contact: NonPersistedContact): boolean => {
629
- switch (type) {
630
- case PartyTypeType.NATURAL_PERSON:
631
- return isNaturalPerson(contact)
632
- case PartyTypeType.ORGANIZATION:
633
- return isOrganization(contact)
634
- default:
635
- throw new Error('Party type not supported')
636
- }
637
- }
638
-
639
- private deleteIdentities = async (identities: Array<IdentityEntity>): Promise<void> => {
640
- debug('Removing identities', identities)
641
-
642
- const connection: DataSource = await this.dbConnection
643
- const correlationIdentifierRepository: Repository<CorrelationIdentifierEntity> = connection.getRepository(CorrelationIdentifierEntity)
644
- const baseConfigRepository: Repository<BaseConfigEntity> = connection.getRepository(BaseConfigEntity)
645
- const connectionRepository: Repository<ConnectionEntity> = connection.getRepository(ConnectionEntity)
646
- const identityMetadataItemRepository: Repository<IdentityMetadataItemEntity> = connection.getRepository(IdentityMetadataItemEntity)
647
- const identityRepository: Repository<IdentityEntity> = connection.getRepository(IdentityEntity)
648
-
649
- identities.map(async (identity: IdentityEntity): Promise<void> => {
650
- await correlationIdentifierRepository
651
- .delete(identity.identifier.id)
652
- .catch((error) => Promise.reject(Error(`Unable to remove identity.identifier with id ${identity.identifier.id}. ${error}`)))
653
-
654
- if (identity.connection) {
655
- await baseConfigRepository.delete(identity.connection.config.id)
656
- await connectionRepository
657
- .delete(identity.connection.id)
658
- .catch((error) => Promise.reject(Error(`Unable to remove identity.connection with id ${identity.connection?.id}. ${error}`)))
659
- }
660
-
661
- if (identity.metadata) {
662
- identity.metadata.map(async (metadataItem: IdentityMetadataItemEntity): Promise<void> => {
663
- await identityMetadataItemRepository
664
- .delete(metadataItem.id)
665
- .catch((error) => Promise.reject(Error(`Unable to remove identity.metadataItem with id ${metadataItem.id}. ${error}`)))
666
- })
667
- }
668
-
669
- await identityRepository
670
- .delete(identity.id)
671
- .catch((error) => Promise.reject(Error(`Unable to remove identity with id ${identity.id}. ${error}`)))
672
- })
673
- }
674
-
675
- private deleteElectronicAddresses = async (electronicAddresses: Array<ElectronicAddressEntity>): Promise<void> => {
676
- debug('Removing electronic addresses', electronicAddresses)
677
-
678
- const electronicAddressRepository: Repository<ElectronicAddressEntity> = (await this.dbConnection).getRepository(ElectronicAddressEntity)
679
- electronicAddresses.map(async (electronicAddress: ElectronicAddressEntity): Promise<void> => {
680
- await electronicAddressRepository
681
- .delete(electronicAddress.id)
682
- .catch((error) => Promise.reject(Error(`Unable to remove electronic address with id ${electronicAddress.id}. ${error}`)))
683
- })
684
- }
685
-
686
- private deletePhysicalAddresses = async (physicalAddresses: Array<PhysicalAddressEntity>): Promise<void> => {
687
- debug('Removing physical addresses', physicalAddresses)
688
-
689
- const physicalAddressRepository: Repository<PhysicalAddressEntity> = (await this.dbConnection).getRepository(PhysicalAddressEntity)
690
- physicalAddresses.map(async (physicalAddress: PhysicalAddressEntity): Promise<void> => {
691
- await physicalAddressRepository
692
- .delete(physicalAddress.id)
693
- .catch((error) => Promise.reject(Error(`Unable to remove physical address with id ${physicalAddress.id}. ${error}`)))
694
- })
695
- }
696
-
697
- private assertRelationshipSides = async (leftId: string, rightId: string): Promise<void> => {
698
- const partyRepository: Repository<PartyEntity> = (await this.dbConnection).getRepository(PartyEntity)
699
- const leftParty: PartyEntity | null = await partyRepository.findOne({
700
- where: { id: leftId },
701
- })
702
-
703
- if (!leftParty) {
704
- return Promise.reject(Error(`No party found for left side of the relationship, party id: ${leftId}`))
705
- }
706
-
707
- const rightParty: PartyEntity | null = await partyRepository.findOne({
708
- where: { id: rightId },
709
- })
710
-
711
- if (!rightParty) {
712
- return Promise.reject(Error(`No party found for right side of the relationship, party id: ${rightId}`))
713
- }
714
- }
715
-
716
- private buildFilters = <T extends BaseEntity>(filter?: Array<Record<string, any>>): Array<FindOptionsWhere<T>> | FindOptionsWhere<T> => {
717
- if (!filter) return {}
718
-
719
- return filter.map((condition) => this.processCondition(condition))
720
- }
721
-
722
- private processCondition = (condition: Record<string, any>): Record<string, any> => {
723
- const conditionObject: Record<string, any> = {}
724
-
725
- Object.keys(condition).forEach((key) => {
726
- const value = condition[key]
727
-
728
- if (key === 'metadata' && value) {
729
- conditionObject[key] = this.buildMetadataCondition(value)
730
- } else if (typeof value === 'object' && value !== null) {
731
- conditionObject[key] = this.processCondition(value)
732
- } else {
733
- conditionObject[key] = value
734
- }
735
- })
736
-
737
- return conditionObject
738
- }
739
-
740
- private buildMetadataCondition = <T extends MetadataItem<MetadataTypes>>(metadata: Partial<T>): FindOptionsWhere<IMetadataEntity> => {
741
- const metadataCondition: FindOptionsWhere<any> = {
742
- label: metadata.label,
743
- }
744
-
745
- switch (typeof metadata.value) {
746
- case 'string':
747
- metadataCondition.stringValue = metadata.value as string
748
- break
749
- case 'number':
750
- metadataCondition.numberValue = metadata.value as number
751
- break
752
- case 'boolean':
753
- metadataCondition.boolValue = metadata.value as boolean
754
- break
755
- case 'object':
756
- if (metadata.value instanceof Date) {
757
- metadataCondition.dateValue = metadata.value as Date
758
- } else {
759
- // For now, we only support / implement not-primitive type Date in the entity
760
- throw new Error(`Unsupported object type: ${Object.prototype.toString.call(metadata.value).slice(8, -1)} for value ${metadata.value}`) // slice to extract type from string [object String]
761
- }
762
- break
763
- default:
764
- throw new Error(`Unsupported value type: ${typeof metadata.value}`)
765
- }
766
- return metadataCondition
767
- }
768
- }
1
+ import { OrPromise } from '@sphereon/ssi-types'
2
+ import { BaseEntity, DataSource, FindOptionsWhere, In, Repository } from 'typeorm'
3
+ import Debug from 'debug'
4
+ import { AbstractContactStore } from './AbstractContactStore'
5
+ import { PartyEntity } from '../entities/contact/PartyEntity'
6
+ import { IdentityEntity } from '../entities/contact/IdentityEntity'
7
+ import { IdentityMetadataItemEntity } from '../entities/contact/IdentityMetadataItemEntity'
8
+ import { CorrelationIdentifierEntity } from '../entities/contact/CorrelationIdentifierEntity'
9
+ import { ConnectionEntity } from '../entities/contact/ConnectionEntity'
10
+ import { BaseConfigEntity } from '../entities/contact/BaseConfigEntity'
11
+ import { PartyRelationshipEntity } from '../entities/contact/PartyRelationshipEntity'
12
+ import { PartyTypeEntity } from '../entities/contact/PartyTypeEntity'
13
+ import { BaseContactEntity } from '../entities/contact/BaseContactEntity'
14
+ import { ElectronicAddressEntity } from '../entities/contact/ElectronicAddressEntity'
15
+ import { PhysicalAddressEntity } from '../entities/contact/PhysicalAddressEntity'
16
+ import {
17
+ electronicAddressEntityFrom,
18
+ electronicAddressFrom,
19
+ identityEntityFrom,
20
+ identityFrom,
21
+ isDidAuthConfig,
22
+ isNaturalPerson,
23
+ isOpenIdConfig,
24
+ isOrganization,
25
+ partyEntityFrom,
26
+ partyFrom,
27
+ partyRelationshipEntityFrom,
28
+ partyRelationshipFrom,
29
+ partyTypeEntityFrom,
30
+ partyTypeFrom,
31
+ physicalAddressEntityFrom,
32
+ physicalAddressFrom,
33
+ } from '../utils/contact/MappingUtils'
34
+ import {
35
+ AddElectronicAddressArgs,
36
+ AddIdentityArgs,
37
+ AddPartyArgs,
38
+ AddPartyTypeArgs,
39
+ AddPhysicalAddressArgs,
40
+ AddRelationshipArgs,
41
+ ConnectionType,
42
+ CorrelationIdentifierType,
43
+ ElectronicAddress,
44
+ GetElectronicAddressArgs,
45
+ GetElectronicAddressesArgs,
46
+ GetIdentitiesArgs,
47
+ GetIdentityArgs,
48
+ GetPartiesArgs,
49
+ GetPartyArgs,
50
+ GetPartyTypeArgs,
51
+ GetPartyTypesArgs,
52
+ GetPhysicalAddressArgs,
53
+ GetPhysicalAddressesArgs,
54
+ GetRelationshipArgs,
55
+ GetRelationshipsArgs,
56
+ IMetadataEntity,
57
+ Identity,
58
+ MetadataItem,
59
+ MetadataTypes,
60
+ NonPersistedConnectionConfig,
61
+ NonPersistedContact,
62
+ Party,
63
+ PartyRelationship,
64
+ PartyType,
65
+ PartyTypeType,
66
+ PhysicalAddress,
67
+ RemoveElectronicAddressArgs,
68
+ RemoveIdentityArgs,
69
+ RemovePartyArgs,
70
+ RemovePartyTypeArgs,
71
+ RemovePhysicalAddressArgs,
72
+ RemoveRelationshipArgs,
73
+ UpdateElectronicAddressArgs,
74
+ UpdateIdentityArgs,
75
+ UpdatePartyArgs,
76
+ UpdatePartyTypeArgs,
77
+ UpdatePhysicalAddressArgs,
78
+ UpdateRelationshipArgs,
79
+ } from '../types'
80
+
81
+ const debug: Debug.Debugger = Debug('sphereon:ssi-sdk:contact-store')
82
+
83
+ export class ContactStore extends AbstractContactStore {
84
+ private readonly dbConnection: OrPromise<DataSource>
85
+
86
+ constructor(dbConnection: OrPromise<DataSource>) {
87
+ super()
88
+ this.dbConnection = dbConnection
89
+ }
90
+
91
+ getParty = async (args: GetPartyArgs): Promise<Party> => {
92
+ const { partyId } = args
93
+ const result: PartyEntity | null = await (await this.dbConnection).getRepository(PartyEntity).findOne({
94
+ where: { id: partyId },
95
+ })
96
+
97
+ if (!result) {
98
+ return Promise.reject(Error(`No party found for id: ${partyId}`))
99
+ }
100
+
101
+ return partyFrom(result)
102
+ }
103
+
104
+ getParties = async (args?: GetPartiesArgs): Promise<Array<Party>> => {
105
+ debug('getParties()', args)
106
+ const { filter } = args ?? {}
107
+ const partyRepository = (await this.dbConnection).getRepository(PartyEntity)
108
+ const filterConditions = this.buildFilters(filter)
109
+ const initialResult = await partyRepository.find({ select: ['id'], where: filterConditions })
110
+
111
+ // Fetch the complete entities based on the initial result IDs
112
+ const result = await partyRepository.find({ where: { id: In(initialResult.map((party) => party.id)) } })
113
+ debug(`getParties() resulted in ${result.length} parties`)
114
+ return result.map(partyFrom)
115
+ }
116
+
117
+ addParty = async (args: AddPartyArgs): Promise<Party> => {
118
+ const { identities, contact, partyType } = args
119
+
120
+ const partyRepository: Repository<PartyEntity> = (await this.dbConnection).getRepository(PartyEntity)
121
+
122
+ if (!this.hasCorrectPartyType(partyType.type, contact)) {
123
+ return Promise.reject(Error(`Party type ${partyType.type}, does not match for provided contact`))
124
+ }
125
+
126
+ for (const identity of identities ?? []) {
127
+ if (identity.identifier.type === CorrelationIdentifierType.URL) {
128
+ if (!identity.connection) {
129
+ return Promise.reject(Error(`Identity with correlation type ${CorrelationIdentifierType.URL} should contain a connection`))
130
+ }
131
+
132
+ if (!this.hasCorrectConnectionConfig(identity.connection.type, identity.connection.config)) {
133
+ return Promise.reject(Error(`Connection type ${identity.connection.type}, does not match for provided config`))
134
+ }
135
+ }
136
+ }
137
+
138
+ const partyEntity: PartyEntity = partyEntityFrom(args)
139
+ debug('Adding party', args)
140
+ const createdResult: PartyEntity = await partyRepository.save(partyEntity)
141
+
142
+ return partyFrom(createdResult)
143
+ }
144
+
145
+ updateParty = async (args: UpdatePartyArgs): Promise<Party> => {
146
+ const { party } = args
147
+ const partyRepository: Repository<PartyEntity> = (await this.dbConnection).getRepository(PartyEntity)
148
+ const result: PartyEntity | null = await partyRepository.findOne({
149
+ where: { id: party.id },
150
+ })
151
+
152
+ if (!result) {
153
+ return Promise.reject(Error(`No party found for id: ${party.id}`))
154
+ }
155
+
156
+ const updatedParty = {
157
+ ...party,
158
+ identities: result.identities,
159
+ type: result.partyType,
160
+ relationships: result.relationships,
161
+ electronicAddresses: result.electronicAddresses,
162
+ }
163
+
164
+ debug('Updating party', party)
165
+ const updatedResult: PartyEntity = await partyRepository.save(updatedParty, { transaction: true })
166
+
167
+ return partyFrom(updatedResult)
168
+ }
169
+
170
+ removeParty = async (args: RemovePartyArgs): Promise<void> => {
171
+ const { partyId } = args
172
+ const partyRepository: Repository<PartyEntity> = (await this.dbConnection).getRepository(PartyEntity)
173
+ debug('Removing party', partyId)
174
+ partyRepository
175
+ .findOneById(partyId)
176
+ .then(async (party: PartyEntity | null): Promise<void> => {
177
+ if (!party) {
178
+ await Promise.reject(Error(`Unable to find the party with id to remove: ${partyId}`))
179
+ } else {
180
+ await this.deleteIdentities(party.identities)
181
+ await this.deleteElectronicAddresses(party.electronicAddresses)
182
+ await this.deletePhysicalAddresses(party.physicalAddresses)
183
+
184
+ await partyRepository
185
+ .delete({ id: partyId })
186
+ .catch((error) => Promise.reject(Error(`Unable to remove party with id: ${partyId}. ${error}`)))
187
+
188
+ const partyContactRepository: Repository<BaseContactEntity> = (await this.dbConnection).getRepository(BaseContactEntity)
189
+ await partyContactRepository
190
+ .delete({ id: party.contact.id })
191
+ .catch((error) => Promise.reject(Error(`Unable to remove party contact with id: ${party.contact.id}. ${error}`)))
192
+ }
193
+ })
194
+ .catch((error) => Promise.reject(Error(`Unable to remove party with id: ${partyId}. ${error}`)))
195
+ }
196
+
197
+ getIdentity = async (args: GetIdentityArgs): Promise<Identity> => {
198
+ const { identityId } = args
199
+ const result: IdentityEntity | null = await (await this.dbConnection).getRepository(IdentityEntity).findOne({
200
+ where: { id: identityId },
201
+ })
202
+
203
+ if (!result) {
204
+ return Promise.reject(Error(`No identity found for id: ${identityId}`))
205
+ }
206
+
207
+ return identityFrom(result)
208
+ }
209
+
210
+ getIdentities = async (args?: GetIdentitiesArgs): Promise<Array<Identity>> => {
211
+ const { filter } = args ?? {}
212
+ const identityRepository = (await this.dbConnection).getRepository(IdentityEntity)
213
+ const filterConditions = this.buildFilters(filter)
214
+ const initialResult = await identityRepository.find({ select: ['id'], where: filterConditions })
215
+
216
+ const result = await identityRepository.find({ where: { id: In(initialResult.map((identity) => identity.id)) } })
217
+ return result.map(identityFrom)
218
+ }
219
+
220
+ addIdentity = async (args: AddIdentityArgs): Promise<Identity> => {
221
+ const { identity, partyId } = args
222
+ const party: PartyEntity | null = await (await this.dbConnection).getRepository(PartyEntity).findOne({
223
+ where: { id: partyId },
224
+ })
225
+
226
+ if (!party) {
227
+ return Promise.reject(Error(`No party found for id: ${partyId}`))
228
+ }
229
+
230
+ if (identity.identifier.type === CorrelationIdentifierType.URL) {
231
+ if (!identity.connection) {
232
+ return Promise.reject(Error(`Identity with correlation type ${CorrelationIdentifierType.URL} should contain a connection`))
233
+ }
234
+
235
+ if (!this.hasCorrectConnectionConfig(identity.connection.type, identity.connection.config)) {
236
+ return Promise.reject(Error(`Connection type ${identity.connection.type}, does not match for provided config`))
237
+ }
238
+ }
239
+
240
+ const identityEntity: IdentityEntity = identityEntityFrom(identity)
241
+ identityEntity.party = party
242
+ debug('Adding identity', identity)
243
+ const result: IdentityEntity = await (await this.dbConnection).getRepository(IdentityEntity).save(identityEntity, {
244
+ transaction: true,
245
+ })
246
+
247
+ return identityFrom(result)
248
+ }
249
+
250
+ updateIdentity = async (args: UpdateIdentityArgs): Promise<Identity> => {
251
+ const { identity } = args
252
+ const identityRepository: Repository<IdentityEntity> = (await this.dbConnection).getRepository(IdentityEntity)
253
+ const result: IdentityEntity | null = await identityRepository.findOne({
254
+ where: { id: identity.id },
255
+ })
256
+
257
+ if (!result) {
258
+ return Promise.reject(Error(`No identity found for id: ${identity.id}`))
259
+ }
260
+
261
+ if (identity.identifier.type === CorrelationIdentifierType.URL) {
262
+ if (!identity.connection) {
263
+ return Promise.reject(Error(`Identity with correlation type ${CorrelationIdentifierType.URL} should contain a connection`))
264
+ }
265
+
266
+ if (!this.hasCorrectConnectionConfig(identity.connection.type, identity.connection.config)) {
267
+ return Promise.reject(Error(`Connection type ${identity.connection.type}, does not match for provided config`))
268
+ }
269
+ }
270
+
271
+ debug('Updating identity', identity)
272
+ const updatedResult: IdentityEntity = await identityRepository.save(identity, { transaction: true })
273
+
274
+ return identityFrom(updatedResult)
275
+ }
276
+
277
+ removeIdentity = async (args: RemoveIdentityArgs): Promise<void> => {
278
+ const { identityId } = args
279
+ const identity: IdentityEntity | null = await (await this.dbConnection).getRepository(IdentityEntity).findOne({
280
+ where: { id: identityId },
281
+ })
282
+
283
+ if (!identity) {
284
+ return Promise.reject(Error(`No identity found for id: ${identityId}`))
285
+ }
286
+
287
+ debug('Removing identity', identityId)
288
+
289
+ await this.deleteIdentities([identity])
290
+ }
291
+
292
+ addRelationship = async (args: AddRelationshipArgs): Promise<PartyRelationship> => {
293
+ const { leftId, rightId } = args
294
+ return this.assertRelationshipSides(leftId, rightId).then(async (): Promise<PartyRelationship> => {
295
+ const relationship: PartyRelationshipEntity = partyRelationshipEntityFrom({
296
+ leftId,
297
+ rightId,
298
+ })
299
+ debug('Adding party relationship', relationship)
300
+
301
+ const createdResult: PartyRelationshipEntity = await (await this.dbConnection).getRepository(PartyRelationshipEntity).save(relationship)
302
+
303
+ return partyRelationshipFrom(createdResult)
304
+ })
305
+ }
306
+
307
+ getRelationship = async (args: GetRelationshipArgs): Promise<PartyRelationship> => {
308
+ const { relationshipId } = args
309
+ const result: PartyRelationshipEntity | null = await (await this.dbConnection).getRepository(PartyRelationshipEntity).findOne({
310
+ where: { id: relationshipId },
311
+ })
312
+
313
+ if (!result) {
314
+ return Promise.reject(Error(`No relationship found for id: ${relationshipId}`))
315
+ }
316
+
317
+ return partyRelationshipFrom(result)
318
+ }
319
+
320
+ getRelationships = async (args?: GetRelationshipsArgs): Promise<Array<PartyRelationship>> => {
321
+ const { filter } = args ?? {}
322
+ const partyRelationshipRepository: Repository<PartyRelationshipEntity> = (await this.dbConnection).getRepository(PartyRelationshipEntity)
323
+ const initialResult: Array<PartyRelationshipEntity> = await partyRelationshipRepository.find({
324
+ ...(filter && { where: filter }),
325
+ })
326
+
327
+ const result: Array<PartyRelationshipEntity> = await partyRelationshipRepository.find({
328
+ where: {
329
+ id: In(initialResult.map((partyRelationship: PartyRelationshipEntity) => partyRelationship.id)),
330
+ },
331
+ })
332
+
333
+ return result.map((partyRelationship: PartyRelationshipEntity) => partyRelationshipFrom(partyRelationship))
334
+ }
335
+
336
+ updateRelationship = async (args: UpdateRelationshipArgs): Promise<PartyRelationship> => {
337
+ const { relationship } = args
338
+ const partyRelationshipRepository: Repository<PartyRelationshipEntity> = (await this.dbConnection).getRepository(PartyRelationshipEntity)
339
+ const result: PartyRelationshipEntity | null = await partyRelationshipRepository.findOne({
340
+ where: { id: relationship.id },
341
+ })
342
+
343
+ if (!result) {
344
+ return Promise.reject(Error(`No party relationship found for id: ${relationship.id}`))
345
+ }
346
+
347
+ return this.assertRelationshipSides(relationship.leftId, relationship.rightId).then(async (): Promise<PartyRelationship> => {
348
+ debug('Updating party relationship', relationship)
349
+ const updatedResult: PartyRelationshipEntity = await partyRelationshipRepository.save(relationship, { transaction: true })
350
+
351
+ return partyRelationshipFrom(updatedResult)
352
+ })
353
+ }
354
+
355
+ removeRelationship = async (args: RemoveRelationshipArgs): Promise<void> => {
356
+ const { relationshipId } = args
357
+ const partyRelationshipRepository: Repository<PartyRelationshipEntity> = (await this.dbConnection).getRepository(PartyRelationshipEntity)
358
+ const relationship: PartyRelationshipEntity | null = await partyRelationshipRepository.findOne({
359
+ where: { id: relationshipId },
360
+ })
361
+
362
+ if (!relationship) {
363
+ return Promise.reject(Error(`No relationship found for id: ${relationshipId}`))
364
+ }
365
+
366
+ debug('Removing relationship', relationshipId)
367
+
368
+ await partyRelationshipRepository.delete(relationshipId)
369
+ }
370
+
371
+ addPartyType = async (args: AddPartyTypeArgs): Promise<PartyType> => {
372
+ const partyEntity: PartyTypeEntity = partyTypeEntityFrom(args)
373
+ debug('Adding party type', args)
374
+ const createdResult: PartyTypeEntity = await (await this.dbConnection).getRepository(PartyTypeEntity).save(partyEntity)
375
+
376
+ return partyTypeFrom(createdResult)
377
+ }
378
+
379
+ getPartyType = async (args: GetPartyTypeArgs): Promise<PartyType> => {
380
+ const { partyTypeId } = args
381
+ const result: PartyTypeEntity | null = await (await this.dbConnection).getRepository(PartyTypeEntity).findOne({
382
+ where: { id: partyTypeId },
383
+ })
384
+
385
+ if (!result) {
386
+ return Promise.reject(Error(`No party type found for id: ${partyTypeId}`))
387
+ }
388
+
389
+ return partyTypeFrom(result)
390
+ }
391
+
392
+ getPartyTypes = async (args?: GetPartyTypesArgs): Promise<Array<PartyType>> => {
393
+ const { filter } = args ?? {}
394
+ const partyTypeRepository: Repository<PartyTypeEntity> = (await this.dbConnection).getRepository(PartyTypeEntity)
395
+ const initialResult: Array<PartyTypeEntity> = await partyTypeRepository.find({
396
+ ...(filter && { where: filter }),
397
+ })
398
+
399
+ const result: Array<PartyTypeEntity> = await partyTypeRepository.find({
400
+ where: {
401
+ id: In(initialResult.map((partyType: PartyTypeEntity) => partyType.id)),
402
+ },
403
+ })
404
+
405
+ return result.map((partyType: PartyTypeEntity) => partyTypeFrom(partyType))
406
+ }
407
+
408
+ updatePartyType = async (args: UpdatePartyTypeArgs): Promise<PartyType> => {
409
+ const { partyType } = args
410
+ const partyTypeRepository: Repository<PartyTypeEntity> = (await this.dbConnection).getRepository(PartyTypeEntity)
411
+ const result: PartyTypeEntity | null = await partyTypeRepository.findOne({
412
+ where: { id: partyType.id },
413
+ })
414
+
415
+ if (!result) {
416
+ return Promise.reject(Error(`No party type found for id: ${partyType.id}`))
417
+ }
418
+
419
+ debug('Updating party type', partyType)
420
+ const updatedResult: PartyTypeEntity = await partyTypeRepository.save(partyType, { transaction: true })
421
+
422
+ return partyTypeFrom(updatedResult)
423
+ }
424
+
425
+ removePartyType = async (args: RemovePartyTypeArgs): Promise<void> => {
426
+ const { partyTypeId } = args
427
+ const parties: Array<PartyEntity> = await (await this.dbConnection).getRepository(PartyEntity).find({
428
+ where: {
429
+ partyType: {
430
+ id: partyTypeId,
431
+ },
432
+ },
433
+ })
434
+
435
+ if (parties.length > 0) {
436
+ return Promise.reject(Error(`Unable to remove party type with id: ${partyTypeId}. Party type is in use`))
437
+ }
438
+
439
+ const partyTypeRepository: Repository<PartyTypeEntity> = (await this.dbConnection).getRepository(PartyTypeEntity)
440
+ const partyType: PartyTypeEntity | null = await partyTypeRepository.findOne({
441
+ where: { id: partyTypeId },
442
+ })
443
+
444
+ if (!partyType) {
445
+ return Promise.reject(Error(`No party type found for id: ${partyTypeId}`))
446
+ }
447
+
448
+ debug('Removing party type', partyTypeId)
449
+
450
+ await partyTypeRepository.delete(partyTypeId)
451
+ }
452
+
453
+ getElectronicAddress = async (args: GetElectronicAddressArgs): Promise<ElectronicAddress> => {
454
+ const { electronicAddressId } = args
455
+ const result: ElectronicAddressEntity | null = await (await this.dbConnection).getRepository(ElectronicAddressEntity).findOne({
456
+ where: { id: electronicAddressId },
457
+ })
458
+
459
+ if (!result) {
460
+ return Promise.reject(Error(`No electronic address found for id: ${electronicAddressId}`))
461
+ }
462
+
463
+ return electronicAddressFrom(result)
464
+ }
465
+
466
+ getElectronicAddresses = async (args?: GetElectronicAddressesArgs): Promise<Array<ElectronicAddress>> => {
467
+ const { filter } = args ?? {}
468
+ const electronicAddressRepository: Repository<ElectronicAddressEntity> = (await this.dbConnection).getRepository(ElectronicAddressEntity)
469
+ const initialResult: Array<ElectronicAddressEntity> = await electronicAddressRepository.find({
470
+ ...(filter && { where: filter }),
471
+ })
472
+
473
+ const result: Array<ElectronicAddressEntity> = await electronicAddressRepository.find({
474
+ where: {
475
+ id: In(initialResult.map((electronicAddress: ElectronicAddressEntity) => electronicAddress.id)),
476
+ },
477
+ })
478
+
479
+ return result.map((electronicAddress: ElectronicAddressEntity) => electronicAddressFrom(electronicAddress))
480
+ }
481
+
482
+ addElectronicAddress = async (args: AddElectronicAddressArgs): Promise<ElectronicAddress> => {
483
+ const { electronicAddress, partyId } = args
484
+ const party: PartyEntity | null = await (await this.dbConnection).getRepository(PartyEntity).findOne({
485
+ where: { id: partyId },
486
+ })
487
+
488
+ if (!party) {
489
+ return Promise.reject(Error(`No party found for id: ${partyId}`))
490
+ }
491
+
492
+ const electronicAddressEntity: ElectronicAddressEntity = electronicAddressEntityFrom(electronicAddress)
493
+ electronicAddressEntity.party = party
494
+ debug('Adding electronic address', electronicAddress)
495
+ const result: ElectronicAddressEntity = await (await this.dbConnection).getRepository(ElectronicAddressEntity).save(electronicAddressEntity, {
496
+ transaction: true,
497
+ })
498
+
499
+ return electronicAddressFrom(result)
500
+ }
501
+
502
+ updateElectronicAddress = async (args: UpdateElectronicAddressArgs): Promise<ElectronicAddress> => {
503
+ const { electronicAddress } = args
504
+ const electronicAddressRepository: Repository<ElectronicAddressEntity> = (await this.dbConnection).getRepository(ElectronicAddressEntity)
505
+ const result: ElectronicAddressEntity | null = await electronicAddressRepository.findOne({
506
+ where: { id: electronicAddress.id },
507
+ })
508
+
509
+ if (!result) {
510
+ return Promise.reject(Error(`No electronic address found for id: ${electronicAddress.id}`))
511
+ }
512
+
513
+ debug('Updating electronic address', electronicAddress)
514
+ const updatedResult: ElectronicAddressEntity = await electronicAddressRepository.save(electronicAddress, { transaction: true })
515
+
516
+ return electronicAddressFrom(updatedResult)
517
+ }
518
+
519
+ removeElectronicAddress = async (args: RemoveElectronicAddressArgs): Promise<void> => {
520
+ const { electronicAddressId } = args
521
+ const electronicAddressRepository: Repository<ElectronicAddressEntity> = (await this.dbConnection).getRepository(ElectronicAddressEntity)
522
+ const electronicAddress: ElectronicAddressEntity | null = await electronicAddressRepository.findOne({
523
+ where: { id: electronicAddressId },
524
+ })
525
+
526
+ if (!electronicAddress) {
527
+ return Promise.reject(Error(`No electronic address found for id: ${electronicAddressId}`))
528
+ }
529
+
530
+ debug('Removing electronic address', electronicAddressId)
531
+
532
+ await electronicAddressRepository.delete(electronicAddressId)
533
+ }
534
+
535
+ getPhysicalAddress = async (args: GetPhysicalAddressArgs): Promise<PhysicalAddress> => {
536
+ const { physicalAddressId } = args
537
+ const result: PhysicalAddressEntity | null = await (await this.dbConnection).getRepository(PhysicalAddressEntity).findOne({
538
+ where: { id: physicalAddressId },
539
+ })
540
+
541
+ if (!result) {
542
+ return Promise.reject(Error(`No physical address found for id: ${physicalAddressId}`))
543
+ }
544
+
545
+ return physicalAddressFrom(result)
546
+ }
547
+
548
+ getPhysicalAddresses = async (args?: GetPhysicalAddressesArgs): Promise<Array<PhysicalAddress>> => {
549
+ const { filter } = args ?? {}
550
+ const physicalAddressRepository: Repository<PhysicalAddressEntity> = (await this.dbConnection).getRepository(PhysicalAddressEntity)
551
+ const initialResult: Array<PhysicalAddressEntity> = await physicalAddressRepository.find({
552
+ ...(filter && { where: filter }),
553
+ })
554
+
555
+ const result: Array<PhysicalAddressEntity> = await physicalAddressRepository.find({
556
+ where: {
557
+ id: In(initialResult.map((physicalAddress: PhysicalAddressEntity) => physicalAddress.id)),
558
+ },
559
+ })
560
+
561
+ return result.map((physicalAddress: PhysicalAddressEntity) => physicalAddressFrom(physicalAddress))
562
+ }
563
+
564
+ addPhysicalAddress = async (args: AddPhysicalAddressArgs): Promise<PhysicalAddress> => {
565
+ const { physicalAddress, partyId } = args
566
+ const party: PartyEntity | null = await (await this.dbConnection).getRepository(PartyEntity).findOne({
567
+ where: { id: partyId },
568
+ })
569
+
570
+ if (!party) {
571
+ return Promise.reject(Error(`No party found for id: ${partyId}`))
572
+ }
573
+
574
+ const physicalAddressEntity: PhysicalAddressEntity = physicalAddressEntityFrom(physicalAddress)
575
+ physicalAddressEntity.party = party
576
+ debug('Adding physical address', physicalAddress)
577
+ const result: PhysicalAddressEntity = await (await this.dbConnection).getRepository(PhysicalAddressEntity).save(physicalAddressEntity, {
578
+ transaction: true,
579
+ })
580
+
581
+ return physicalAddressFrom(result)
582
+ }
583
+
584
+ updatePhysicalAddress = async (args: UpdatePhysicalAddressArgs): Promise<PhysicalAddress> => {
585
+ const { physicalAddress } = args
586
+ const physicalAddressRepository: Repository<PhysicalAddressEntity> = (await this.dbConnection).getRepository(PhysicalAddressEntity)
587
+ const result: PhysicalAddressEntity | null = await physicalAddressRepository.findOne({
588
+ where: { id: physicalAddress.id },
589
+ })
590
+
591
+ if (!result) {
592
+ return Promise.reject(Error(`No physical address found for id: ${physicalAddress.id}`))
593
+ }
594
+
595
+ debug('Updating physical address', physicalAddress)
596
+ const updatedResult: PhysicalAddressEntity = await physicalAddressRepository.save(physicalAddress, { transaction: true })
597
+
598
+ return physicalAddressFrom(updatedResult)
599
+ }
600
+
601
+ removePhysicalAddress = async (args: RemovePhysicalAddressArgs): Promise<void> => {
602
+ const { physicalAddressId } = args
603
+ const physicalAddressRepository: Repository<PhysicalAddressEntity> = (await this.dbConnection).getRepository(PhysicalAddressEntity)
604
+ const physicalAddress: PhysicalAddressEntity | null = await physicalAddressRepository.findOne({
605
+ where: { id: physicalAddressId },
606
+ })
607
+
608
+ if (!physicalAddress) {
609
+ return Promise.reject(Error(`No physical address found for id: ${physicalAddressId}`))
610
+ }
611
+
612
+ debug('Removing physical address', physicalAddressId)
613
+
614
+ await physicalAddressRepository.delete(physicalAddressId)
615
+ }
616
+
617
+ private hasCorrectConnectionConfig = (type: ConnectionType, config: NonPersistedConnectionConfig): boolean => {
618
+ switch (type) {
619
+ case ConnectionType.OPENID_CONNECT:
620
+ return isOpenIdConfig(config)
621
+ case ConnectionType.SIOPv2:
622
+ return isDidAuthConfig(config)
623
+ default:
624
+ throw new Error('Connection type not supported')
625
+ }
626
+ }
627
+
628
+ private hasCorrectPartyType = (type: PartyTypeType, contact: NonPersistedContact): boolean => {
629
+ switch (type) {
630
+ case PartyTypeType.NATURAL_PERSON:
631
+ return isNaturalPerson(contact)
632
+ case PartyTypeType.ORGANIZATION:
633
+ return isOrganization(contact)
634
+ default:
635
+ throw new Error('Party type not supported')
636
+ }
637
+ }
638
+
639
+ private deleteIdentities = async (identities: Array<IdentityEntity>): Promise<void> => {
640
+ debug('Removing identities', identities)
641
+
642
+ const connection: DataSource = await this.dbConnection
643
+ const correlationIdentifierRepository: Repository<CorrelationIdentifierEntity> = connection.getRepository(CorrelationIdentifierEntity)
644
+ const baseConfigRepository: Repository<BaseConfigEntity> = connection.getRepository(BaseConfigEntity)
645
+ const connectionRepository: Repository<ConnectionEntity> = connection.getRepository(ConnectionEntity)
646
+ const identityMetadataItemRepository: Repository<IdentityMetadataItemEntity> = connection.getRepository(IdentityMetadataItemEntity)
647
+ const identityRepository: Repository<IdentityEntity> = connection.getRepository(IdentityEntity)
648
+
649
+ identities.map(async (identity: IdentityEntity): Promise<void> => {
650
+ await correlationIdentifierRepository
651
+ .delete(identity.identifier.id)
652
+ .catch((error) => Promise.reject(Error(`Unable to remove identity.identifier with id ${identity.identifier.id}. ${error}`)))
653
+
654
+ if (identity.connection) {
655
+ await baseConfigRepository.delete(identity.connection.config.id)
656
+ await connectionRepository
657
+ .delete(identity.connection.id)
658
+ .catch((error) => Promise.reject(Error(`Unable to remove identity.connection with id ${identity.connection?.id}. ${error}`)))
659
+ }
660
+
661
+ if (identity.metadata) {
662
+ identity.metadata.map(async (metadataItem: IdentityMetadataItemEntity): Promise<void> => {
663
+ await identityMetadataItemRepository
664
+ .delete(metadataItem.id)
665
+ .catch((error) => Promise.reject(Error(`Unable to remove identity.metadataItem with id ${metadataItem.id}. ${error}`)))
666
+ })
667
+ }
668
+
669
+ await identityRepository
670
+ .delete(identity.id)
671
+ .catch((error) => Promise.reject(Error(`Unable to remove identity with id ${identity.id}. ${error}`)))
672
+ })
673
+ }
674
+
675
+ private deleteElectronicAddresses = async (electronicAddresses: Array<ElectronicAddressEntity>): Promise<void> => {
676
+ debug('Removing electronic addresses', electronicAddresses)
677
+
678
+ const electronicAddressRepository: Repository<ElectronicAddressEntity> = (await this.dbConnection).getRepository(ElectronicAddressEntity)
679
+ electronicAddresses.map(async (electronicAddress: ElectronicAddressEntity): Promise<void> => {
680
+ await electronicAddressRepository
681
+ .delete(electronicAddress.id)
682
+ .catch((error) => Promise.reject(Error(`Unable to remove electronic address with id ${electronicAddress.id}. ${error}`)))
683
+ })
684
+ }
685
+
686
+ private deletePhysicalAddresses = async (physicalAddresses: Array<PhysicalAddressEntity>): Promise<void> => {
687
+ debug('Removing physical addresses', physicalAddresses)
688
+
689
+ const physicalAddressRepository: Repository<PhysicalAddressEntity> = (await this.dbConnection).getRepository(PhysicalAddressEntity)
690
+ physicalAddresses.map(async (physicalAddress: PhysicalAddressEntity): Promise<void> => {
691
+ await physicalAddressRepository
692
+ .delete(physicalAddress.id)
693
+ .catch((error) => Promise.reject(Error(`Unable to remove physical address with id ${physicalAddress.id}. ${error}`)))
694
+ })
695
+ }
696
+
697
+ private assertRelationshipSides = async (leftId: string, rightId: string): Promise<void> => {
698
+ const partyRepository: Repository<PartyEntity> = (await this.dbConnection).getRepository(PartyEntity)
699
+ const leftParty: PartyEntity | null = await partyRepository.findOne({
700
+ where: { id: leftId },
701
+ })
702
+
703
+ if (!leftParty) {
704
+ return Promise.reject(Error(`No party found for left side of the relationship, party id: ${leftId}`))
705
+ }
706
+
707
+ const rightParty: PartyEntity | null = await partyRepository.findOne({
708
+ where: { id: rightId },
709
+ })
710
+
711
+ if (!rightParty) {
712
+ return Promise.reject(Error(`No party found for right side of the relationship, party id: ${rightId}`))
713
+ }
714
+ }
715
+
716
+ private buildFilters = <T extends BaseEntity>(filter?: Array<Record<string, any>>): Array<FindOptionsWhere<T>> | FindOptionsWhere<T> => {
717
+ if (!filter) return {}
718
+
719
+ return filter.map((condition) => this.processCondition(condition))
720
+ }
721
+
722
+ private processCondition = (condition: Record<string, any>): Record<string, any> => {
723
+ const conditionObject: Record<string, any> = {}
724
+
725
+ Object.keys(condition).forEach((key) => {
726
+ const value = condition[key]
727
+
728
+ if (key === 'metadata' && value) {
729
+ conditionObject[key] = this.buildMetadataCondition(value)
730
+ } else if (typeof value === 'object' && value !== null) {
731
+ conditionObject[key] = this.processCondition(value)
732
+ } else {
733
+ conditionObject[key] = value
734
+ }
735
+ })
736
+
737
+ return conditionObject
738
+ }
739
+
740
+ private buildMetadataCondition = <T extends MetadataItem<MetadataTypes>>(metadata: Partial<T>): FindOptionsWhere<IMetadataEntity> => {
741
+ const metadataCondition: FindOptionsWhere<any> = {
742
+ label: metadata.label,
743
+ }
744
+
745
+ switch (typeof metadata.value) {
746
+ case 'string':
747
+ metadataCondition.stringValue = metadata.value as string
748
+ break
749
+ case 'number':
750
+ metadataCondition.numberValue = metadata.value as number
751
+ break
752
+ case 'boolean':
753
+ metadataCondition.boolValue = metadata.value as boolean
754
+ break
755
+ case 'object':
756
+ if (metadata.value instanceof Date) {
757
+ metadataCondition.dateValue = metadata.value as Date
758
+ } else {
759
+ // For now, we only support / implement not-primitive type Date in the entity
760
+ throw new Error(`Unsupported object type: ${Object.prototype.toString.call(metadata.value).slice(8, -1)} for value ${metadata.value}`) // slice to extract type from string [object String]
761
+ }
762
+ break
763
+ default:
764
+ throw new Error(`Unsupported value type: ${typeof metadata.value}`)
765
+ }
766
+ return metadataCondition
767
+ }
768
+ }