@sphereon/ssi-sdk.data-store 0.34.1-feature.SSISDK.45.94 → 0.34.1-feature.SSISDK.46.151
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/dist/index.cjs +299 -123
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +299 -123
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
- package/src/__tests__/contact.entities.test.ts +2 -2
- package/src/__tests__/contact.store.test.ts +1 -1
- package/src/__tests__/digitalCredential.entities.test.ts +2 -1
- package/src/__tests__/digitalCredential.store.test.ts +5 -5
- package/src/__tests__/pd-manager.entities.test.ts +14 -37
- package/src/__tests__/pd-manager.store.test.ts +133 -0
- package/src/entities/presentationDefinition/PresentationDefinitionItemEntity.ts +1 -1
- package/src/migrations/generic/12-CreateBitstringStatusList.ts +1 -0
- package/src/migrations/generic/13-UpdatePresentationDefinitionItemNullable.ts +67 -0
- package/src/migrations/generic/index.ts +5 -1
- package/src/migrations/postgres/1756975509000-UpdatePresentationDefinitionItemNullable.ts +15 -0
- package/src/migrations/sqlite/1756975340000-UpdatePresentationDefinitionItemNullable.ts +77 -0
- package/src/presentationDefinition/PDStore.ts +6 -1
- package/src/types/presentationDefinition/presentationDefinition.ts +3 -3
- package/src/utils/presentationDefinition/MappingUtils.ts +39 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sphereon/ssi-sdk.data-store",
|
|
3
|
-
"version": "0.34.1-feature.SSISDK.
|
|
3
|
+
"version": "0.34.1-feature.SSISDK.46.151+d3c33df4",
|
|
4
4
|
"source": "src/index.ts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -28,16 +28,16 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@sphereon/kmp-mdoc-core": "0.2.0-SNAPSHOT.26",
|
|
30
30
|
"@sphereon/pex": "5.0.0-unstable.28",
|
|
31
|
-
"@sphereon/ssi-sdk-ext.did-utils": "0.34.1-feature.SSISDK.
|
|
32
|
-
"@sphereon/ssi-sdk-ext.identifier-resolution": "0.34.1-feature.SSISDK.
|
|
33
|
-
"@sphereon/ssi-sdk.agent-config": "0.34.1-feature.SSISDK.
|
|
34
|
-
"@sphereon/ssi-sdk.core": "0.34.1-feature.SSISDK.
|
|
35
|
-
"@sphereon/ssi-types": "0.34.1-feature.SSISDK.
|
|
31
|
+
"@sphereon/ssi-sdk-ext.did-utils": "0.34.1-feature.SSISDK.46.151+d3c33df4",
|
|
32
|
+
"@sphereon/ssi-sdk-ext.identifier-resolution": "0.34.1-feature.SSISDK.46.151+d3c33df4",
|
|
33
|
+
"@sphereon/ssi-sdk.agent-config": "0.34.1-feature.SSISDK.46.151+d3c33df4",
|
|
34
|
+
"@sphereon/ssi-sdk.core": "0.34.1-feature.SSISDK.46.151+d3c33df4",
|
|
35
|
+
"@sphereon/ssi-types": "0.34.1-feature.SSISDK.46.151+d3c33df4",
|
|
36
36
|
"@veramo/core": "4.2.0",
|
|
37
37
|
"@veramo/utils": "4.2.0",
|
|
38
38
|
"blakejs": "^1.2.1",
|
|
39
39
|
"class-validator": "0.14.1",
|
|
40
|
-
"dcql": "0.
|
|
40
|
+
"dcql": "1.0.1",
|
|
41
41
|
"debug": "^4.3.5",
|
|
42
42
|
"typeorm": "0.3.20"
|
|
43
43
|
},
|
|
@@ -65,5 +65,5 @@
|
|
|
65
65
|
"PostgreSQL",
|
|
66
66
|
"Contact Store"
|
|
67
67
|
],
|
|
68
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "d3c33df44daea79ddf7863e0bf12234ec4837cfd"
|
|
69
69
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { getDID } from '@sphereon/ssi-sdk-ext.did-utils'
|
|
2
2
|
import { DataSources } from '@sphereon/ssi-sdk.agent-config'
|
|
3
|
+
import { CredentialRole } from '@sphereon/ssi-types'
|
|
3
4
|
import { DataSource, FindOptionsWhere } from 'typeorm'
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
|
4
6
|
import { BaseContactEntity } from '../entities/contact/BaseContactEntity'
|
|
5
7
|
import { ConnectionEntity } from '../entities/contact/ConnectionEntity'
|
|
6
8
|
import { ContactMetadataItemEntity } from '../entities/contact/ContactMetadataItemEntity'
|
|
@@ -18,7 +20,6 @@ import { PartyTypeEntity } from '../entities/contact/PartyTypeEntity'
|
|
|
18
20
|
import { PhysicalAddressEntity } from '../entities/contact/PhysicalAddressEntity'
|
|
19
21
|
import {
|
|
20
22
|
contactMetadataItemEntityFrom,
|
|
21
|
-
CredentialRole,
|
|
22
23
|
DataStoreContactEntities,
|
|
23
24
|
DataStoreMigrations,
|
|
24
25
|
identityMetadataItemEntityFrom,
|
|
@@ -57,7 +58,6 @@ import {
|
|
|
57
58
|
partyTypeEntityFrom,
|
|
58
59
|
physicalAddressEntityFrom,
|
|
59
60
|
} from '../utils/contact/MappingUtils'
|
|
60
|
-
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
|
61
61
|
// TODO write test adding two contacts reusing the same contactType
|
|
62
62
|
|
|
63
63
|
describe('Database entities tests', (): void => {
|
|
@@ -4,7 +4,6 @@ import { ConnectionType, DataStoreContactEntities, DataStoreMigrations, Identity
|
|
|
4
4
|
import { ContactStore } from '../contact/ContactStore'
|
|
5
5
|
import {
|
|
6
6
|
CorrelationIdentifierType,
|
|
7
|
-
CredentialRole,
|
|
8
7
|
ElectronicAddress,
|
|
9
8
|
GetElectronicAddressesArgs,
|
|
10
9
|
GetIdentitiesArgs,
|
|
@@ -27,6 +26,7 @@ import {
|
|
|
27
26
|
PhysicalAddress,
|
|
28
27
|
} from '../types'
|
|
29
28
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
|
29
|
+
import { CredentialRole } from "@sphereon/ssi-types"
|
|
30
30
|
|
|
31
31
|
describe('Contact store tests', (): void => {
|
|
32
32
|
let dbConnection: DataSource
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DataSources } from '@sphereon/ssi-sdk.agent-config'
|
|
2
|
+
import { CredentialRole } from '@sphereon/ssi-types'
|
|
2
3
|
import { DataSource } from 'typeorm'
|
|
3
|
-
import {
|
|
4
|
+
import { DataStoreDigitalCredentialEntities } from '../index'
|
|
4
5
|
import { DataStoreDigitalCredentialMigrations } from '../migrations'
|
|
5
6
|
import { DigitalCredentialEntity } from '../entities/digitalCredential/DigitalCredentialEntity'
|
|
6
7
|
import { computeEntryHash } from '@veramo/utils'
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { DataSources } from '@sphereon/ssi-sdk.agent-config'
|
|
2
|
-
import {
|
|
2
|
+
import { defaultHasher } from '@sphereon/ssi-sdk.core'
|
|
3
|
+
import { CredentialRole, IVerifiablePresentation } from '@sphereon/ssi-types'
|
|
3
4
|
import { DataSource } from 'typeorm'
|
|
4
|
-
import {
|
|
5
|
-
import { CredentialRole, DataStoreDigitalCredentialEntities } from '../index'
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
|
6
6
|
import { DigitalCredentialStore } from '../digitalCredential/DigitalCredentialStore'
|
|
7
|
+
import { DataStoreDigitalCredentialEntities } from '../index'
|
|
8
|
+
import { DataStoreDigitalCredentialMigrations } from '../migrations'
|
|
7
9
|
import {
|
|
8
10
|
AddCredentialArgs,
|
|
9
11
|
CredentialCorrelationType,
|
|
@@ -14,8 +16,6 @@ import {
|
|
|
14
16
|
GetCredentialsArgs,
|
|
15
17
|
GetCredentialsResponse,
|
|
16
18
|
} from '../types'
|
|
17
|
-
import { defaultHasher } from '@sphereon/ssi-sdk.core'
|
|
18
|
-
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
|
19
19
|
|
|
20
20
|
describe('Database entities tests', (): void => {
|
|
21
21
|
let dbConnection: DataSource
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { DataSources } from '@sphereon/ssi-sdk.agent-config'
|
|
2
|
+
import { DcqlQuery } from 'dcql'
|
|
2
3
|
import { DataSource } from 'typeorm'
|
|
3
4
|
import { PresentationDefinitionItemEntity } from '../entities/presentationDefinition/PresentationDefinitionItemEntity'
|
|
4
5
|
import { DataStorePresentationDefinitionMigrations } from '../migrations'
|
|
5
6
|
import { DataStorePresentationDefinitionEntities } from '../index'
|
|
6
7
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
|
8
|
+
import { SAMPLE_DCQL_QUERY_PAYLOAD } from './pd-manager.store.test'
|
|
7
9
|
|
|
8
10
|
describe('PresentationDefinitionItemEntity tests', (): void => {
|
|
9
11
|
let dbConnection: DataSource
|
|
@@ -28,23 +30,9 @@ describe('PresentationDefinitionItemEntity tests', (): void => {
|
|
|
28
30
|
it('should create and retrieve PresentationDefinitionItemEntity with dcqlPayload', async (): Promise<void> => {
|
|
29
31
|
const repository = dbConnection.getRepository(PresentationDefinitionItemEntity)
|
|
30
32
|
const entity = new PresentationDefinitionItemEntity()
|
|
31
|
-
entity.definitionId = '
|
|
33
|
+
entity.definitionId = 'ajax-club'
|
|
32
34
|
entity.version = '1.0'
|
|
33
|
-
entity.
|
|
34
|
-
entity.dcqlPayload = JSON.stringify({
|
|
35
|
-
credentials: [
|
|
36
|
-
{
|
|
37
|
-
id: 'credential1',
|
|
38
|
-
format: 'jwt_vc',
|
|
39
|
-
claims: [
|
|
40
|
-
{
|
|
41
|
-
namespace: 'test',
|
|
42
|
-
claim_name: 'testClaim',
|
|
43
|
-
},
|
|
44
|
-
],
|
|
45
|
-
},
|
|
46
|
-
],
|
|
47
|
-
})
|
|
35
|
+
entity.dcqlPayload = JSON.stringify(SAMPLE_DCQL_QUERY_PAYLOAD.dcqlQuery)
|
|
48
36
|
|
|
49
37
|
const savedEntity = await repository.save(entity)
|
|
50
38
|
expect(savedEntity).toBeDefined()
|
|
@@ -55,29 +43,18 @@ describe('PresentationDefinitionItemEntity tests', (): void => {
|
|
|
55
43
|
expect(retrievedEntity).toBeDefined()
|
|
56
44
|
expect(retrievedEntity!.dcqlPayload).toBeDefined()
|
|
57
45
|
const parsedDcql = JSON.parse(retrievedEntity!.dcqlPayload)
|
|
58
|
-
expect(parsedDcql.credentials[0].id).toEqual('
|
|
46
|
+
expect(parsedDcql.credentials[0].id).toEqual('clubcard-v1')
|
|
47
|
+
expect(parsedDcql.credentials[0].format).toEqual('dc+sd-jwt')
|
|
48
|
+
expect(parsedDcql.credentials[0].meta.vct_values).toContain('clubcard-v1')
|
|
49
|
+
expect(parsedDcql.credentials[0].claims).toHaveLength(4)
|
|
59
50
|
})
|
|
60
51
|
|
|
61
52
|
it('should update PresentationDefinitionItemEntity dcqlPayload', async (): Promise<void> => {
|
|
62
53
|
const repository = dbConnection.getRepository(PresentationDefinitionItemEntity)
|
|
63
54
|
const entity = new PresentationDefinitionItemEntity()
|
|
64
|
-
entity.definitionId = '
|
|
55
|
+
entity.definitionId = 'ajax-club'
|
|
65
56
|
entity.version = '1.0'
|
|
66
|
-
entity.
|
|
67
|
-
entity.dcqlPayload = JSON.stringify({
|
|
68
|
-
credentials: [
|
|
69
|
-
{
|
|
70
|
-
id: 'credential1',
|
|
71
|
-
format: 'jwt_vc',
|
|
72
|
-
claims: [
|
|
73
|
-
{
|
|
74
|
-
namespace: 'test',
|
|
75
|
-
claim_name: 'testClaim',
|
|
76
|
-
},
|
|
77
|
-
],
|
|
78
|
-
},
|
|
79
|
-
],
|
|
80
|
-
})
|
|
57
|
+
entity.dcqlPayload = JSON.stringify(SAMPLE_DCQL_QUERY_PAYLOAD.dcqlQuery)
|
|
81
58
|
|
|
82
59
|
const savedEntity = await repository.save(entity)
|
|
83
60
|
expect(savedEntity).toBeDefined()
|
|
@@ -85,12 +62,11 @@ describe('PresentationDefinitionItemEntity tests', (): void => {
|
|
|
85
62
|
const updatedDcql = {
|
|
86
63
|
credentials: [
|
|
87
64
|
{
|
|
88
|
-
id: '
|
|
65
|
+
id: 'updated-clubcard',
|
|
89
66
|
format: 'jwt_vc',
|
|
90
67
|
claims: [
|
|
91
68
|
{
|
|
92
|
-
|
|
93
|
-
claim_name: 'updatedClaim',
|
|
69
|
+
path: ['name'],
|
|
94
70
|
},
|
|
95
71
|
],
|
|
96
72
|
},
|
|
@@ -99,7 +75,8 @@ describe('PresentationDefinitionItemEntity tests', (): void => {
|
|
|
99
75
|
savedEntity.dcqlPayload = JSON.stringify(updatedDcql)
|
|
100
76
|
const updatedEntity = await repository.save(savedEntity)
|
|
101
77
|
expect(updatedEntity).toBeDefined()
|
|
102
|
-
expect(JSON.parse(updatedEntity.dcqlPayload).credentials[0].id).toEqual('
|
|
78
|
+
expect(JSON.parse(updatedEntity.dcqlPayload).credentials[0].id).toEqual('updated-clubcard')
|
|
79
|
+
expect(JSON.parse(updatedEntity.dcqlPayload).credentials[0].format).toEqual('jwt_vc')
|
|
103
80
|
})
|
|
104
81
|
|
|
105
82
|
it('should create and retrieve PresentationDefinitionItemEntity', async (): Promise<void> => {
|
|
@@ -1,9 +1,41 @@
|
|
|
1
1
|
import { DataSources } from '@sphereon/ssi-sdk.agent-config'
|
|
2
|
+
import { DcqlQueryPayload } from '@sphereon/ssi-types'
|
|
2
3
|
import { DataSource } from 'typeorm'
|
|
3
4
|
import { DataStorePresentationDefinitionEntities, DataStorePresentationDefinitionMigrations, PDStore } from '../index'
|
|
4
5
|
import { GetDefinitionsArgs, NonPersistedPresentationDefinitionItem, PresentationDefinitionItem } from '../types'
|
|
5
6
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
|
6
7
|
|
|
8
|
+
export const SAMPLE_DCQL_QUERY_PAYLOAD: DcqlQueryPayload = {
|
|
9
|
+
queryId: 'ajax-club',
|
|
10
|
+
dcqlQuery: {
|
|
11
|
+
credentials: [
|
|
12
|
+
{
|
|
13
|
+
id: 'clubcard-v1',
|
|
14
|
+
format: 'dc+sd-jwt',
|
|
15
|
+
require_cryptographic_holder_binding: true,
|
|
16
|
+
multiple: false,
|
|
17
|
+
meta: {
|
|
18
|
+
vct_values: ['clubcard-v1'],
|
|
19
|
+
},
|
|
20
|
+
claims: [
|
|
21
|
+
{
|
|
22
|
+
path: ['personData', 'name'],
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
path: ['personData', 'birthDate'],
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
path: ['membershipData', 'membershipId'],
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
path: ['membershipData', 'season'],
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
}
|
|
38
|
+
|
|
7
39
|
describe('PDStore tests', (): void => {
|
|
8
40
|
let dbConnection: DataSource
|
|
9
41
|
let pdStore: PDStore
|
|
@@ -130,6 +162,23 @@ describe('PDStore tests', (): void => {
|
|
|
130
162
|
expect(result.definitionId).toEqual(definition.definitionId)
|
|
131
163
|
})
|
|
132
164
|
|
|
165
|
+
it('should add definition with dcqlPayload', async (): Promise<void> => {
|
|
166
|
+
const definition: NonPersistedPresentationDefinitionItem = {
|
|
167
|
+
definitionId: 'ajax-club',
|
|
168
|
+
version: '1.0',
|
|
169
|
+
definitionPayload: { id: 'ajax-club', input_descriptors: [] },
|
|
170
|
+
dcqlPayload: SAMPLE_DCQL_QUERY_PAYLOAD,
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const result: PresentationDefinitionItem = await pdStore.addDefinition(definition)
|
|
174
|
+
|
|
175
|
+
expect(result).toBeDefined()
|
|
176
|
+
expect(result.definitionId).toEqual(definition.definitionId)
|
|
177
|
+
expect(result.dcqlPayload).toBeDefined()
|
|
178
|
+
expect(result.dcqlPayload?.dcqlQuery.credentials[0].id).toEqual('clubcard-v1')
|
|
179
|
+
expect(result.dcqlPayload?.dcqlQuery.credentials[0].format).toEqual('dc+sd-jwt')
|
|
180
|
+
})
|
|
181
|
+
|
|
133
182
|
it('should update definition', async (): Promise<void> => {
|
|
134
183
|
const definition: NonPersistedPresentationDefinitionItem = {
|
|
135
184
|
definitionId: 'definition1',
|
|
@@ -151,6 +200,90 @@ describe('PDStore tests', (): void => {
|
|
|
151
200
|
expect(result.version).toEqual('1.1')
|
|
152
201
|
})
|
|
153
202
|
|
|
203
|
+
it('should update definition with dcqlPayload', async (): Promise<void> => {
|
|
204
|
+
const definition: NonPersistedPresentationDefinitionItem = {
|
|
205
|
+
definitionId: 'ajax-club',
|
|
206
|
+
version: '1.0',
|
|
207
|
+
definitionPayload: { id: 'ajax-club', input_descriptors: [] },
|
|
208
|
+
dcqlPayload: SAMPLE_DCQL_QUERY_PAYLOAD,
|
|
209
|
+
}
|
|
210
|
+
const savedDefinition: PresentationDefinitionItem = await pdStore.addDefinition(definition)
|
|
211
|
+
expect(savedDefinition).toBeDefined()
|
|
212
|
+
|
|
213
|
+
const updatedDcqlQueryPayload = {
|
|
214
|
+
...SAMPLE_DCQL_QUERY_PAYLOAD,
|
|
215
|
+
dcqlQuery: {
|
|
216
|
+
credentials: [
|
|
217
|
+
{
|
|
218
|
+
id: 'updated-clubcard',
|
|
219
|
+
format: 'dc+sd-jwt',
|
|
220
|
+
claims: [
|
|
221
|
+
{
|
|
222
|
+
path: ['name'],
|
|
223
|
+
},
|
|
224
|
+
],
|
|
225
|
+
},
|
|
226
|
+
],
|
|
227
|
+
},
|
|
228
|
+
} as unknown as DcqlQueryPayload // FIXME I do not have another solution for this atm, I can do Partial<DcqlQuery> but that does not work for its child entities
|
|
229
|
+
|
|
230
|
+
const updatedDefinition: PresentationDefinitionItem = {
|
|
231
|
+
...savedDefinition,
|
|
232
|
+
version: '1.1',
|
|
233
|
+
dcqlPayload: updatedDcqlQueryPayload,
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
await pdStore.updateDefinition(updatedDefinition)
|
|
237
|
+
const result: PresentationDefinitionItem = await pdStore.getDefinition({ itemId: savedDefinition.id })
|
|
238
|
+
|
|
239
|
+
expect(result).toBeDefined()
|
|
240
|
+
expect(result.version).toEqual('1.1')
|
|
241
|
+
expect(result.dcqlPayload?.dcqlQuery.credentials[0].id).toEqual('updated-clubcard')
|
|
242
|
+
expect(result.dcqlPayload?.dcqlQuery.credentials[0].format).toEqual('dc+sd-jwt')
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
it('should get definition with dcqlPayload by id', async (): Promise<void> => {
|
|
246
|
+
const definition: NonPersistedPresentationDefinitionItem = {
|
|
247
|
+
definitionId: 'ajax-club',
|
|
248
|
+
version: '1.0',
|
|
249
|
+
definitionPayload: { id: 'ajax-club', input_descriptors: [] },
|
|
250
|
+
dcqlPayload: SAMPLE_DCQL_QUERY_PAYLOAD,
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const savedDefinition: PresentationDefinitionItem = await pdStore.addDefinition(definition)
|
|
254
|
+
expect(savedDefinition).toBeDefined()
|
|
255
|
+
|
|
256
|
+
const result: PresentationDefinitionItem = await pdStore.getDefinition({ itemId: savedDefinition.id })
|
|
257
|
+
|
|
258
|
+
expect(result).toBeDefined()
|
|
259
|
+
expect(result.dcqlPayload).toBeDefined()
|
|
260
|
+
expect(result.dcqlPayload?.dcqlQuery.credentials[0].format).toBe('dc+sd-jwt')
|
|
261
|
+
if (result.dcqlPayload?.dcqlQuery.credentials[0].format === 'dc+sd-jwt') {
|
|
262
|
+
expect(result.dcqlPayload.dcqlQuery.credentials[0].meta?.vct_values).toContain('clubcard-v1')
|
|
263
|
+
}
|
|
264
|
+
expect(result.dcqlPayload?.dcqlQuery.credentials[0].claims).toHaveLength(4)
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
it('should get definitions with dcqlPayload by filter', async (): Promise<void> => {
|
|
268
|
+
const definition: NonPersistedPresentationDefinitionItem = {
|
|
269
|
+
definitionId: 'ajax-club',
|
|
270
|
+
version: '1.0',
|
|
271
|
+
definitionPayload: { id: 'ajax-club', input_descriptors: [] },
|
|
272
|
+
dcqlPayload: SAMPLE_DCQL_QUERY_PAYLOAD,
|
|
273
|
+
}
|
|
274
|
+
const savedDefinition: PresentationDefinitionItem = await pdStore.addDefinition(definition)
|
|
275
|
+
expect(savedDefinition).toBeDefined()
|
|
276
|
+
|
|
277
|
+
const args: GetDefinitionsArgs = {
|
|
278
|
+
filter: [{ definitionId: 'ajax-club' }],
|
|
279
|
+
}
|
|
280
|
+
const result: Array<PresentationDefinitionItem> = await pdStore.getDefinitions(args)
|
|
281
|
+
|
|
282
|
+
expect(result.length).toEqual(1)
|
|
283
|
+
expect(result[0].dcqlPayload).toBeDefined()
|
|
284
|
+
expect(result[0].dcqlPayload?.dcqlQuery.credentials[0].id).toEqual('clubcard-v1')
|
|
285
|
+
})
|
|
286
|
+
|
|
154
287
|
it('should delete definition', async (): Promise<void> => {
|
|
155
288
|
const definition: NonPersistedPresentationDefinitionItem = {
|
|
156
289
|
definitionId: 'definition1',
|
|
@@ -25,7 +25,7 @@ export class PresentationDefinitionItemEntity extends BaseEntity {
|
|
|
25
25
|
@Column({ name: 'name', length: 255, type: 'varchar', nullable: true, unique: false })
|
|
26
26
|
name?: string
|
|
27
27
|
|
|
28
|
-
@Column({ name: 'definition_payload', type: 'text', nullable:
|
|
28
|
+
@Column({ name: 'definition_payload', type: 'text', nullable: true, unique: false })
|
|
29
29
|
@IsNotEmpty({ message: 'A blank PD definition payload field is not allowed' })
|
|
30
30
|
definitionPayload!: string
|
|
31
31
|
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import Debug from 'debug'
|
|
2
|
+
import { DatabaseType, MigrationInterface, QueryRunner } from 'typeorm'
|
|
3
|
+
|
|
4
|
+
import { UpdatePresentationDefinitionItemNullablePG1741895824000 } from '../postgres/1756975509000-UpdatePresentationDefinitionItemNullable'
|
|
5
|
+
import { UpdatePresentationDefinitionItemNullableSqlite1756975340000 } from '../sqlite/1756975340000-UpdatePresentationDefinitionItemNullable'
|
|
6
|
+
|
|
7
|
+
const debug: Debug.Debugger = Debug('sphereon:ssi-sdk:migrations')
|
|
8
|
+
|
|
9
|
+
export class UpdatePresentationDefinitionItemNullable1741895824000 implements MigrationInterface {
|
|
10
|
+
name = 'UpdatePresentationDefinitionItemNullable1741895824000'
|
|
11
|
+
|
|
12
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
13
|
+
debug('migration: updating presentation definition item nullable fields')
|
|
14
|
+
const dbType: DatabaseType = queryRunner.connection.driver.options.type
|
|
15
|
+
|
|
16
|
+
switch (dbType) {
|
|
17
|
+
case 'postgres': {
|
|
18
|
+
debug('using postgres migration file')
|
|
19
|
+
const mig: UpdatePresentationDefinitionItemNullablePG1741895824000 = new UpdatePresentationDefinitionItemNullablePG1741895824000()
|
|
20
|
+
await mig.up(queryRunner)
|
|
21
|
+
debug('Migration statements executed')
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
case 'sqlite':
|
|
25
|
+
case 'expo':
|
|
26
|
+
case 'react-native': {
|
|
27
|
+
debug('using sqlite/react-native migration file')
|
|
28
|
+
const mig: UpdatePresentationDefinitionItemNullableSqlite1756975340000 = new UpdatePresentationDefinitionItemNullableSqlite1756975340000()
|
|
29
|
+
await mig.up(queryRunner)
|
|
30
|
+
debug('Migration statements executed')
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
default:
|
|
34
|
+
return Promise.reject(
|
|
35
|
+
`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`,
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
41
|
+
debug('migration: reverting presentation definition item nullable fields')
|
|
42
|
+
const dbType: DatabaseType = queryRunner.connection.driver.options.type
|
|
43
|
+
|
|
44
|
+
switch (dbType) {
|
|
45
|
+
case 'postgres': {
|
|
46
|
+
debug('using postgres migration file')
|
|
47
|
+
const mig: UpdatePresentationDefinitionItemNullablePG1741895824000 = new UpdatePresentationDefinitionItemNullablePG1741895824000()
|
|
48
|
+
await mig.down(queryRunner)
|
|
49
|
+
debug('Migration statements executed')
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
case 'sqlite':
|
|
53
|
+
case 'expo':
|
|
54
|
+
case 'react-native': {
|
|
55
|
+
debug('using sqlite/react-native migration file')
|
|
56
|
+
const mig: UpdatePresentationDefinitionItemNullableSqlite1756975340000 = new UpdatePresentationDefinitionItemNullableSqlite1756975340000()
|
|
57
|
+
await mig.down(queryRunner)
|
|
58
|
+
debug('Migration statements executed')
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
default:
|
|
62
|
+
return Promise.reject(
|
|
63
|
+
`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`,
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -2,6 +2,7 @@ import { CreateContacts1659463079429 } from './1-CreateContacts'
|
|
|
2
2
|
import { CreatePresentationDefinitions1716533767523 } from './10-CreatePresentationDefinitions'
|
|
3
3
|
import { FixCredentialClaimsReferencesUuid1741895822987 } from './11-FixCredentialClaimsReferenceUuid'
|
|
4
4
|
import { AddBitstringStatusListEnum1741895823000, CreateBitstringStatusList1741895823000 } from './12-CreateBitstringStatusList'
|
|
5
|
+
import { UpdatePresentationDefinitionItemNullable1741895824000 } from './13-UpdatePresentationDefinitionItemNullable'
|
|
5
6
|
import { CreateIssuanceBranding1659463079429 } from './2-CreateIssuanceBranding'
|
|
6
7
|
import { CreateContacts1690925872318 } from './3-CreateContacts'
|
|
7
8
|
import { CreateStatusList1693866470000 } from './4-CreateStatusList'
|
|
@@ -35,7 +36,10 @@ export const DataStoreStatusListMigrations = [
|
|
|
35
36
|
export const DataStoreEventLoggerMigrations = [CreateAuditEvents1701635835330]
|
|
36
37
|
export const DataStoreDigitalCredentialMigrations = [CreateDigitalCredential1708525189000]
|
|
37
38
|
export const DataStoreMachineStateMigrations = [CreateMachineStateStore1708098041262]
|
|
38
|
-
export const DataStorePresentationDefinitionMigrations = [
|
|
39
|
+
export const DataStorePresentationDefinitionMigrations = [
|
|
40
|
+
CreatePresentationDefinitions1716533767523,
|
|
41
|
+
UpdatePresentationDefinitionItemNullable1741895824000,
|
|
42
|
+
]
|
|
39
43
|
|
|
40
44
|
// All migrations together
|
|
41
45
|
export const DataStoreMigrations = [
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from 'typeorm'
|
|
2
|
+
|
|
3
|
+
export class UpdatePresentationDefinitionItemNullablePG1741895824000 implements MigrationInterface {
|
|
4
|
+
name = 'UpdatePresentationDefinitionItemNullable1741895824000'
|
|
5
|
+
|
|
6
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
7
|
+
// Make definition_payload nullable
|
|
8
|
+
await queryRunner.query(`ALTER TABLE "PresentationDefinitionItem" ALTER COLUMN "definition_payload" DROP NOT NULL`)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
12
|
+
// Make definition_payload NOT NULL again
|
|
13
|
+
await queryRunner.query(`ALTER TABLE "PresentationDefinitionItem" ALTER COLUMN "definition_payload" SET NOT NULL`)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from 'typeorm'
|
|
2
|
+
|
|
3
|
+
export class UpdatePresentationDefinitionItemNullableSqlite1756975340000 implements MigrationInterface {
|
|
4
|
+
name = 'UpdatePresentationDefinitionItemNullable1756975340000'
|
|
5
|
+
|
|
6
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
7
|
+
// Create temporary table with updated schema (definition_payload nullable)
|
|
8
|
+
await queryRunner.query(`
|
|
9
|
+
CREATE TABLE "temporary_PresentationDefinitionItem" (
|
|
10
|
+
"id" varchar PRIMARY KEY NOT NULL,
|
|
11
|
+
"definition_id" varchar(255) NOT NULL,
|
|
12
|
+
"version" varchar(255) NOT NULL,
|
|
13
|
+
"tenant_id" varchar(255),
|
|
14
|
+
"purpose" varchar(255),
|
|
15
|
+
"name" varchar(255),
|
|
16
|
+
"definition_payload" text,
|
|
17
|
+
"dcql_payload" text,
|
|
18
|
+
"created_at" datetime NOT NULL DEFAULT (datetime('now')),
|
|
19
|
+
"last_updated_at" datetime NOT NULL DEFAULT (datetime('now')),
|
|
20
|
+
CONSTRAINT "UQ_PresentationDefinitionItem_definition_id_version" UNIQUE ("definition_id", "version")
|
|
21
|
+
)
|
|
22
|
+
`)
|
|
23
|
+
|
|
24
|
+
// Copy data from old table
|
|
25
|
+
await queryRunner.query(`
|
|
26
|
+
INSERT INTO "temporary_PresentationDefinitionItem"(
|
|
27
|
+
"id", "definition_id", "version", "tenant_id", "purpose", "name",
|
|
28
|
+
"definition_payload", "dcql_payload", "created_at", "last_updated_at"
|
|
29
|
+
)
|
|
30
|
+
SELECT
|
|
31
|
+
"id", "definition_id", "version", "tenant_id", "purpose", "name",
|
|
32
|
+
"definition_payload", "dcql_payload", "created_at", "last_updated_at"
|
|
33
|
+
FROM "PresentationDefinitionItem"
|
|
34
|
+
`)
|
|
35
|
+
|
|
36
|
+
// Drop old table and rename
|
|
37
|
+
await queryRunner.query(`DROP TABLE "PresentationDefinitionItem"`)
|
|
38
|
+
await queryRunner.query(`ALTER TABLE "temporary_PresentationDefinitionItem" RENAME TO "PresentationDefinitionItem"`)
|
|
39
|
+
|
|
40
|
+
// Recreate index
|
|
41
|
+
await queryRunner.query(`CREATE INDEX "IDX_PresentationDefinitionItem_version" ON "PresentationDefinitionItem" ("version")`)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
45
|
+
// Revert to original schema (definition_payload NOT NULL, dcql_payload nullable)
|
|
46
|
+
await queryRunner.query(`
|
|
47
|
+
CREATE TABLE "temporary_PresentationDefinitionItem" (
|
|
48
|
+
"id" varchar PRIMARY KEY NOT NULL,
|
|
49
|
+
"definition_id" varchar(255) NOT NULL,
|
|
50
|
+
"version" varchar(255) NOT NULL,
|
|
51
|
+
"tenant_id" varchar(255),
|
|
52
|
+
"purpose" varchar(255),
|
|
53
|
+
"name" varchar(255),
|
|
54
|
+
"definition_payload" text NOT NULL,
|
|
55
|
+
"dcql_payload" text,
|
|
56
|
+
"created_at" datetime NOT NULL DEFAULT (datetime('now')),
|
|
57
|
+
"last_updated_at" datetime NOT NULL DEFAULT (datetime('now')),
|
|
58
|
+
CONSTRAINT "UQ_PresentationDefinitionItem_definition_id_version" UNIQUE ("definition_id", "version")
|
|
59
|
+
)
|
|
60
|
+
`)
|
|
61
|
+
|
|
62
|
+
await queryRunner.query(`
|
|
63
|
+
INSERT INTO "temporary_PresentationDefinitionItem"(
|
|
64
|
+
"id", "definition_id", "version", "tenant_id", "purpose", "name",
|
|
65
|
+
"definition_payload", "dcql_payload", "created_at", "last_updated_at"
|
|
66
|
+
)
|
|
67
|
+
SELECT
|
|
68
|
+
"id", "definition_id", "version", "tenant_id", "purpose", "name",
|
|
69
|
+
"definition_payload", "dcql_payload", "created_at", "last_updated_at"
|
|
70
|
+
FROM "PresentationDefinitionItem"
|
|
71
|
+
`)
|
|
72
|
+
|
|
73
|
+
await queryRunner.query(`DROP TABLE "PresentationDefinitionItem"`)
|
|
74
|
+
await queryRunner.query(`ALTER TABLE "temporary_PresentationDefinitionItem" RENAME TO "PresentationDefinitionItem"`)
|
|
75
|
+
await queryRunner.query(`CREATE INDEX "IDX_PresentationDefinitionItem_version" ON "PresentationDefinitionItem" ("version")`)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -106,7 +106,12 @@ export class PDStore extends AbstractPDStore {
|
|
|
106
106
|
updatedEntity.version = item.version
|
|
107
107
|
updatedEntity.name = item.name
|
|
108
108
|
updatedEntity.purpose = item.purpose
|
|
109
|
-
|
|
109
|
+
if (item.definitionPayload) {
|
|
110
|
+
updatedEntity.definitionPayload = JSON.stringify(item.definitionPayload!)
|
|
111
|
+
}
|
|
112
|
+
if (item.dcqlPayload) {
|
|
113
|
+
updatedEntity.dcqlPayload = JSON.stringify(item.dcqlPayload!.dcqlQuery)
|
|
114
|
+
}
|
|
110
115
|
|
|
111
116
|
debug('Updating presentation definition entity', updatedEntity)
|
|
112
117
|
const updateResult: PresentationDefinitionItemEntity = await pdRepository.save(updatedEntity, {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IPresentationDefinition } from '@sphereon/pex'
|
|
2
|
-
import {
|
|
2
|
+
import { DcqlQueryPayload } from '@sphereon/ssi-types'
|
|
3
3
|
|
|
4
4
|
export type PresentationDefinitionItem = {
|
|
5
5
|
id: string
|
|
@@ -8,8 +8,8 @@ export type PresentationDefinitionItem = {
|
|
|
8
8
|
version: string
|
|
9
9
|
name?: string
|
|
10
10
|
purpose?: string
|
|
11
|
-
definitionPayload
|
|
12
|
-
dcqlPayload?:
|
|
11
|
+
definitionPayload?: IPresentationDefinition
|
|
12
|
+
dcqlPayload?: DcqlQueryPayload
|
|
13
13
|
createdAt: Date
|
|
14
14
|
lastUpdatedAt: Date
|
|
15
15
|
}
|