@sphereon/ssi-sdk.data-store 0.24.0 → 0.24.1-next.112

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 (202) hide show
  1. package/LICENSE +1 -1
  2. package/dist/contact/ContactStore.d.ts +3 -0
  3. package/dist/contact/ContactStore.d.ts.map +1 -1
  4. package/dist/contact/ContactStore.js +84 -48
  5. package/dist/contact/ContactStore.js.map +1 -1
  6. package/dist/entities/contact/BaseContactEntity.d.ts +2 -0
  7. package/dist/entities/contact/BaseContactEntity.d.ts.map +1 -1
  8. package/dist/entities/contact/BaseContactEntity.js +12 -3
  9. package/dist/entities/contact/BaseContactEntity.js.map +1 -1
  10. package/dist/entities/contact/ConnectionEntity.d.ts +2 -0
  11. package/dist/entities/contact/ConnectionEntity.d.ts.map +1 -1
  12. package/dist/entities/contact/ConnectionEntity.js +8 -0
  13. package/dist/entities/contact/ConnectionEntity.js.map +1 -1
  14. package/dist/entities/contact/ContactMetadataItemEntity.d.ts +14 -0
  15. package/dist/entities/contact/ContactMetadataItemEntity.d.ts.map +1 -0
  16. package/dist/entities/contact/ContactMetadataItemEntity.js +88 -0
  17. package/dist/entities/contact/ContactMetadataItemEntity.js.map +1 -0
  18. package/dist/entities/contact/CorrelationIdentifierEntity.d.ts +2 -0
  19. package/dist/entities/contact/CorrelationIdentifierEntity.d.ts.map +1 -1
  20. package/dist/entities/contact/CorrelationIdentifierEntity.js +8 -0
  21. package/dist/entities/contact/CorrelationIdentifierEntity.js.map +1 -1
  22. package/dist/entities/contact/DidAuthConfigEntity.d.ts +2 -0
  23. package/dist/entities/contact/DidAuthConfigEntity.d.ts.map +1 -1
  24. package/dist/entities/contact/DidAuthConfigEntity.js +8 -0
  25. package/dist/entities/contact/DidAuthConfigEntity.js.map +1 -1
  26. package/dist/entities/contact/ElectronicAddressEntity.d.ts +2 -0
  27. package/dist/entities/contact/ElectronicAddressEntity.d.ts.map +1 -1
  28. package/dist/entities/contact/ElectronicAddressEntity.js +8 -0
  29. package/dist/entities/contact/ElectronicAddressEntity.js.map +1 -1
  30. package/dist/entities/contact/IMetadataEntity.d.ts +8 -0
  31. package/dist/entities/contact/IMetadataEntity.d.ts.map +1 -0
  32. package/dist/entities/contact/IMetadataEntity.js +2 -0
  33. package/dist/entities/contact/IMetadataEntity.js.map +1 -0
  34. package/dist/entities/contact/IdentityEntity.d.ts +5 -2
  35. package/dist/entities/contact/IdentityEntity.d.ts.map +1 -1
  36. package/dist/entities/contact/IdentityEntity.js +13 -0
  37. package/dist/entities/contact/IdentityEntity.js.map +1 -1
  38. package/dist/entities/contact/IdentityMetadataItemEntity.d.ts +6 -2
  39. package/dist/entities/contact/IdentityMetadataItemEntity.d.ts.map +1 -1
  40. package/dist/entities/contact/IdentityMetadataItemEntity.js +19 -3
  41. package/dist/entities/contact/IdentityMetadataItemEntity.js.map +1 -1
  42. package/dist/entities/contact/NaturalPersonEntity.d.ts +2 -0
  43. package/dist/entities/contact/NaturalPersonEntity.d.ts.map +1 -1
  44. package/dist/entities/contact/NaturalPersonEntity.js +8 -0
  45. package/dist/entities/contact/NaturalPersonEntity.js.map +1 -1
  46. package/dist/entities/contact/OpenIdConfigEntity.d.ts +2 -0
  47. package/dist/entities/contact/OpenIdConfigEntity.d.ts.map +1 -1
  48. package/dist/entities/contact/OpenIdConfigEntity.js +8 -0
  49. package/dist/entities/contact/OpenIdConfigEntity.js.map +1 -1
  50. package/dist/entities/contact/OrganizationEntity.d.ts +2 -0
  51. package/dist/entities/contact/OrganizationEntity.d.ts.map +1 -1
  52. package/dist/entities/contact/OrganizationEntity.js +8 -0
  53. package/dist/entities/contact/OrganizationEntity.js.map +1 -1
  54. package/dist/entities/contact/PartyEntity.d.ts +2 -0
  55. package/dist/entities/contact/PartyEntity.d.ts.map +1 -1
  56. package/dist/entities/contact/PartyEntity.js +8 -0
  57. package/dist/entities/contact/PartyEntity.js.map +1 -1
  58. package/dist/entities/contact/PartyRelationshipEntity.d.ts +2 -0
  59. package/dist/entities/contact/PartyRelationshipEntity.d.ts.map +1 -1
  60. package/dist/entities/contact/PartyRelationshipEntity.js +8 -0
  61. package/dist/entities/contact/PartyRelationshipEntity.js.map +1 -1
  62. package/dist/entities/contact/PartyTypeEntity.js +4 -4
  63. package/dist/entities/contact/PartyTypeEntity.js.map +1 -1
  64. package/dist/entities/contact/PhysicalAddressEntity.d.ts +2 -0
  65. package/dist/entities/contact/PhysicalAddressEntity.d.ts.map +1 -1
  66. package/dist/entities/contact/PhysicalAddressEntity.js +10 -1
  67. package/dist/entities/contact/PhysicalAddressEntity.js.map +1 -1
  68. package/dist/entities/presentationDefinition/PresentationDefinitionItemEntity.d.ts +14 -0
  69. package/dist/entities/presentationDefinition/PresentationDefinitionItemEntity.d.ts.map +1 -0
  70. package/dist/entities/presentationDefinition/PresentationDefinitionItemEntity.js +74 -0
  71. package/dist/entities/presentationDefinition/PresentationDefinitionItemEntity.js.map +1 -0
  72. package/dist/index.d.ts +10 -4
  73. package/dist/index.d.ts.map +1 -1
  74. package/dist/index.js +16 -2
  75. package/dist/index.js.map +1 -1
  76. package/dist/migrations/generic/10-CreatePresentationDefinitions.d.ts +7 -0
  77. package/dist/migrations/generic/10-CreatePresentationDefinitions.d.ts.map +1 -0
  78. package/dist/migrations/generic/10-CreatePresentationDefinitions.js +78 -0
  79. package/dist/migrations/generic/10-CreatePresentationDefinitions.js.map +1 -0
  80. package/dist/migrations/generic/8-CreateContacts.d.ts +7 -0
  81. package/dist/migrations/generic/8-CreateContacts.d.ts.map +1 -0
  82. package/dist/migrations/generic/8-CreateContacts.js +78 -0
  83. package/dist/migrations/generic/8-CreateContacts.js.map +1 -0
  84. package/dist/migrations/generic/9-CreateContacts.d.ts +7 -0
  85. package/dist/migrations/generic/9-CreateContacts.d.ts.map +1 -0
  86. package/dist/migrations/generic/9-CreateContacts.js +78 -0
  87. package/dist/migrations/generic/9-CreateContacts.js.map +1 -0
  88. package/dist/migrations/generic/index.d.ts +2 -0
  89. package/dist/migrations/generic/index.d.ts.map +1 -1
  90. package/dist/migrations/generic/index.js +12 -2
  91. package/dist/migrations/generic/index.js.map +1 -1
  92. package/dist/migrations/index.d.ts +1 -1
  93. package/dist/migrations/index.d.ts.map +1 -1
  94. package/dist/migrations/index.js +2 -1
  95. package/dist/migrations/index.js.map +1 -1
  96. package/dist/migrations/postgres/1690925872592-CreateContacts.d.ts.map +1 -1
  97. package/dist/migrations/postgres/1690925872592-CreateContacts.js +40 -3
  98. package/dist/migrations/postgres/1690925872592-CreateContacts.js.map +1 -1
  99. package/dist/migrations/postgres/1710438363001-CreateContacts.d.ts +7 -0
  100. package/dist/migrations/postgres/1710438363001-CreateContacts.d.ts.map +1 -0
  101. package/dist/migrations/postgres/1710438363001-CreateContacts.js +63 -0
  102. package/dist/migrations/postgres/1710438363001-CreateContacts.js.map +1 -0
  103. package/dist/migrations/postgres/1715761125001-CreateContacts.d.ts +7 -0
  104. package/dist/migrations/postgres/1715761125001-CreateContacts.d.ts.map +1 -0
  105. package/dist/migrations/postgres/1715761125001-CreateContacts.js +74 -0
  106. package/dist/migrations/postgres/1715761125001-CreateContacts.js.map +1 -0
  107. package/dist/migrations/postgres/1716475165345-CreatePresentationDefinitions.d.ts +7 -0
  108. package/dist/migrations/postgres/1716475165345-CreatePresentationDefinitions.d.ts.map +1 -0
  109. package/dist/migrations/postgres/1716475165345-CreatePresentationDefinitions.js +41 -0
  110. package/dist/migrations/postgres/1716475165345-CreatePresentationDefinitions.js.map +1 -0
  111. package/dist/migrations/sqlite/1690925872693-CreateContacts.d.ts.map +1 -1
  112. package/dist/migrations/sqlite/1690925872693-CreateContacts.js +40 -3
  113. package/dist/migrations/sqlite/1690925872693-CreateContacts.js.map +1 -1
  114. package/dist/migrations/sqlite/1710438363002-CreateContacts.d.ts +7 -0
  115. package/dist/migrations/sqlite/1710438363002-CreateContacts.d.ts.map +1 -0
  116. package/dist/migrations/sqlite/1710438363002-CreateContacts.js +79 -0
  117. package/dist/migrations/sqlite/1710438363002-CreateContacts.js.map +1 -0
  118. package/dist/migrations/sqlite/1715761125002-CreateContacts.d.ts +7 -0
  119. package/dist/migrations/sqlite/1715761125002-CreateContacts.d.ts.map +1 -0
  120. package/dist/migrations/sqlite/1715761125002-CreateContacts.js +73 -0
  121. package/dist/migrations/sqlite/1715761125002-CreateContacts.js.map +1 -0
  122. package/dist/migrations/sqlite/1716475165344-CreatePresentationDefinitions.d.ts +7 -0
  123. package/dist/migrations/sqlite/1716475165344-CreatePresentationDefinitions.d.ts.map +1 -0
  124. package/dist/migrations/sqlite/1716475165344-CreatePresentationDefinitions.js +38 -0
  125. package/dist/migrations/sqlite/1716475165344-CreatePresentationDefinitions.js.map +1 -0
  126. package/dist/presentationDefinition/AbstractPDStore.d.ts +12 -0
  127. package/dist/presentationDefinition/AbstractPDStore.d.ts.map +1 -0
  128. package/dist/presentationDefinition/AbstractPDStore.js +7 -0
  129. package/dist/presentationDefinition/AbstractPDStore.js.map +1 -0
  130. package/dist/presentationDefinition/PDStore.d.ts +19 -0
  131. package/dist/presentationDefinition/PDStore.d.ts.map +1 -0
  132. package/dist/presentationDefinition/PDStore.js +152 -0
  133. package/dist/presentationDefinition/PDStore.js.map +1 -0
  134. package/dist/types/contact/contact.d.ts +51 -15
  135. package/dist/types/contact/contact.d.ts.map +1 -1
  136. package/dist/types/contact/contact.js +12 -7
  137. package/dist/types/contact/contact.js.map +1 -1
  138. package/dist/types/index.d.ts +2 -0
  139. package/dist/types/index.d.ts.map +1 -1
  140. package/dist/types/index.js +2 -0
  141. package/dist/types/index.js.map +1 -1
  142. package/dist/types/presentationDefinition/IAbstractPDStore.d.ts +17 -0
  143. package/dist/types/presentationDefinition/IAbstractPDStore.d.ts.map +1 -0
  144. package/dist/types/presentationDefinition/IAbstractPDStore.js +3 -0
  145. package/dist/types/presentationDefinition/IAbstractPDStore.js.map +1 -0
  146. package/dist/types/presentationDefinition/presentationDefinition.d.ts +16 -0
  147. package/dist/types/presentationDefinition/presentationDefinition.d.ts.map +1 -0
  148. package/dist/types/presentationDefinition/presentationDefinition.js +3 -0
  149. package/dist/types/presentationDefinition/presentationDefinition.js.map +1 -0
  150. package/dist/utils/contact/MappingUtils.d.ts +6 -4
  151. package/dist/utils/contact/MappingUtils.d.ts.map +1 -1
  152. package/dist/utils/contact/MappingUtils.js +128 -18
  153. package/dist/utils/contact/MappingUtils.js.map +1 -1
  154. package/dist/utils/presentationDefinition/MappingUtils.d.ts +6 -0
  155. package/dist/utils/presentationDefinition/MappingUtils.d.ts.map +1 -0
  156. package/dist/utils/presentationDefinition/MappingUtils.js +48 -0
  157. package/dist/utils/presentationDefinition/MappingUtils.js.map +1 -0
  158. package/package.json +7 -4
  159. package/src/__tests__/contact.entities.test.ts +129 -44
  160. package/src/__tests__/contact.store.test.ts +205 -29
  161. package/src/__tests__/pd-manager.entities.test.ts +71 -0
  162. package/src/__tests__/pd-manager.store.test.ts +191 -0
  163. package/src/contact/ContactStore.ts +74 -30
  164. package/src/entities/contact/BaseContactEntity.ts +11 -0
  165. package/src/entities/contact/ConnectionEntity.ts +6 -0
  166. package/src/entities/contact/ContactMetadataItemEntity.ts +50 -0
  167. package/src/entities/contact/CorrelationIdentifierEntity.ts +6 -0
  168. package/src/entities/contact/DidAuthConfigEntity.ts +6 -0
  169. package/src/entities/contact/ElectronicAddressEntity.ts +6 -0
  170. package/src/entities/contact/IMetadataEntity.ts +7 -0
  171. package/src/entities/contact/IdentityEntity.ts +11 -2
  172. package/src/entities/contact/IdentityMetadataItemEntity.ts +16 -4
  173. package/src/entities/contact/NaturalPersonEntity.ts +6 -0
  174. package/src/entities/contact/OpenIdConfigEntity.ts +6 -0
  175. package/src/entities/contact/OrganizationEntity.ts +6 -0
  176. package/src/entities/contact/PartyEntity.ts +6 -0
  177. package/src/entities/contact/PartyRelationshipEntity.ts +6 -0
  178. package/src/entities/contact/PartyTypeEntity.ts +4 -4
  179. package/src/entities/contact/PhysicalAddressEntity.ts +9 -2
  180. package/src/entities/presentationDefinition/PresentationDefinitionItemEntity.ts +43 -0
  181. package/src/index.ts +13 -0
  182. package/src/migrations/generic/10-CreatePresentationDefinitions.ts +66 -0
  183. package/src/migrations/generic/8-CreateContacts.ts +66 -0
  184. package/src/migrations/generic/9-CreateContacts.ts +66 -0
  185. package/src/migrations/generic/index.ts +11 -1
  186. package/src/migrations/index.ts +1 -0
  187. package/src/migrations/postgres/1690925872592-CreateContacts.ts +59 -5
  188. package/src/migrations/postgres/1710438363001-CreateContacts.ts +63 -0
  189. package/src/migrations/postgres/1715761125001-CreateContacts.ts +60 -0
  190. package/src/migrations/postgres/1716475165345-CreatePresentationDefinitions.ts +25 -0
  191. package/src/migrations/sqlite/1690925872693-CreateContacts.ts +70 -3
  192. package/src/migrations/sqlite/1710438363002-CreateContacts.ts +83 -0
  193. package/src/migrations/sqlite/1715761125002-CreateContacts.ts +59 -0
  194. package/src/migrations/sqlite/1716475165344-CreatePresentationDefinitions.ts +24 -0
  195. package/src/presentationDefinition/AbstractPDStore.ts +20 -0
  196. package/src/presentationDefinition/PDStore.ts +185 -0
  197. package/src/types/contact/contact.ts +56 -15
  198. package/src/types/index.ts +2 -0
  199. package/src/types/presentationDefinition/IAbstractPDStore.ts +25 -0
  200. package/src/types/presentationDefinition/presentationDefinition.ts +17 -0
  201. package/src/utils/contact/MappingUtils.ts +135 -19
  202. package/src/utils/presentationDefinition/MappingUtils.ts +52 -0
@@ -0,0 +1,191 @@
1
+ import { DataSource } from 'typeorm'
2
+ import { DataStorePresentationDefinitionEntities, DataStorePresentationDefinitionMigrations, PDStore } from '../index'
3
+ import { GetDefinitionsArgs, NonPersistedPresentationDefinitionItem, PresentationDefinitionItem } from '../types'
4
+
5
+ describe('PDStore tests', (): void => {
6
+ let dbConnection: DataSource
7
+ let pdStore: PDStore
8
+
9
+ beforeEach(async (): Promise<void> => {
10
+ dbConnection = await new DataSource({
11
+ type: 'sqlite',
12
+ database: ':memory:',
13
+ logging: ['info'],
14
+ synchronize: false,
15
+ migrationsRun: false,
16
+ migrations: DataStorePresentationDefinitionMigrations,
17
+ entities: DataStorePresentationDefinitionEntities,
18
+ }).initialize()
19
+ await dbConnection.runMigrations()
20
+ expect(await dbConnection.showMigrations()).toBeFalsy()
21
+ pdStore = new PDStore(dbConnection)
22
+ })
23
+
24
+ afterEach(async (): Promise<void> => {
25
+ await dbConnection.destroy()
26
+ })
27
+
28
+ it('should check if definition exists', async (): Promise<void> => {
29
+ const definition: NonPersistedPresentationDefinitionItem = {
30
+ definitionId: 'definition1',
31
+ version: '1.0',
32
+ definitionPayload: { id: 'definition1', input_descriptors: [] },
33
+ }
34
+ const savedDefinition: PresentationDefinitionItem = await pdStore.addDefinition(definition)
35
+ expect(savedDefinition).toBeDefined()
36
+
37
+ const exists: boolean = await pdStore.hasDefinition({ itemId: savedDefinition.id })
38
+
39
+ expect(exists).toBeTruthy()
40
+ })
41
+
42
+ it('should check if definitions exist by filter', async (): Promise<void> => {
43
+ const definition: NonPersistedPresentationDefinitionItem = {
44
+ definitionId: 'definition1',
45
+ version: '1.0',
46
+ definitionPayload: { id: 'definition1', input_descriptors: [] },
47
+ }
48
+ const savedDefinition: PresentationDefinitionItem = await pdStore.addDefinition(definition)
49
+ expect(savedDefinition).toBeDefined()
50
+
51
+ const exists: boolean = await pdStore.hasDefinitions({ filter: [{ definitionId: 'definition1' }] })
52
+
53
+ expect(exists).toBeTruthy()
54
+ })
55
+
56
+ it('should get definition by id', async (): Promise<void> => {
57
+ const definition: NonPersistedPresentationDefinitionItem = {
58
+ definitionId: 'definition1',
59
+ version: '1.0',
60
+ definitionPayload: { id: 'definition1', input_descriptors: [] },
61
+ }
62
+
63
+ const savedDefinition: PresentationDefinitionItem = await pdStore.addDefinition(definition)
64
+ expect(savedDefinition).toBeDefined()
65
+
66
+ const result: PresentationDefinitionItem = await pdStore.getDefinition({ itemId: savedDefinition.id })
67
+
68
+ expect(result).toBeDefined()
69
+ })
70
+
71
+ it('should throw error when getting definition with unknown id', async (): Promise<void> => {
72
+ const itemId = 'unknownDefinitionId'
73
+
74
+ await expect(pdStore.getDefinition({ itemId })).rejects.toThrow(`No presentation definition item found for id: ${itemId}`)
75
+ })
76
+
77
+ it('should get all definitions', async (): Promise<void> => {
78
+ const definition1: NonPersistedPresentationDefinitionItem = {
79
+ definitionId: 'definition1',
80
+ version: '1.0',
81
+ definitionPayload: { id: 'definition1', input_descriptors: [] },
82
+ }
83
+ const savedDefinition1: PresentationDefinitionItem = await pdStore.addDefinition(definition1)
84
+ expect(savedDefinition1).toBeDefined()
85
+
86
+ const definition2: NonPersistedPresentationDefinitionItem = {
87
+ definitionId: 'definition2',
88
+ version: '1.0',
89
+ definitionPayload: { id: 'definition2', input_descriptors: [] },
90
+ }
91
+ const savedDefinition2: PresentationDefinitionItem = await pdStore.addDefinition(definition2)
92
+ expect(savedDefinition2).toBeDefined()
93
+
94
+ const result: Array<PresentationDefinitionItem> = await pdStore.getDefinitions({})
95
+
96
+ expect(result).toBeDefined()
97
+ expect(result.length).toEqual(2)
98
+ })
99
+
100
+ it('should get definitions by filter', async (): Promise<void> => {
101
+ const definition: NonPersistedPresentationDefinitionItem = {
102
+ definitionId: 'definition1',
103
+ version: '1.0',
104
+ definitionPayload: { id: 'definition1', input_descriptors: [] },
105
+ }
106
+ const savedDefinition: PresentationDefinitionItem = await pdStore.addDefinition(definition)
107
+ expect(savedDefinition).toBeDefined()
108
+
109
+ const args: GetDefinitionsArgs = {
110
+ filter: [{ definitionId: 'definition1' }],
111
+ }
112
+ const result: Array<PresentationDefinitionItem> = await pdStore.getDefinitions(args)
113
+
114
+ expect(result.length).toEqual(1)
115
+ })
116
+
117
+ it('should add definition', async (): Promise<void> => {
118
+ const definition: NonPersistedPresentationDefinitionItem = {
119
+ definitionId: 'definition1',
120
+ version: '1.0',
121
+ definitionPayload: { id: 'definition1', input_descriptors: [] },
122
+ }
123
+
124
+ const result: PresentationDefinitionItem = await pdStore.addDefinition(definition)
125
+
126
+ expect(result).toBeDefined()
127
+ expect(result.definitionId).toEqual(definition.definitionId)
128
+ })
129
+
130
+ it('should update definition', async (): Promise<void> => {
131
+ const definition: NonPersistedPresentationDefinitionItem = {
132
+ definitionId: 'definition1',
133
+ version: '1.0',
134
+ definitionPayload: { id: 'definition1', input_descriptors: [] },
135
+ }
136
+ const savedDefinition: PresentationDefinitionItem = await pdStore.addDefinition(definition)
137
+ expect(savedDefinition).toBeDefined()
138
+
139
+ const updatedDefinition: PresentationDefinitionItem = {
140
+ ...savedDefinition,
141
+ version: '1.1',
142
+ }
143
+
144
+ await pdStore.updateDefinition(updatedDefinition)
145
+ const result: PresentationDefinitionItem = await pdStore.getDefinition({ itemId: savedDefinition.id })
146
+
147
+ expect(result).toBeDefined()
148
+ expect(result.version).toEqual('1.1')
149
+ })
150
+
151
+ it('should delete definition', async (): Promise<void> => {
152
+ const definition: NonPersistedPresentationDefinitionItem = {
153
+ definitionId: 'definition1',
154
+ version: '1.0',
155
+ definitionPayload: { id: 'definition1', input_descriptors: [] },
156
+ }
157
+ const savedDefinition: PresentationDefinitionItem = await pdStore.addDefinition(definition)
158
+ expect(savedDefinition).toBeDefined()
159
+
160
+ await pdStore.deleteDefinition({ itemId: savedDefinition.id })
161
+
162
+ await expect(pdStore.getDefinition({ itemId: savedDefinition.id })).rejects.toThrow(
163
+ `No presentation definition item found for id: ${savedDefinition.id}`,
164
+ )
165
+ })
166
+
167
+ it('should delete definitions by filter', async (): Promise<void> => {
168
+ const definition1: NonPersistedPresentationDefinitionItem = {
169
+ definitionId: 'definition1',
170
+ version: '1.0',
171
+ definitionPayload: { id: 'definition1', input_descriptors: [] },
172
+ }
173
+ const savedDefinition1: PresentationDefinitionItem = await pdStore.addDefinition(definition1)
174
+ expect(savedDefinition1).toBeDefined()
175
+
176
+ const definition2: NonPersistedPresentationDefinitionItem = {
177
+ definitionId: 'definition2',
178
+ version: '1.0',
179
+ definitionPayload: { id: 'definition2', input_descriptors: [] },
180
+ }
181
+ const savedDefinition2: PresentationDefinitionItem = await pdStore.addDefinition(definition2)
182
+ expect(savedDefinition2).toBeDefined()
183
+
184
+ const filter = { filter: [{ definitionId: 'definition1' }] }
185
+ await pdStore.deleteDefinitions(filter)
186
+
187
+ const remainingDefinitions: Array<PresentationDefinitionItem> = await pdStore.getDefinitions({})
188
+ expect(remainingDefinitions.length).toEqual(1)
189
+ expect(remainingDefinitions[0].definitionId).toEqual('definition2')
190
+ })
191
+ })
@@ -1,5 +1,5 @@
1
1
  import { OrPromise } from '@sphereon/ssi-types'
2
- import { DataSource, In, Repository } from 'typeorm'
2
+ import { BaseEntity, DataSource, FindOptionsWhere, In, Repository } from 'typeorm'
3
3
  import Debug from 'debug'
4
4
  import { AbstractContactStore } from './AbstractContactStore'
5
5
  import { PartyEntity } from '../entities/contact/PartyEntity'
@@ -54,6 +54,8 @@ import {
54
54
  GetRelationshipArgs,
55
55
  GetRelationshipsArgs,
56
56
  Identity,
57
+ MetadataItem,
58
+ MetadataTypes,
57
59
  NonPersistedConnectionConfig,
58
60
  NonPersistedContact,
59
61
  Party,
@@ -99,21 +101,16 @@ export class ContactStore extends AbstractContactStore {
99
101
  }
100
102
 
101
103
  getParties = async (args?: GetPartiesArgs): Promise<Array<Party>> => {
102
- debug(`getParties()`, args)
104
+ debug('getParties()', args)
103
105
  const { filter } = args ?? {}
104
- const partyRepository: Repository<PartyEntity> = (await this.dbConnection).getRepository(PartyEntity)
105
- const initialResult: Array<PartyEntity> = await partyRepository.find({
106
- ...(filter && { where: filter }),
107
- })
106
+ const partyRepository = (await this.dbConnection).getRepository(PartyEntity)
107
+ const filterConditions = this.buildFilters(filter)
108
+ const initialResult = await partyRepository.find({ select: ['id'], where: filterConditions })
108
109
 
109
- const result: Array<PartyEntity> = await partyRepository.find({
110
- where: {
111
- id: In(initialResult.map((party: PartyEntity) => party.id)),
112
- },
113
- })
110
+ // Fetch the complete entities based on the initial result IDs
111
+ const result = await partyRepository.find({ where: { id: In(initialResult.map((party) => party.id)) } })
114
112
  debug(`getParties() resulted in ${result.length} parties`)
115
-
116
- return result.map((party: PartyEntity) => partyFrom(party))
113
+ return result.map(partyFrom)
117
114
  }
118
115
 
119
116
  addParty = async (args: AddPartyArgs): Promise<Party> => {
@@ -211,18 +208,12 @@ export class ContactStore extends AbstractContactStore {
211
208
 
212
209
  getIdentities = async (args?: GetIdentitiesArgs): Promise<Array<Identity>> => {
213
210
  const { filter } = args ?? {}
214
- const identityRepository: Repository<IdentityEntity> = (await this.dbConnection).getRepository(IdentityEntity)
215
- const initialResult: Array<IdentityEntity> = await identityRepository.find({
216
- ...(filter && { where: filter }),
217
- })
218
-
219
- const result: Array<IdentityEntity> = await identityRepository.find({
220
- where: {
221
- id: In(initialResult.map((identity: IdentityEntity) => identity.id)),
222
- },
223
- })
211
+ const identityRepository = (await this.dbConnection).getRepository(IdentityEntity)
212
+ const filterConditions = this.buildFilters(filter)
213
+ const initialResult = await identityRepository.find({ select: ['id'], where: filterConditions })
224
214
 
225
- return result.map((identity: IdentityEntity) => identityFrom(identity))
215
+ const result = await identityRepository.find({ where: { id: In(initialResult.map((identity) => identity.id)) } })
216
+ return result.map(identityFrom)
226
217
  }
227
218
 
228
219
  addIdentity = async (args: AddIdentityArgs): Promise<Identity> => {
@@ -622,7 +613,7 @@ export class ContactStore extends AbstractContactStore {
622
613
  await physicalAddressRepository.delete(physicalAddressId)
623
614
  }
624
615
 
625
- private hasCorrectConnectionConfig(type: ConnectionType, config: NonPersistedConnectionConfig): boolean {
616
+ private hasCorrectConnectionConfig = (type: ConnectionType, config: NonPersistedConnectionConfig): boolean => {
626
617
  switch (type) {
627
618
  case ConnectionType.OPENID_CONNECT:
628
619
  return isOpenIdConfig(config)
@@ -633,7 +624,7 @@ export class ContactStore extends AbstractContactStore {
633
624
  }
634
625
  }
635
626
 
636
- private hasCorrectPartyType(type: PartyTypeType, contact: NonPersistedContact): boolean {
627
+ private hasCorrectPartyType = (type: PartyTypeType, contact: NonPersistedContact): boolean => {
637
628
  switch (type) {
638
629
  case PartyTypeType.NATURAL_PERSON:
639
630
  return isNaturalPerson(contact)
@@ -644,7 +635,7 @@ export class ContactStore extends AbstractContactStore {
644
635
  }
645
636
  }
646
637
 
647
- private async deleteIdentities(identities: Array<IdentityEntity>): Promise<void> {
638
+ private deleteIdentities = async (identities: Array<IdentityEntity>): Promise<void> => {
648
639
  debug('Removing identities', identities)
649
640
 
650
641
  const connection: DataSource = await this.dbConnection
@@ -680,7 +671,7 @@ export class ContactStore extends AbstractContactStore {
680
671
  })
681
672
  }
682
673
 
683
- private async deleteElectronicAddresses(electronicAddresses: Array<ElectronicAddressEntity>): Promise<void> {
674
+ private deleteElectronicAddresses = async (electronicAddresses: Array<ElectronicAddressEntity>): Promise<void> => {
684
675
  debug('Removing electronic addresses', electronicAddresses)
685
676
 
686
677
  const electronicAddressRepository: Repository<ElectronicAddressEntity> = (await this.dbConnection).getRepository(ElectronicAddressEntity)
@@ -691,7 +682,7 @@ export class ContactStore extends AbstractContactStore {
691
682
  })
692
683
  }
693
684
 
694
- private async deletePhysicalAddresses(physicalAddresses: Array<PhysicalAddressEntity>): Promise<void> {
685
+ private deletePhysicalAddresses = async (physicalAddresses: Array<PhysicalAddressEntity>): Promise<void> => {
695
686
  debug('Removing physical addresses', physicalAddresses)
696
687
 
697
688
  const physicalAddressRepository: Repository<PhysicalAddressEntity> = (await this.dbConnection).getRepository(PhysicalAddressEntity)
@@ -702,7 +693,7 @@ export class ContactStore extends AbstractContactStore {
702
693
  })
703
694
  }
704
695
 
705
- private async assertRelationshipSides(leftId: string, rightId: string): Promise<void> {
696
+ private assertRelationshipSides = async (leftId: string, rightId: string): Promise<void> => {
706
697
  const partyRepository: Repository<PartyEntity> = (await this.dbConnection).getRepository(PartyEntity)
707
698
  const leftParty: PartyEntity | null = await partyRepository.findOne({
708
699
  where: { id: leftId },
@@ -720,4 +711,57 @@ export class ContactStore extends AbstractContactStore {
720
711
  return Promise.reject(Error(`No party found for right side of the relationship, party id: ${rightId}`))
721
712
  }
722
713
  }
714
+
715
+ private buildFilters = <T extends BaseEntity>(filter?: Array<Record<string, any>>): Array<FindOptionsWhere<T>> | FindOptionsWhere<T> => {
716
+ if (!filter) return {}
717
+
718
+ return filter.map((condition) => this.processCondition(condition))
719
+ }
720
+
721
+ private processCondition = (condition: Record<string, any>): Record<string, any> => {
722
+ const conditionObject: Record<string, any> = {}
723
+
724
+ Object.keys(condition).forEach((key) => {
725
+ const value = condition[key]
726
+
727
+ if (key === 'metadata' && value) {
728
+ conditionObject[key] = this.buildMetadataCondition(value)
729
+ } else if (typeof value === 'object' && value !== null) {
730
+ conditionObject[key] = this.processCondition(value)
731
+ } else {
732
+ conditionObject[key] = value
733
+ }
734
+ })
735
+
736
+ return conditionObject
737
+ }
738
+
739
+ private buildMetadataCondition = <T extends MetadataItem<MetadataTypes>>(metadata: Partial<T>): FindOptionsWhere<IMetadataEntity> => {
740
+ const metadataCondition: FindOptionsWhere<any> = {
741
+ label: metadata.label,
742
+ }
743
+
744
+ switch (typeof metadata.value) {
745
+ case 'string':
746
+ metadataCondition.stringValue = metadata.value as string
747
+ break
748
+ case 'number':
749
+ metadataCondition.numberValue = metadata.value as number
750
+ break
751
+ case 'boolean':
752
+ metadataCondition.boolValue = metadata.value as boolean
753
+ break
754
+ case 'object':
755
+ if (metadata.value instanceof Date) {
756
+ metadataCondition.dateValue = metadata.value as Date
757
+ } else {
758
+ // For now, we only support / implement not-primitive type Date in the entity
759
+ 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]
760
+ }
761
+ break
762
+ default:
763
+ throw new Error(`Unsupported value type: ${typeof metadata.value}`)
764
+ }
765
+ return metadataCondition
766
+ }
723
767
  }
@@ -5,12 +5,14 @@ import {
5
5
  CreateDateColumn,
6
6
  Entity,
7
7
  JoinColumn,
8
+ OneToMany,
8
9
  OneToOne,
9
10
  PrimaryGeneratedColumn,
10
11
  TableInheritance,
11
12
  UpdateDateColumn,
12
13
  } from 'typeorm'
13
14
  import { PartyEntity } from './PartyEntity'
15
+ import { ContactMetadataItemEntity } from './ContactMetadataItemEntity'
14
16
 
15
17
  @Entity('BaseContact')
16
18
  @TableInheritance({ column: { type: 'varchar', name: 'type' } })
@@ -30,6 +32,15 @@ export abstract class BaseContactEntity extends BaseEntity {
30
32
  @JoinColumn({ name: 'party_id' })
31
33
  party!: PartyEntity
32
34
 
35
+ @OneToMany(() => ContactMetadataItemEntity, (metadata: ContactMetadataItemEntity) => metadata.contact, {
36
+ cascade: true,
37
+ onDelete: 'CASCADE',
38
+ eager: true,
39
+ nullable: false,
40
+ })
41
+ @JoinColumn({ name: 'metadata_id' })
42
+ metadata!: Array<ContactMetadataItemEntity>
43
+
33
44
  // By default, @UpdateDateColumn in TypeORM updates the timestamp only when the entity's top-level properties change.
34
45
  @BeforeInsert()
35
46
  @BeforeUpdate()
@@ -13,6 +13,12 @@ export class ConnectionEntity extends BaseEntity {
13
13
  @Column('simple-enum', { name: 'type', enum: ConnectionType, nullable: false })
14
14
  type!: ConnectionType
15
15
 
16
+ @Column({name: 'tenant_id', nullable: true})
17
+ tenantId?: string
18
+
19
+ @Column({name: 'owner_id', nullable: true})
20
+ ownerId?: string
21
+
16
22
  @OneToOne(() => BaseConfigEntity, (config: OpenIdConfigEntity | DidAuthConfigEntity) => config.connection, {
17
23
  cascade: true,
18
24
  onDelete: 'CASCADE',
@@ -0,0 +1,50 @@
1
+ import { Entity, Column, PrimaryGeneratedColumn, BaseEntity, ManyToOne, BeforeInsert, BeforeUpdate } from 'typeorm'
2
+ import { ValidationConstraint } from '../../types'
3
+ import { BaseContactEntity } from './BaseContactEntity'
4
+ import { IsNotEmpty, validate, ValidationError } from 'class-validator'
5
+ import { getConstraint } from '../../utils/ValidatorUtils'
6
+
7
+ @Entity('ContactMetadata')
8
+ export class ContactMetadataItemEntity extends BaseEntity implements IMetadataEntity {
9
+ @PrimaryGeneratedColumn('uuid')
10
+ id!: string
11
+
12
+ @Column({ name: 'label', length: 255, nullable: false })
13
+ @IsNotEmpty({ message: 'Blank metadata labels are not allowed' })
14
+ label!: string
15
+
16
+ @Column({ name: 'valueType', nullable: false })
17
+ @IsNotEmpty({ message: 'valueType must not be empty' })
18
+ valueType!: string
19
+
20
+ @Column({ name: 'stringValue', length: 255, nullable: true })
21
+ stringValue?: string
22
+
23
+ @Column({ name: 'numberValue', nullable: true })
24
+ numberValue?: number
25
+
26
+ @Column({ name: 'dateValue', nullable: true })
27
+ dateValue?: Date
28
+
29
+ @Column({ name: 'boolValue', nullable: true })
30
+ boolValue?: boolean
31
+
32
+ @ManyToOne(() => BaseContactEntity, (contact: BaseContactEntity) => contact.metadata, {
33
+ cascade: ['insert', 'update'],
34
+ onDelete: 'CASCADE',
35
+ })
36
+ contact!: BaseContactEntity
37
+
38
+ @BeforeInsert()
39
+ @BeforeUpdate()
40
+ async validate(): Promise<void> {
41
+ const validation: Array<ValidationError> = await validate(this)
42
+ if (validation.length > 0) {
43
+ const constraint: ValidationConstraint | undefined = getConstraint(validation[0])
44
+ if (constraint) {
45
+ const message: string = Object.values(constraint!)[0]
46
+ return Promise.reject(Error(message))
47
+ }
48
+ }
49
+ }
50
+ }
@@ -16,6 +16,12 @@ export class CorrelationIdentifierEntity extends BaseEntity {
16
16
  @IsNotEmpty({ message: 'Blank correlation ids are not allowed' })
17
17
  correlationId!: string
18
18
 
19
+ @Column({name: 'owner_id', nullable: true})
20
+ ownerId?: string
21
+
22
+ @Column({name: 'tenant_id', nullable: true})
23
+ tenantId?: string
24
+
19
25
  @OneToOne(() => IdentityEntity, (identity: IdentityEntity) => identity.identifier, {
20
26
  onDelete: 'CASCADE',
21
27
  })
@@ -11,4 +11,10 @@ export class DidAuthConfigEntity extends BaseConfigEntity {
11
11
 
12
12
  @Column({ name: 'session_id', length: 255, nullable: false })
13
13
  sessionId!: string
14
+
15
+ @Column({name: 'owner_id', nullable: true})
16
+ ownerId?: string
17
+
18
+ @Column({name: 'tenant_id', nullable: true})
19
+ tenantId?: string
14
20
  }
@@ -35,6 +35,12 @@ export class ElectronicAddressEntity extends BaseEntity {
35
35
  @Column({ name: 'partyId', nullable: true })
36
36
  partyId?: string
37
37
 
38
+ @Column({name: 'owner_id', nullable: true})
39
+ ownerId?: string
40
+
41
+ @Column({name: 'tenant_id', nullable: true})
42
+ tenantId?: string
43
+
38
44
  @CreateDateColumn({ name: 'created_at', nullable: false })
39
45
  createdAt!: Date
40
46
 
@@ -0,0 +1,7 @@
1
+ interface IMetadataEntity { // TODO move to types
2
+ label: string
3
+ stringValue?: string
4
+ numberValue?: number
5
+ dateValue?: Date
6
+ boolValue?: boolean
7
+ }
@@ -16,7 +16,7 @@ import { IsNotEmpty, validate, ValidationError } from 'class-validator'
16
16
  import { CorrelationIdentifierEntity } from './CorrelationIdentifierEntity'
17
17
  import { ConnectionEntity } from './ConnectionEntity'
18
18
  import { IdentityMetadataItemEntity } from './IdentityMetadataItemEntity'
19
- import { IdentityRole, ValidationConstraint } from '../../types'
19
+ import { CredentialRole, IdentityOrigin, ValidationConstraint } from '../../types'
20
20
  import { PartyEntity } from './PartyEntity'
21
21
  import { getConstraint } from '../../utils/ValidatorUtils'
22
22
 
@@ -34,8 +34,17 @@ export class IdentityEntity extends BaseEntity {
34
34
  @IsNotEmpty({ message: 'Blank aliases are not allowed' })
35
35
  alias!: string
36
36
 
37
+ @Column('simple-enum', { name: 'origin', enum: IdentityOrigin, nullable: false })
38
+ origin!: IdentityOrigin
39
+
40
+ @Column({ name: 'owner_id', nullable: true })
41
+ ownerId?: string
42
+
43
+ @Column({ name: 'tenant_id', nullable: true })
44
+ tenantId?: string
45
+
37
46
  @Column('simple-array', { name: 'roles', nullable: false })
38
- roles!: Array<IdentityRole>
47
+ roles!: Array<CredentialRole>
39
48
 
40
49
  @OneToOne(() => CorrelationIdentifierEntity, (identifier: CorrelationIdentifierEntity) => identifier.identity, {
41
50
  cascade: true,
@@ -5,7 +5,7 @@ import { IsNotEmpty, validate, ValidationError } from 'class-validator'
5
5
  import { getConstraint } from '../../utils/ValidatorUtils'
6
6
 
7
7
  @Entity('IdentityMetadata')
8
- export class IdentityMetadataItemEntity extends BaseEntity {
8
+ export class IdentityMetadataItemEntity extends BaseEntity implements IMetadataEntity {
9
9
  @PrimaryGeneratedColumn('uuid')
10
10
  id!: string
11
11
 
@@ -13,9 +13,21 @@ export class IdentityMetadataItemEntity extends BaseEntity {
13
13
  @IsNotEmpty({ message: 'Blank metadata labels are not allowed' })
14
14
  label!: string
15
15
 
16
- @Column({ name: 'value', length: 255, nullable: false })
17
- @IsNotEmpty({ message: 'Blank metadata values are not allowed' })
18
- value!: string
16
+ @Column({ name: 'valueType', nullable: false })
17
+ @IsNotEmpty({ message: 'valueType must not be empty' })
18
+ valueType!: string
19
+
20
+ @Column({ name: 'stringValue', length: 255, nullable: true })
21
+ stringValue?: string
22
+
23
+ @Column({ name: 'numberValue', nullable: true })
24
+ numberValue?: number
25
+
26
+ @Column({ name: 'dateValue', nullable: true })
27
+ dateValue?: Date
28
+
29
+ @Column({ name: 'boolValue', nullable: true })
30
+ boolValue?: boolean
19
31
 
20
32
  @ManyToOne(() => IdentityEntity, (identity: IdentityEntity) => identity.metadata, { cascade: ['insert', 'update'], onDelete: 'CASCADE' })
21
33
  identity!: IdentityEntity
@@ -23,6 +23,12 @@ export class NaturalPersonEntity extends BaseContactEntity {
23
23
  @IsNotEmpty({ message: 'Blank display names are not allowed' })
24
24
  displayName!: string
25
25
 
26
+ @Column({name: 'owner_id', nullable: true})
27
+ ownerId?: string
28
+
29
+ @Column({name: 'tenant_id', nullable: true})
30
+ tenantId?: string
31
+
26
32
  @BeforeInsert()
27
33
  @BeforeUpdate()
28
34
  async validate(): Promise<void> {
@@ -23,4 +23,10 @@ export class OpenIdConfigEntity extends BaseConfigEntity {
23
23
 
24
24
  @Column('text', { name: 'client_auth_method', nullable: false })
25
25
  clientAuthMethod!: 'basic' | 'post' | undefined
26
+
27
+ @Column({name: 'owner_id', nullable: true})
28
+ ownerId?: string
29
+
30
+ @Column({name: 'tenant_id', nullable: true})
31
+ tenantId?: string
26
32
  }
@@ -15,6 +15,12 @@ export class OrganizationEntity extends BaseContactEntity {
15
15
  @IsNotEmpty({ message: 'Blank display names are not allowed' })
16
16
  displayName!: string
17
17
 
18
+ @Column({name: 'owner_id', nullable: true})
19
+ ownerId?: string
20
+
21
+ @Column({name: 'tenant_id', nullable: true})
22
+ tenantId?: string
23
+
18
24
  @OneToOne(() => PartyEntity)
19
25
  @JoinColumn({ name: 'party_id' })
20
26
  party!: PartyEntity
@@ -30,6 +30,12 @@ export class PartyEntity extends BaseEntity {
30
30
  @Column({ name: 'uri', length: 255, nullable: true })
31
31
  uri?: string
32
32
 
33
+ @Column({name: 'owner_id', nullable: true})
34
+ ownerId?: string
35
+
36
+ @Column({name: 'tenant_id', nullable: true})
37
+ tenantId?: string
38
+
33
39
  @OneToMany(() => IdentityEntity, (identity: IdentityEntity) => identity.party, {
34
40
  cascade: true,
35
41
  onDelete: 'CASCADE',
@@ -38,6 +38,12 @@ export class PartyRelationshipEntity {
38
38
  @Column({ name: 'right_id', nullable: false })
39
39
  rightId!: string
40
40
 
41
+ @Column({name: 'owner_id', nullable: true})
42
+ ownerId?: string
43
+
44
+ @Column({name: 'tenant_id', nullable: true})
45
+ tenantId?: string
46
+
41
47
  @CreateDateColumn({ name: 'created_at', nullable: false })
42
48
  createdAt!: Date
43
49
 
@@ -11,21 +11,21 @@ export class PartyTypeEntity {
11
11
  @PrimaryGeneratedColumn('uuid')
12
12
  id!: string
13
13
 
14
- @Column('simple-enum', { name: 'type', enum: PartyTypeType, nullable: false, unique: false })
14
+ @Column('simple-enum', { name: 'type', enum: PartyTypeType, nullable: false })
15
15
  type!: PartyTypeType
16
16
 
17
- @Column('simple-enum', { name: 'origin', enum: PartyOrigin, default: 'EXTERNAL', nullable: false, unique: false })
17
+ @Column('simple-enum', { name: 'origin', enum: PartyOrigin, nullable: false, unique: false })
18
18
  origin!: PartyOrigin
19
19
 
20
20
  @Column({ name: 'name', length: 255, nullable: false, unique: true })
21
21
  @IsNotEmpty({ message: 'Blank names are not allowed' })
22
22
  name!: string
23
23
 
24
- @Column({ name: 'description', length: 255, nullable: true, unique: false })
24
+ @Column({ name: 'description', length: 255, nullable: true })
25
25
  @Validate(IsNonEmptyStringConstraint, { message: 'Blank descriptions are not allowed' })
26
26
  description?: string
27
27
 
28
- @Column({ name: 'tenant_id', length: 255, nullable: false, unique: false })
28
+ @Column({ name: 'tenant_id', length: 255, nullable: true })
29
29
  @IsNotEmpty({ message: "Blank tenant id's are not allowed" })
30
30
  tenantId!: string
31
31