@sphereon/ssi-sdk.data-store 0.24.1-next.42 → 0.24.1-next.98

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 (70) hide show
  1. package/LICENSE +1 -1
  2. package/dist/entities/presentationDefinition/PresentationDefinitionItemEntity.d.ts +14 -0
  3. package/dist/entities/presentationDefinition/PresentationDefinitionItemEntity.d.ts.map +1 -0
  4. package/dist/entities/presentationDefinition/PresentationDefinitionItemEntity.js +74 -0
  5. package/dist/entities/presentationDefinition/PresentationDefinitionItemEntity.js.map +1 -0
  6. package/dist/index.d.ts +8 -3
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +13 -2
  9. package/dist/index.js.map +1 -1
  10. package/dist/migrations/generic/10-CreatePresentationDefinitions.d.ts +7 -0
  11. package/dist/migrations/generic/10-CreatePresentationDefinitions.d.ts.map +1 -0
  12. package/dist/migrations/generic/10-CreatePresentationDefinitions.js +78 -0
  13. package/dist/migrations/generic/10-CreatePresentationDefinitions.js.map +1 -0
  14. package/dist/migrations/generic/index.d.ts +2 -0
  15. package/dist/migrations/generic/index.d.ts.map +1 -1
  16. package/dist/migrations/generic/index.js +4 -1
  17. package/dist/migrations/generic/index.js.map +1 -1
  18. package/dist/migrations/index.d.ts +1 -1
  19. package/dist/migrations/index.d.ts.map +1 -1
  20. package/dist/migrations/index.js +2 -1
  21. package/dist/migrations/index.js.map +1 -1
  22. package/dist/migrations/postgres/1716475165345-CreatePresentationDefinitions.d.ts +7 -0
  23. package/dist/migrations/postgres/1716475165345-CreatePresentationDefinitions.d.ts.map +1 -0
  24. package/dist/migrations/postgres/1716475165345-CreatePresentationDefinitions.js +41 -0
  25. package/dist/migrations/postgres/1716475165345-CreatePresentationDefinitions.js.map +1 -0
  26. package/dist/migrations/sqlite/1716475165344-CreatePresentationDefinitions.d.ts +7 -0
  27. package/dist/migrations/sqlite/1716475165344-CreatePresentationDefinitions.d.ts.map +1 -0
  28. package/dist/migrations/sqlite/1716475165344-CreatePresentationDefinitions.js +38 -0
  29. package/dist/migrations/sqlite/1716475165344-CreatePresentationDefinitions.js.map +1 -0
  30. package/dist/presentationDefinition/AbstractPDStore.d.ts +12 -0
  31. package/dist/presentationDefinition/AbstractPDStore.d.ts.map +1 -0
  32. package/dist/presentationDefinition/AbstractPDStore.js +7 -0
  33. package/dist/presentationDefinition/AbstractPDStore.js.map +1 -0
  34. package/dist/presentationDefinition/PDStore.d.ts +19 -0
  35. package/dist/presentationDefinition/PDStore.d.ts.map +1 -0
  36. package/dist/presentationDefinition/PDStore.js +152 -0
  37. package/dist/presentationDefinition/PDStore.js.map +1 -0
  38. package/dist/types/index.d.ts +2 -0
  39. package/dist/types/index.d.ts.map +1 -1
  40. package/dist/types/index.js +2 -0
  41. package/dist/types/index.js.map +1 -1
  42. package/dist/types/presentationDefinition/IAbstractPDStore.d.ts +17 -0
  43. package/dist/types/presentationDefinition/IAbstractPDStore.d.ts.map +1 -0
  44. package/dist/types/presentationDefinition/IAbstractPDStore.js +3 -0
  45. package/dist/types/presentationDefinition/IAbstractPDStore.js.map +1 -0
  46. package/dist/types/presentationDefinition/presentationDefinition.d.ts +16 -0
  47. package/dist/types/presentationDefinition/presentationDefinition.d.ts.map +1 -0
  48. package/dist/types/presentationDefinition/presentationDefinition.js +3 -0
  49. package/dist/types/presentationDefinition/presentationDefinition.js.map +1 -0
  50. package/dist/utils/presentationDefinition/MappingUtils.d.ts +6 -0
  51. package/dist/utils/presentationDefinition/MappingUtils.d.ts.map +1 -0
  52. package/dist/utils/presentationDefinition/MappingUtils.js +48 -0
  53. package/dist/utils/presentationDefinition/MappingUtils.js.map +1 -0
  54. package/package.json +7 -4
  55. package/src/__tests__/pd-manager.entities.test.ts +71 -0
  56. package/src/__tests__/pd-manager.store.test.ts +191 -0
  57. package/src/entities/presentationDefinition/PresentationDefinitionItemEntity.ts +43 -0
  58. package/src/index.ts +10 -0
  59. package/src/migrations/generic/10-CreatePresentationDefinitions.ts +66 -0
  60. package/src/migrations/generic/index.ts +3 -0
  61. package/src/migrations/index.ts +1 -0
  62. package/src/migrations/postgres/1716475165345-CreatePresentationDefinitions.ts +25 -0
  63. package/src/migrations/sqlite/1716475165344-CreatePresentationDefinitions.ts +24 -0
  64. package/src/presentationDefinition/AbstractPDStore.ts +20 -0
  65. package/src/presentationDefinition/PDStore.ts +185 -0
  66. package/src/types/index.ts +2 -0
  67. package/src/types/presentationDefinition/IAbstractPDStore.ts +25 -0
  68. package/src/types/presentationDefinition/presentationDefinition.ts +17 -0
  69. package/src/utils/contact/MappingUtils.ts +1 -1
  70. 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
+ })
@@ -0,0 +1,43 @@
1
+ import { BaseEntity, BeforeInsert, BeforeUpdate, Column, CreateDateColumn, Entity, Index, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'
2
+ import { IsNotEmpty } from 'class-validator'
3
+
4
+ @Entity('PresentationDefinitionItem')
5
+ @Index(['version'], { unique: false })
6
+ export class PresentationDefinitionItemEntity extends BaseEntity {
7
+ @PrimaryGeneratedColumn('uuid')
8
+ id!: string
9
+
10
+ @Column({ name: 'definition_id', length: 255, nullable: false, unique: false })
11
+ @IsNotEmpty({ message: 'A blank definition id field is not allowed' })
12
+ definitionId!: string
13
+
14
+ @Column({ name: 'version', length: 255, nullable: false, unique: false })
15
+ @IsNotEmpty({ message: 'A blank version field is not allowed' })
16
+ version!: string
17
+
18
+ @Column({ name: 'tenant_id', length: 255, nullable: true, unique: false })
19
+ tenantId?: string
20
+
21
+ @Column({ name: 'purpose', length: 255, nullable: true, unique: false })
22
+ purpose?: string
23
+
24
+ @Column({ name: 'name', length: 255, nullable: true, unique: false })
25
+ name?: string
26
+
27
+ @Column({ name: 'definition_payload', type: 'text', nullable: false, unique: false })
28
+ @IsNotEmpty({ message: 'A blank definition payload field is not allowed' })
29
+ definitionPayload!: string
30
+
31
+ @CreateDateColumn({ name: 'created_at', nullable: false })
32
+ createdAt!: Date
33
+
34
+ @UpdateDateColumn({ name: 'last_updated_at', nullable: false })
35
+ lastUpdatedAt!: Date
36
+
37
+ // By default, @UpdateDateColumn in TypeORM updates the timestamp only when the entity's top-level properties change.
38
+ @BeforeInsert()
39
+ @BeforeUpdate()
40
+ updateUpdatedDate(): void {
41
+ this.lastUpdatedAt = new Date()
42
+ }
43
+ }
package/src/index.ts CHANGED
@@ -34,11 +34,15 @@ export { StatusListStore } from './statusList/StatusListStore'
34
34
  import { AuditEventEntity, auditEventEntityFrom } from './entities/eventLogger/AuditEventEntity'
35
35
  import { DigitalCredentialEntity } from './entities/digitalCredential/DigitalCredentialEntity'
36
36
  import { digitalCredentialFrom, digitalCredentialsFrom, nonPersistedDigitalCredentialEntityFromAddArgs } from './utils/digitalCredential/MappingUtils'
37
+ import { isPresentationDefinitionEqual } from './utils/presentationDefinition/MappingUtils'
38
+ import { PresentationDefinitionItemEntity } from './entities/presentationDefinition/PresentationDefinitionItemEntity'
37
39
  import { ContactMetadataItemEntity } from './entities/contact/ContactMetadataItemEntity'
38
40
  export { AbstractEventLoggerStore } from './eventLogger/AbstractEventLoggerStore'
39
41
  export { EventLoggerStore } from './eventLogger/EventLoggerStore'
40
42
  export { IAbstractMachineStateStore } from './machineState/IAbstractMachineStateStore'
41
43
  export { MachineStateStore } from './machineState/MachineStateStore'
44
+ export { AbstractPDStore } from './presentationDefinition/AbstractPDStore'
45
+ export { PDStore } from './presentationDefinition/PDStore'
42
46
 
43
47
  export {
44
48
  DataStoreMigrations,
@@ -47,6 +51,7 @@ export {
47
51
  DataStoreIssuanceBrandingMigrations,
48
52
  DataStoreStatusListMigrations,
49
53
  DataStoreMachineStateMigrations,
54
+ DataStorePresentationDefinitionMigrations,
50
55
  } from './migrations'
51
56
  export * from './types'
52
57
  export * from './utils/contact/MappingUtils'
@@ -82,6 +87,8 @@ export const DataStoreIssuanceBrandingEntities = [
82
87
  IssuerLocaleBrandingEntity,
83
88
  ]
84
89
 
90
+ export const DataStorePresentationDefinitionEntities = [PresentationDefinitionItemEntity]
91
+
85
92
  export const DataStoreStatusListEntities = [StatusListEntity, StatusListEntryEntity]
86
93
 
87
94
  export const DataStoreEventLoggerEntities = [AuditEventEntity]
@@ -98,6 +105,7 @@ export const DataStoreEntities = [
98
105
  ...DataStoreEventLoggerEntities,
99
106
  ...DataStoreDigitalCredentialEntities,
100
107
  ...DataStoreMachineStateEntities,
108
+ ...DataStorePresentationDefinitionEntities,
101
109
  ]
102
110
 
103
111
  export {
@@ -140,5 +148,7 @@ export {
140
148
  digitalCredentialsFrom,
141
149
  nonPersistedDigitalCredentialEntityFromAddArgs,
142
150
  MachineStateInfoEntity,
151
+ PresentationDefinitionItemEntity,
152
+ isPresentationDefinitionEqual,
143
153
  ContactMetadataItemEntity,
144
154
  }
@@ -0,0 +1,66 @@
1
+ import { DatabaseType, MigrationInterface, QueryRunner } from 'typeorm'
2
+ import Debug from 'debug'
3
+ import { CreatePresentationDefinitions1716475165345 } from '../postgres/1716475165345-CreatePresentationDefinitions'
4
+ import { CreatePresentationDefinitions1716475165344 } from '../sqlite/1716475165344-CreatePresentationDefinitions'
5
+
6
+ const debug: Debug.Debugger = Debug('sphereon:ssi-sdk:migrations')
7
+
8
+ export class CreatePresentationDefinitions1716533767523 implements MigrationInterface {
9
+ name = 'CreatePresentationDefinitionItems1716533767523'
10
+
11
+ public async up(queryRunner: QueryRunner): Promise<void> {
12
+ debug('migration: creating machine state tables')
13
+ const dbType: DatabaseType = queryRunner.connection.driver.options.type
14
+
15
+ switch (dbType) {
16
+ case 'postgres': {
17
+ debug('using postgres migration file')
18
+ const mig: CreatePresentationDefinitions1716475165345 = new CreatePresentationDefinitions1716475165345()
19
+ await mig.up(queryRunner)
20
+ debug('Migration statements executed')
21
+ return
22
+ }
23
+ case 'sqlite':
24
+ case 'expo':
25
+ case 'react-native': {
26
+ debug('using sqlite/react-native migration file')
27
+ const mig: CreatePresentationDefinitions1716475165344 = new CreatePresentationDefinitions1716475165344()
28
+ await mig.up(queryRunner)
29
+ debug('Migration statements executed')
30
+ return
31
+ }
32
+ default:
33
+ return Promise.reject(
34
+ `Migrations are currently only supported for sqlite, react-native, expo and postgres. Was ${dbType}. Please run your database without migrations and with 'migrationsRun: false' and 'synchronize: true' for now`,
35
+ )
36
+ }
37
+ }
38
+
39
+ public async down(queryRunner: QueryRunner): Promise<void> {
40
+ debug('migration: reverting machine state tables')
41
+ const dbType: DatabaseType = queryRunner.connection.driver.options.type
42
+
43
+ switch (dbType) {
44
+ case 'postgres': {
45
+ debug('using postgres migration file')
46
+ const mig: CreatePresentationDefinitions1716475165345 = new CreatePresentationDefinitions1716475165345()
47
+ await mig.down(queryRunner)
48
+ debug('Migration statements executed')
49
+ return
50
+ }
51
+ case 'sqlite':
52
+ case 'expo':
53
+ case 'react-native': {
54
+ debug('using sqlite/react-native migration file')
55
+ const mig: CreatePresentationDefinitions1716475165344 = new CreatePresentationDefinitions1716475165344()
56
+ await mig.down(queryRunner)
57
+ debug('Migration statements executed')
58
+ return
59
+ }
60
+ default:
61
+ return Promise.reject(
62
+ `Migrations are currently only supported for sqlite, react-native, expo and postgres. Was ${dbType}. Please run your database without migrations and with 'migrationsRun: false' and 'synchronize: true' for now`,
63
+ )
64
+ }
65
+ }
66
+ }
@@ -7,6 +7,7 @@ import { CreateDigitalCredential1708525189000 } from './6-CreateDigitalCredentia
7
7
  import { CreateMachineStateStore1708098041262 } from './7-CreateMachineStateStore'
8
8
  import { CreateContacts1708525189000 } from './8-CreateContacts'
9
9
  import { CreateContacts1715761125000 } from './9-CreateContacts'
10
+ import { CreatePresentationDefinitions1716533767523 } from './10-CreatePresentationDefinitions'
10
11
 
11
12
  /**
12
13
  * The migrations array that SHOULD be used when initializing a TypeORM database connection.
@@ -28,6 +29,7 @@ export const DataStoreStatusListMigrations = [CreateStatusList1693866470000]
28
29
  export const DataStoreEventLoggerMigrations = [CreateAuditEvents1701635835330]
29
30
  export const DataStoreDigitalCredentialMigrations = [CreateDigitalCredential1708525189000]
30
31
  export const DataStoreMachineStateMigrations = [CreateMachineStateStore1708098041262]
32
+ export const DataStorePresentationDefinitionMigrations = [CreatePresentationDefinitions1716533767523]
31
33
 
32
34
  // All migrations together
33
35
  export const DataStoreMigrations = [
@@ -37,4 +39,5 @@ export const DataStoreMigrations = [
37
39
  ...DataStoreEventLoggerMigrations,
38
40
  ...DataStoreDigitalCredentialMigrations,
39
41
  ...DataStoreMachineStateMigrations,
42
+ ...DataStorePresentationDefinitionMigrations,
40
43
  ]
@@ -6,4 +6,5 @@ export {
6
6
  DataStoreStatusListMigrations,
7
7
  DataStoreDigitalCredentialMigrations,
8
8
  DataStoreMachineStateMigrations,
9
+ DataStorePresentationDefinitionMigrations,
9
10
  } from './generic'
@@ -0,0 +1,25 @@
1
+ import { MigrationInterface, QueryRunner } from 'typeorm'
2
+
3
+ export class CreatePresentationDefinitions1716475165345 implements MigrationInterface {
4
+ name = 'CreatePresentationDefinitions1716475165345'
5
+
6
+ public async up(queryRunner: QueryRunner): Promise<void> {
7
+ await queryRunner.query(`
8
+ CREATE TABLE "PresentationDefinitionItem" (
9
+ "id" uuid NOT NULL DEFAULT uuid_generate_v4(),
10
+ "tenant_id" TEXT,
11
+ "definition_id" TEXT NOT NULL,
12
+ "name" TEXT,
13
+ "version" TEXT NOT NULL,
14
+ "purpose" TEXT,
15
+ "definition_payload" TEXT NOT NULL,
16
+ "created_at" TIMESTAMP NOT NULL DEFAULT now(),
17
+ "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(),
18
+ CONSTRAINT "PK_PresentationDefinitionItem_id" PRIMARY KEY ("id"))
19
+ `)
20
+ }
21
+
22
+ public async down(queryRunner: QueryRunner): Promise<void> {
23
+ await queryRunner.query(`DROP TABLE "PresentationDefinitionItem"`)
24
+ }
25
+ }
@@ -0,0 +1,24 @@
1
+ import { MigrationInterface, QueryRunner } from 'typeorm'
2
+
3
+ export class CreatePresentationDefinitions1716475165344 implements MigrationInterface {
4
+ name = 'CreatePresentationDefinitions1716475165344'
5
+
6
+ public async up(queryRunner: QueryRunner): Promise<void> {
7
+ await queryRunner.query(
8
+ `CREATE TABLE "PresentationDefinitionItem" (
9
+ "id" varchar PRIMARY KEY NOT NULL,
10
+ "tenant_id" varchar,
11
+ "definition_id" varchar NOT NULL,
12
+ "name" varchar,
13
+ "version" varchar NOT NULL,
14
+ "purpose" varchar,
15
+ "definition_payload" varchar NOT NULL,
16
+ "created_at" datetime NOT NULL DEFAULT (datetime('now')),
17
+ "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')))`,
18
+ )
19
+ }
20
+
21
+ public async down(queryRunner: QueryRunner): Promise<void> {
22
+ await queryRunner.query(`DROP TABLE "PresentationDefinitionItem"`)
23
+ }
24
+ }
@@ -0,0 +1,20 @@
1
+ import {
2
+ GetDefinitionArgs,
3
+ GetDefinitionsArgs,
4
+ DeleteDefinitionArgs,
5
+ PresentationDefinitionItem,
6
+ AddDefinitionArgs,
7
+ UpdateDefinitionArgs,
8
+ DeleteDefinitionsArgs,
9
+ } from '../types'
10
+
11
+ export abstract class AbstractPDStore {
12
+ abstract hasDefinition(args: GetDefinitionArgs): Promise<boolean>
13
+ abstract hasDefinitions(args: GetDefinitionsArgs): Promise<boolean>
14
+ abstract getDefinition(args: GetDefinitionArgs): Promise<PresentationDefinitionItem>
15
+ abstract getDefinitions(args: GetDefinitionsArgs): Promise<Array<PresentationDefinitionItem>>
16
+ abstract addDefinition(args: AddDefinitionArgs): Promise<PresentationDefinitionItem>
17
+ abstract updateDefinition(args: UpdateDefinitionArgs): Promise<PresentationDefinitionItem>
18
+ abstract deleteDefinition(args: DeleteDefinitionArgs): Promise<void>
19
+ abstract deleteDefinitions(args: DeleteDefinitionsArgs): Promise<number>
20
+ }
@@ -0,0 +1,185 @@
1
+ import { OrPromise } from '@sphereon/ssi-types'
2
+ import { DataSource, In, Repository } from 'typeorm'
3
+ import { AbstractPDStore } from './AbstractPDStore'
4
+ import Debug from 'debug'
5
+ import {
6
+ DeleteDefinitionArgs,
7
+ DeleteDefinitionsArgs,
8
+ GetDefinitionArgs,
9
+ GetDefinitionsArgs,
10
+ HasDefinitionArgs,
11
+ HasDefinitionsArgs,
12
+ NonPersistedPresentationDefinitionItem,
13
+ PresentationDefinitionItem,
14
+ PresentationDefinitionItemFilter,
15
+ } from '../types'
16
+ import { PresentationDefinitionItemEntity } from '../entities/presentationDefinition/PresentationDefinitionItemEntity'
17
+ import { presentationDefinitionEntityItemFrom, presentationDefinitionItemFrom } from '../utils/presentationDefinition/MappingUtils'
18
+
19
+ const debug: Debug.Debugger = Debug('sphereon:ssi-sdk:pd-store')
20
+
21
+ export class PDStore extends AbstractPDStore {
22
+ private readonly dbConnection: OrPromise<DataSource>
23
+
24
+ constructor(dbConnection: OrPromise<DataSource>) {
25
+ super()
26
+ this.dbConnection = dbConnection
27
+ }
28
+
29
+ getDefinition = async (args: GetDefinitionArgs): Promise<PresentationDefinitionItem> => {
30
+ const { itemId } = args ?? {}
31
+ const pdRepository = (await this.dbConnection).getRepository(PresentationDefinitionItemEntity)
32
+ const result: PresentationDefinitionItemEntity | null = await pdRepository.findOne({
33
+ where: { id: itemId },
34
+ })
35
+ if (!result) {
36
+ return Promise.reject(Error(`No presentation definition item found for id: ${itemId}`))
37
+ }
38
+
39
+ return presentationDefinitionItemFrom(result)
40
+ }
41
+
42
+ hasDefinition = async (args: HasDefinitionArgs): Promise<boolean> => {
43
+ const { itemId } = args ?? {}
44
+ const pdRepository = (await this.dbConnection).getRepository(PresentationDefinitionItemEntity)
45
+
46
+ const resultCount: number = await pdRepository.count({
47
+ where: { id: itemId },
48
+ })
49
+
50
+ return resultCount > 0
51
+ }
52
+
53
+ hasDefinitions = async (args: HasDefinitionsArgs): Promise<boolean> => {
54
+ const { filter } = args
55
+ const pdRepository = (await this.dbConnection).getRepository(PresentationDefinitionItemEntity)
56
+
57
+ const resultCount: number = await pdRepository.count({
58
+ ...(filter && { where: cleanFilter(filter) }),
59
+ })
60
+ return resultCount > 0
61
+ }
62
+
63
+ getDefinitions = async (args: GetDefinitionsArgs): Promise<Array<PresentationDefinitionItem>> => {
64
+ const { filter } = args
65
+ const pdRepository = (await this.dbConnection).getRepository(PresentationDefinitionItemEntity)
66
+ const initialResult = await this.findIds(pdRepository, filter)
67
+ const result: Array<PresentationDefinitionItemEntity> = await pdRepository.find({
68
+ where: {
69
+ id: In(initialResult.map((entity: PresentationDefinitionItemEntity) => entity.id)),
70
+ },
71
+ order: {
72
+ version: 'DESC',
73
+ },
74
+ })
75
+
76
+ return result.map((entity: PresentationDefinitionItemEntity) => presentationDefinitionItemFrom(entity))
77
+ }
78
+
79
+ addDefinition = async (item: NonPersistedPresentationDefinitionItem): Promise<PresentationDefinitionItem> => {
80
+ const pdRepository = (await this.dbConnection).getRepository(PresentationDefinitionItemEntity)
81
+
82
+ const entity: PresentationDefinitionItemEntity = presentationDefinitionEntityItemFrom(item)
83
+ debug('Adding presentation definition entity', item)
84
+ const result: PresentationDefinitionItemEntity = await pdRepository.save(entity, {
85
+ transaction: true,
86
+ })
87
+
88
+ return presentationDefinitionItemFrom(result)
89
+ }
90
+
91
+ updateDefinition = async (item: PresentationDefinitionItem): Promise<PresentationDefinitionItem> => {
92
+ const pdRepository = (await this.dbConnection).getRepository(PresentationDefinitionItemEntity)
93
+
94
+ const result: PresentationDefinitionItemEntity | null = await pdRepository.findOne({
95
+ where: { id: item.id },
96
+ })
97
+ if (!result) {
98
+ return Promise.reject(Error(`No presentation definition entity found for id: ${item.id}`))
99
+ }
100
+
101
+ const updatedEntity: Partial<PresentationDefinitionItemEntity> = {
102
+ ...result,
103
+ }
104
+ updatedEntity.tenantId = item.tenantId
105
+ updatedEntity.definitionId = item.definitionId!
106
+ updatedEntity.version = item.version
107
+ updatedEntity.name = item.name
108
+ updatedEntity.purpose = item.purpose
109
+ updatedEntity.definitionPayload = JSON.stringify(item.definitionPayload!)
110
+
111
+ debug('Updating presentation definition entity', updatedEntity)
112
+ const updateResult: PresentationDefinitionItemEntity = await pdRepository.save(updatedEntity, {
113
+ transaction: true,
114
+ })
115
+
116
+ return presentationDefinitionItemFrom(updateResult)
117
+ }
118
+
119
+ deleteDefinition = async (args: DeleteDefinitionArgs): Promise<void> => {
120
+ const { itemId } = args
121
+
122
+ const pdRepository = (await this.dbConnection).getRepository(PresentationDefinitionItemEntity)
123
+ const entity: PresentationDefinitionItemEntity | null = await pdRepository.findOne({
124
+ where: { id: itemId },
125
+ })
126
+
127
+ if (!entity) {
128
+ return Promise.reject(Error(`No presentation definition found with id: ${itemId}`))
129
+ }
130
+
131
+ debug('Deleting presentation definition entity', entity)
132
+ await pdRepository.delete(entity.id)
133
+ }
134
+
135
+ deleteDefinitions = async (args: DeleteDefinitionsArgs): Promise<number> => {
136
+ const { filter } = args
137
+ const pdRepository = (await this.dbConnection).getRepository(PresentationDefinitionItemEntity)
138
+ const initialResult = await this.findIds(pdRepository, filter)
139
+
140
+ const result: Array<PresentationDefinitionItemEntity> = await pdRepository.find({
141
+ where: {
142
+ id: In(initialResult.map((entity: PresentationDefinitionItemEntity) => entity.id)),
143
+ },
144
+ })
145
+
146
+ for (const entity of result) {
147
+ debug('Deleting presentation definition entity', entity.id)
148
+ await pdRepository.delete(entity.id)
149
+ }
150
+ return result.length
151
+ }
152
+
153
+ findIds = async (
154
+ pdRepository: Repository<PresentationDefinitionItemEntity>,
155
+ filter: Array<PresentationDefinitionItemFilter> | undefined,
156
+ ): Promise<Array<PresentationDefinitionItemEntity>> => {
157
+ const idFilter = filter?.find((f) => f.id !== undefined && f.id !== null)
158
+ if (idFilter) {
159
+ return await pdRepository.find({
160
+ where: { id: idFilter.id },
161
+ })
162
+ } else {
163
+ return await pdRepository.find({
164
+ ...(filter && { where: cleanFilter(filter) }),
165
+ })
166
+ }
167
+ }
168
+ }
169
+
170
+ const cleanFilter = (filter: Array<PresentationDefinitionItemFilter> | undefined): Array<PresentationDefinitionItemFilter> | undefined => {
171
+ if (filter === undefined) {
172
+ return undefined
173
+ }
174
+
175
+ return filter.map((item) => {
176
+ const cleanedItem: PresentationDefinitionItemFilter = {}
177
+ for (const key in item) {
178
+ const value = item[key as keyof PresentationDefinitionItemFilter]
179
+ if (value !== undefined) {
180
+ ;(cleanedItem as any)[key] = value
181
+ }
182
+ }
183
+ return cleanedItem
184
+ })
185
+ }
@@ -1,6 +1,8 @@
1
1
  export * from './issuanceBranding/issuanceBranding'
2
2
  export * from './issuanceBranding/IAbstractIssuanceBrandingStore'
3
3
  export * from './contact/contact'
4
+ export * from './presentationDefinition/presentationDefinition'
5
+ export * from './presentationDefinition/IAbstractPDStore'
4
6
  export * from './contact/IAbstractContactStore'
5
7
  export * from './validation/validation'
6
8
  export * from './statusList/statusList'
@@ -0,0 +1,25 @@
1
+ import { NonPersistedPresentationDefinitionItem, PresentationDefinitionItem, PresentationDefinitionItemFilter } from './presentationDefinition'
2
+
3
+ export type FindDefinitionArgs = Array<PresentationDefinitionItemFilter>
4
+
5
+ export type GetDefinitionArgs = {
6
+ itemId: string
7
+ }
8
+
9
+ export type HasDefinitionArgs = GetDefinitionArgs
10
+
11
+ export type GetDefinitionsArgs = {
12
+ filter?: FindDefinitionArgs
13
+ }
14
+
15
+ export type HasDefinitionsArgs = GetDefinitionsArgs
16
+
17
+ export type AddDefinitionArgs = NonPersistedPresentationDefinitionItem
18
+
19
+ export type UpdateDefinitionArgs = PresentationDefinitionItem
20
+
21
+ export type DeleteDefinitionArgs = {
22
+ itemId: string
23
+ }
24
+
25
+ export type DeleteDefinitionsArgs = GetDefinitionsArgs