@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.
- package/LICENSE +1 -1
- package/dist/entities/presentationDefinition/PresentationDefinitionItemEntity.d.ts +14 -0
- package/dist/entities/presentationDefinition/PresentationDefinitionItemEntity.d.ts.map +1 -0
- package/dist/entities/presentationDefinition/PresentationDefinitionItemEntity.js +74 -0
- package/dist/entities/presentationDefinition/PresentationDefinitionItemEntity.js.map +1 -0
- package/dist/index.d.ts +8 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -2
- package/dist/index.js.map +1 -1
- package/dist/migrations/generic/10-CreatePresentationDefinitions.d.ts +7 -0
- package/dist/migrations/generic/10-CreatePresentationDefinitions.d.ts.map +1 -0
- package/dist/migrations/generic/10-CreatePresentationDefinitions.js +78 -0
- package/dist/migrations/generic/10-CreatePresentationDefinitions.js.map +1 -0
- package/dist/migrations/generic/index.d.ts +2 -0
- package/dist/migrations/generic/index.d.ts.map +1 -1
- package/dist/migrations/generic/index.js +4 -1
- package/dist/migrations/generic/index.js.map +1 -1
- package/dist/migrations/index.d.ts +1 -1
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/migrations/index.js +2 -1
- package/dist/migrations/index.js.map +1 -1
- package/dist/migrations/postgres/1716475165345-CreatePresentationDefinitions.d.ts +7 -0
- package/dist/migrations/postgres/1716475165345-CreatePresentationDefinitions.d.ts.map +1 -0
- package/dist/migrations/postgres/1716475165345-CreatePresentationDefinitions.js +41 -0
- package/dist/migrations/postgres/1716475165345-CreatePresentationDefinitions.js.map +1 -0
- package/dist/migrations/sqlite/1716475165344-CreatePresentationDefinitions.d.ts +7 -0
- package/dist/migrations/sqlite/1716475165344-CreatePresentationDefinitions.d.ts.map +1 -0
- package/dist/migrations/sqlite/1716475165344-CreatePresentationDefinitions.js +38 -0
- package/dist/migrations/sqlite/1716475165344-CreatePresentationDefinitions.js.map +1 -0
- package/dist/presentationDefinition/AbstractPDStore.d.ts +12 -0
- package/dist/presentationDefinition/AbstractPDStore.d.ts.map +1 -0
- package/dist/presentationDefinition/AbstractPDStore.js +7 -0
- package/dist/presentationDefinition/AbstractPDStore.js.map +1 -0
- package/dist/presentationDefinition/PDStore.d.ts +19 -0
- package/dist/presentationDefinition/PDStore.d.ts.map +1 -0
- package/dist/presentationDefinition/PDStore.js +152 -0
- package/dist/presentationDefinition/PDStore.js.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/presentationDefinition/IAbstractPDStore.d.ts +17 -0
- package/dist/types/presentationDefinition/IAbstractPDStore.d.ts.map +1 -0
- package/dist/types/presentationDefinition/IAbstractPDStore.js +3 -0
- package/dist/types/presentationDefinition/IAbstractPDStore.js.map +1 -0
- package/dist/types/presentationDefinition/presentationDefinition.d.ts +16 -0
- package/dist/types/presentationDefinition/presentationDefinition.d.ts.map +1 -0
- package/dist/types/presentationDefinition/presentationDefinition.js +3 -0
- package/dist/types/presentationDefinition/presentationDefinition.js.map +1 -0
- package/dist/utils/presentationDefinition/MappingUtils.d.ts +6 -0
- package/dist/utils/presentationDefinition/MappingUtils.d.ts.map +1 -0
- package/dist/utils/presentationDefinition/MappingUtils.js +48 -0
- package/dist/utils/presentationDefinition/MappingUtils.js.map +1 -0
- package/package.json +7 -4
- package/src/__tests__/pd-manager.entities.test.ts +71 -0
- package/src/__tests__/pd-manager.store.test.ts +191 -0
- package/src/entities/presentationDefinition/PresentationDefinitionItemEntity.ts +43 -0
- package/src/index.ts +10 -0
- package/src/migrations/generic/10-CreatePresentationDefinitions.ts +66 -0
- package/src/migrations/generic/index.ts +3 -0
- package/src/migrations/index.ts +1 -0
- package/src/migrations/postgres/1716475165345-CreatePresentationDefinitions.ts +25 -0
- package/src/migrations/sqlite/1716475165344-CreatePresentationDefinitions.ts +24 -0
- package/src/presentationDefinition/AbstractPDStore.ts +20 -0
- package/src/presentationDefinition/PDStore.ts +185 -0
- package/src/types/index.ts +2 -0
- package/src/types/presentationDefinition/IAbstractPDStore.ts +25 -0
- package/src/types/presentationDefinition/presentationDefinition.ts +17 -0
- package/src/utils/contact/MappingUtils.ts +1 -1
- 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
|
]
|
package/src/migrations/index.ts
CHANGED
|
@@ -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
|
+
}
|
package/src/types/index.ts
CHANGED
|
@@ -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
|