@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sphereon/ssi-sdk.data-store",
3
- "version": "0.34.1-feature.SSISDK.45.94+24a0078a",
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.45.94+24a0078a",
32
- "@sphereon/ssi-sdk-ext.identifier-resolution": "0.34.1-feature.SSISDK.45.94+24a0078a",
33
- "@sphereon/ssi-sdk.agent-config": "0.34.1-feature.SSISDK.45.94+24a0078a",
34
- "@sphereon/ssi-sdk.core": "0.34.1-feature.SSISDK.45.94+24a0078a",
35
- "@sphereon/ssi-types": "0.34.1-feature.SSISDK.45.94+24a0078a",
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.2.19",
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": "24a0078a739502cd84e93cc2d4c3938c8854087a"
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 { CredentialRole, DataStoreDigitalCredentialEntities } from '../index'
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 { IVerifiablePresentation } from '@sphereon/ssi-types'
2
+ import { defaultHasher } from '@sphereon/ssi-sdk.core'
3
+ import { CredentialRole, IVerifiablePresentation } from '@sphereon/ssi-types'
3
4
  import { DataSource } from 'typeorm'
4
- import { DataStoreDigitalCredentialMigrations } from '../migrations'
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 = 'definition1'
33
+ entity.definitionId = 'ajax-club'
32
34
  entity.version = '1.0'
33
- entity.definitionPayload = JSON.stringify({ id: 'definition1', input_descriptors: [] })
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('credential1')
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 = 'definition1'
55
+ entity.definitionId = 'ajax-club'
65
56
  entity.version = '1.0'
66
- entity.definitionPayload = JSON.stringify({ id: 'definition1', input_descriptors: [] })
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: 'credential2',
65
+ id: 'updated-clubcard',
89
66
  format: 'jwt_vc',
90
67
  claims: [
91
68
  {
92
- namespace: 'test',
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('credential2')
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: false, unique: false }) // TODO should this become nullable now we have dcqlPayload?
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
 
@@ -1,5 +1,6 @@
1
1
  import Debug from 'debug'
2
2
  import { DatabaseType, MigrationInterface, QueryRunner } from 'typeorm'
3
+
3
4
  import {
4
5
  AddBitstringStatusListEnumPG1741895823000,
5
6
  CreateBitstringStatusListPG1741895823000,
@@ -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 = [CreatePresentationDefinitions1716533767523]
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
- updatedEntity.definitionPayload = JSON.stringify(item.definitionPayload!)
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 { DcqlQueryREST } from '@sphereon/ssi-types'
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: IPresentationDefinition
12
- dcqlPayload?: DcqlQueryREST
11
+ definitionPayload?: IPresentationDefinition
12
+ dcqlPayload?: DcqlQueryPayload
13
13
  createdAt: Date
14
14
  lastUpdatedAt: Date
15
15
  }