@sphereon/ssi-sdk.data-store 0.30.1-unstable.4 → 0.30.1
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 +201 -201
- package/README.md +77 -77
- package/dist/contact/ContactStore.d.ts.map +1 -1
- package/dist/digitalCredential/DigitalCredentialStore.d.ts.map +1 -1
- package/dist/eventLogger/EventLoggerStore.d.ts.map +1 -1
- package/dist/issuanceBranding/IssuanceBrandingStore.d.ts.map +1 -1
- package/dist/migrations/internal-migrations-ormconfig.d.ts.map +1 -1
- package/dist/migrations/postgres/1708525189001-CreateDigitalCredential.js +33 -33
- package/dist/migrations/postgres/1708797018115-CreateMachineStateStore.js +16 -16
- package/dist/migrations/postgres/1715761125001-CreateContacts.js +33 -33
- package/dist/migrations/postgres/1716475165345-CreatePresentationDefinitions.js +12 -12
- package/dist/migrations/sqlite/1708525189002-CreateDigitalCredential.js +32 -32
- package/dist/migrations/sqlite/1708796002272-CreateMachineStateStore.js +15 -15
- package/dist/migrations/sqlite/1710438363002-CreateContacts.js +13 -13
- package/dist/migrations/sqlite/1715761125002-CreateContacts.js +32 -32
- package/dist/migrations/sqlite/1716475165344-CreatePresentationDefinitions.js +9 -9
- package/dist/presentationDefinition/PDStore.d.ts.map +1 -1
- package/dist/utils/SortingUtils.d.ts.map +1 -1
- package/dist/utils/contact/MappingUtils.d.ts.map +1 -1
- package/dist/utils/digitalCredential/MappingUtils.d.ts.map +1 -1
- package/dist/utils/digitalCredential/MappingUtils.js +4 -4
- package/dist/utils/digitalCredential/MappingUtils.js.map +1 -1
- package/dist/utils/presentationDefinition/MappingUtils.js +2 -2
- package/dist/utils/presentationDefinition/MappingUtils.js.map +1 -1
- package/package.json +8 -8
- package/src/__tests__/contact.entities.test.ts +2642 -2642
- package/src/__tests__/contact.store.test.ts +2649 -2649
- package/src/__tests__/digitalCredential.entities.test.ts +274 -274
- package/src/__tests__/digitalCredential.store.test.ts +330 -330
- package/src/__tests__/eventLogger.entities.test.ts +76 -76
- package/src/__tests__/eventLogger.store.test.ts +130 -130
- package/src/__tests__/issuanceBranding.entities.test.ts +846 -846
- package/src/__tests__/issuanceBranding.store.test.ts +1886 -1886
- package/src/__tests__/machineState.entities.test.ts +53 -53
- package/src/__tests__/machineState.store.test.ts +176 -176
- package/src/__tests__/pd-manager.entities.test.ts +73 -73
- package/src/__tests__/pd-manager.store.test.ts +193 -193
- package/src/contact/AbstractContactStore.ts +71 -71
- package/src/contact/ContactStore.ts +768 -768
- package/src/digitalCredential/AbstractDigitalCredentialStore.ts +21 -21
- package/src/digitalCredential/DigitalCredentialStore.ts +189 -189
- package/src/entities/contact/BaseContactEntity.ts +51 -51
- package/src/entities/contact/ConnectionEntity.ts +35 -35
- package/src/entities/contact/ContactMetadataItemEntity.ts +51 -51
- package/src/entities/contact/CorrelationIdentifierEntity.ts +43 -43
- package/src/entities/contact/DidAuthConfigEntity.ts +20 -20
- package/src/entities/contact/ElectronicAddressEntity.ts +70 -70
- package/src/entities/contact/IdentityEntity.ts +107 -107
- package/src/entities/contact/IdentityMetadataItemEntity.ts +48 -48
- package/src/entities/contact/NaturalPersonEntity.ts +44 -44
- package/src/entities/contact/OpenIdConfigEntity.ts +32 -32
- package/src/entities/contact/OrganizationEntity.ts +35 -35
- package/src/entities/contact/PartyEntity.ts +117 -117
- package/src/entities/contact/PartyRelationshipEntity.ts +68 -68
- package/src/entities/contact/PartyTypeEntity.ts +63 -63
- package/src/entities/contact/PhysicalAddressEntity.ts +95 -95
- package/src/entities/digitalCredential/DigitalCredentialEntity.ts +98 -98
- package/src/entities/eventLogger/AuditEventEntity.ts +92 -92
- package/src/entities/issuanceBranding/BackgroundAttributesEntity.ts +42 -42
- package/src/entities/issuanceBranding/BaseLocaleBrandingEntity.ts +87 -87
- package/src/entities/issuanceBranding/CredentialBrandingEntity.ts +79 -79
- package/src/entities/issuanceBranding/CredentialLocaleBrandingEntity.ts +33 -33
- package/src/entities/issuanceBranding/ImageAttributesEntity.ts +57 -57
- package/src/entities/issuanceBranding/ImageDimensionsEntity.ts +22 -22
- package/src/entities/issuanceBranding/IssuerBrandingEntity.ts +73 -73
- package/src/entities/issuanceBranding/IssuerLocaleBrandingEntity.ts +33 -33
- package/src/entities/issuanceBranding/TextAttributesEntity.ts +31 -31
- package/src/entities/machineState/MachineStateInfoEntity.ts +59 -59
- package/src/entities/presentationDefinition/PresentationDefinitionItemEntity.ts +44 -44
- package/src/entities/statusList2021/StatusList2021Entity.ts +96 -96
- package/src/entities/statusList2021/StatusList2021EntryEntity.ts +29 -29
- package/src/eventLogger/AbstractEventLoggerStore.ts +7 -7
- package/src/eventLogger/EventLoggerStore.ts +62 -62
- package/src/index.ts +160 -160
- package/src/issuanceBranding/IssuanceBrandingStore.ts +559 -559
- package/src/machineState/IAbstractMachineStateStore.ts +65 -65
- package/src/machineState/MachineStateStore.ts +149 -149
- package/src/migrations/generic/1-CreateContacts.ts +66 -66
- package/src/migrations/generic/10-CreatePresentationDefinitions.ts +66 -66
- package/src/migrations/generic/2-CreateIssuanceBranding.ts +64 -64
- package/src/migrations/generic/3-CreateContacts.ts +66 -66
- package/src/migrations/generic/4-CreateStatusList.ts +54 -54
- package/src/migrations/generic/5-CreateAuditEvents.ts +66 -66
- package/src/migrations/generic/6-CreateDigitalCredential.ts +66 -66
- package/src/migrations/generic/7-CreateMachineStateStore.ts +66 -66
- package/src/migrations/generic/8-CreateContacts.ts +66 -66
- package/src/migrations/generic/9-CreateContacts.ts +66 -66
- package/src/migrations/generic/index.ts +43 -43
- package/src/migrations/index.ts +10 -10
- package/src/migrations/postgres/1659463079428-CreateContacts.ts +63 -63
- package/src/migrations/postgres/1685628974232-CreateIssuanceBranding.ts +85 -85
- package/src/migrations/postgres/1690925872592-CreateContacts.ts +158 -158
- package/src/migrations/postgres/1693866470001-CreateStatusList.ts +24 -24
- package/src/migrations/postgres/1701634812183-CreateAuditEvents.ts +33 -33
- package/src/migrations/postgres/1708525189001-CreateDigitalCredential.ts +61 -61
- package/src/migrations/postgres/1708797018115-CreateMachineStateStore.ts +29 -29
- package/src/migrations/postgres/1710438363001-CreateContacts.ts +63 -63
- package/src/migrations/postgres/1715761125001-CreateContacts.ts +60 -60
- package/src/migrations/postgres/1716475165345-CreatePresentationDefinitions.ts +25 -25
- package/src/migrations/sqlite/1659463069549-CreateContacts.ts +110 -110
- package/src/migrations/sqlite/1685628973231-CreateIssuanceBranding.ts +119 -119
- package/src/migrations/sqlite/1690925872693-CreateContacts.ts +228 -228
- package/src/migrations/sqlite/1693866470000-CreateStatusList.ts +24 -24
- package/src/migrations/sqlite/1701634819487-CreateAuditEvents.ts +15 -15
- package/src/migrations/sqlite/1708525189002-CreateDigitalCredential.ts +46 -46
- package/src/migrations/sqlite/1708796002272-CreateMachineStateStore.ts +28 -28
- package/src/migrations/sqlite/1710438363002-CreateContacts.ts +83 -83
- package/src/migrations/sqlite/1715761125002-CreateContacts.ts +59 -59
- package/src/migrations/sqlite/1716475165344-CreatePresentationDefinitions.ts +24 -24
- package/src/presentationDefinition/AbstractPDStore.ts +20 -20
- package/src/presentationDefinition/PDStore.ts +185 -185
- package/src/statusList/IStatusListStore.ts +44 -44
- package/src/statusList/StatusListStore.ts +236 -236
- package/src/types/contact/IAbstractContactStore.ts +161 -161
- package/src/types/contact/contact.ts +295 -295
- package/src/types/digitalCredential/IAbstractDigitalCredentialStore.ts +42 -42
- package/src/types/digitalCredential/digitalCredential.ts +102 -102
- package/src/types/eventLogger/IAbstractEventLoggerStore.ts +12 -12
- package/src/types/eventLogger/eventLogger.ts +3 -3
- package/src/types/index.ts +14 -14
- package/src/types/machineState/IAbstractMachineStateStore.ts +68 -68
- package/src/types/presentationDefinition/IAbstractPDStore.ts +25 -25
- package/src/types/presentationDefinition/presentationDefinition.ts +17 -17
- package/src/utils/SortingUtils.ts +16 -16
- package/src/utils/contact/MappingUtils.ts +506 -506
- package/src/utils/digitalCredential/MappingUtils.ts +160 -160
- package/src/utils/hasher.ts +19 -19
- package/src/utils/presentationDefinition/MappingUtils.ts +52 -52
- package/dist/entities/contact/IMetadataEntity.d.ts +0 -8
- package/dist/entities/contact/IMetadataEntity.d.ts.map +0 -1
- package/dist/entities/contact/IMetadataEntity.js +0 -2
- package/dist/entities/contact/IMetadataEntity.js.map +0 -1
- package/dist/migrations/generic/8-CreatePresentationDefinitions.d.ts +0 -7
- package/dist/migrations/generic/8-CreatePresentationDefinitions.d.ts.map +0 -1
- package/dist/migrations/generic/8-CreatePresentationDefinitions.js +0 -78
- package/dist/migrations/generic/8-CreatePresentationDefinitions.js.map +0 -1
|
@@ -1,236 +1,236 @@
|
|
|
1
|
-
import { OrPromise } from '@sphereon/ssi-types'
|
|
2
|
-
import Debug from 'debug'
|
|
3
|
-
import { DataSource, In, Repository } from 'typeorm'
|
|
4
|
-
import { StatusListEntity } from '../entities/statusList2021/StatusList2021Entity'
|
|
5
|
-
import { StatusListEntryEntity } from '../entities/statusList2021/StatusList2021EntryEntity'
|
|
6
|
-
import {
|
|
7
|
-
IAddStatusListArgs,
|
|
8
|
-
IAddStatusListEntryArgs,
|
|
9
|
-
IGetStatusListArgs,
|
|
10
|
-
IGetStatusListEntriesArgs,
|
|
11
|
-
IGetStatusListEntryByCredentialIdArgs,
|
|
12
|
-
IGetStatusListEntryByIndexArgs,
|
|
13
|
-
IGetStatusListsArgs,
|
|
14
|
-
IRemoveStatusListArgs,
|
|
15
|
-
IStatusListEntryAvailableArgs,
|
|
16
|
-
IUpdateStatusListIndexArgs,
|
|
17
|
-
IStatusListEntity,
|
|
18
|
-
IStatusListEntryEntity,
|
|
19
|
-
} from '../types'
|
|
20
|
-
import { IStatusListStore } from './IStatusListStore'
|
|
21
|
-
|
|
22
|
-
const debug = Debug('sphereon:ssi-sdk:data-store:status-list')
|
|
23
|
-
|
|
24
|
-
export class StatusListStore implements IStatusListStore {
|
|
25
|
-
private readonly _dbConnection: OrPromise<DataSource>
|
|
26
|
-
|
|
27
|
-
constructor(dbConnection: OrPromise<DataSource>) {
|
|
28
|
-
this._dbConnection = dbConnection
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Gets the available status list indices from the provided indices. Meaning it will filter out any index that is already known.
|
|
33
|
-
*
|
|
34
|
-
* The idea is that the caller provides a set of random status list indices. We can relatively easy check against the DB in an optimized way.
|
|
35
|
-
* If the status list is large it is probably best to also provide at least a good number of indices. So something like 10 or 20 values.
|
|
36
|
-
* Callers are also expected to call this function multiple times if it does not yield results
|
|
37
|
-
*
|
|
38
|
-
* @param args
|
|
39
|
-
*/
|
|
40
|
-
async availableStatusListEntries(args: IStatusListEntryAvailableArgs): Promise<number[]> {
|
|
41
|
-
const statusListIndex = Array.isArray(args.statusListIndex) ? args.statusListIndex : [args.statusListIndex]
|
|
42
|
-
const statusList = await this.getStatusList({ ...args, id: args.statusListId })
|
|
43
|
-
const repo = await this.getStatusListEntryRepo()
|
|
44
|
-
const results = (
|
|
45
|
-
await repo.find({
|
|
46
|
-
where: {
|
|
47
|
-
statusList,
|
|
48
|
-
statusListIndex: In(statusListIndex),
|
|
49
|
-
},
|
|
50
|
-
})
|
|
51
|
-
).map((index) => index.statusListIndex)
|
|
52
|
-
return statusListIndex.filter((index) => !results.includes(index))
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async addStatusListEntry(args: IAddStatusListEntryArgs): Promise<IStatusListEntryEntity> {
|
|
56
|
-
return (await this.getStatusListEntryRepo()).save(args)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async updateStatusListEntry(args: IAddStatusListEntryArgs): Promise<IStatusListEntryEntity> {
|
|
60
|
-
const statusListId = typeof args.statusList === 'string' ? args.statusList : args.statusList.id
|
|
61
|
-
const result = await this.getStatusListEntryByIndex({ ...args, statusListId, errorOnNotFound: false })
|
|
62
|
-
const updatedEntry: Partial<IStatusListEntryEntity> = {
|
|
63
|
-
value: args.value,
|
|
64
|
-
correlationId: args.correlationId,
|
|
65
|
-
credentialHash: args.credentialHash,
|
|
66
|
-
credentialId: args.credentialId,
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const updateResult = await (
|
|
70
|
-
await this.getStatusListEntryRepo()
|
|
71
|
-
).upsert(
|
|
72
|
-
{ ...(result ?? { statusList: args.statusList, statusListIndex: args.statusListIndex }), ...updatedEntry },
|
|
73
|
-
{ conflictPaths: ['statusList', 'statusListIndex'] },
|
|
74
|
-
)
|
|
75
|
-
console.log(updateResult)
|
|
76
|
-
return (await this.getStatusListEntryByIndex({ ...args, statusListId, errorOnNotFound: true })) as IStatusListEntryEntity
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async getStatusListEntryByIndex(args: IGetStatusListEntryByIndexArgs): Promise<StatusListEntryEntity | undefined> {
|
|
80
|
-
if (!args.statusListId && !args.correlationId) {
|
|
81
|
-
throw Error(`Cannot get statusList entry if not either a statusList id or correlationId is provided`)
|
|
82
|
-
}
|
|
83
|
-
const result = await (
|
|
84
|
-
await this.getStatusListEntryRepo()
|
|
85
|
-
).findOne({
|
|
86
|
-
where: {
|
|
87
|
-
...(args.statusListId && { statusList: args.statusListId }),
|
|
88
|
-
...(args.correlationId && { correlationId: args.correlationId }),
|
|
89
|
-
statusListIndex: args.statusListIndex,
|
|
90
|
-
},
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
if (!result && args.errorOnNotFound) {
|
|
94
|
-
throw Error(`Could not find status list index ${args.statusListIndex} for status list id ${args.statusListId}`)
|
|
95
|
-
}
|
|
96
|
-
return result ?? undefined
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
async removeStatusListEntryByIndex(args: IGetStatusListEntryByIndexArgs): Promise<boolean> {
|
|
100
|
-
let error = false
|
|
101
|
-
try {
|
|
102
|
-
await this.getStatusListEntryByIndex(args) // only used to check it exists
|
|
103
|
-
} catch (error) {
|
|
104
|
-
error = true
|
|
105
|
-
}
|
|
106
|
-
if (error) {
|
|
107
|
-
console.log(`Could not delete statusList ${args.statusListId} entry by index ${args.statusListIndex}`)
|
|
108
|
-
} else {
|
|
109
|
-
const result = await (
|
|
110
|
-
await this.getStatusListEntryRepo()
|
|
111
|
-
).delete({
|
|
112
|
-
...(args.statusListId && { statusList: args.statusListId }),
|
|
113
|
-
...(args.correlationId && { correlationId: args.correlationId }),
|
|
114
|
-
statusListIndex: args.statusListIndex,
|
|
115
|
-
})
|
|
116
|
-
error = !result.affected || result.affected !== 1
|
|
117
|
-
}
|
|
118
|
-
return !error
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
async getStatusListEntryByCredentialId(args: IGetStatusListEntryByCredentialIdArgs): Promise<StatusListEntryEntity | undefined> {
|
|
122
|
-
const credentialId = args.credentialId
|
|
123
|
-
if (!credentialId) {
|
|
124
|
-
throw Error('Can only get a credential by credentialId when a credentialId is supplied')
|
|
125
|
-
}
|
|
126
|
-
const statusList = await this.getStatusList({ id: args.statusListId, correlationId: args.statusListCorrelationId })
|
|
127
|
-
const where = {
|
|
128
|
-
statusList: statusList.id,
|
|
129
|
-
...(args.entryCorrelationId && { correlationId: args.entryCorrelationId }),
|
|
130
|
-
credentialId,
|
|
131
|
-
}
|
|
132
|
-
console.log(`Entries: ${JSON.stringify(await (await this.getStatusListEntryRepo()).find(), null, 2)}`)
|
|
133
|
-
const result = await (await this.getStatusListEntryRepo()).findOne({ where })
|
|
134
|
-
|
|
135
|
-
if (!result && args.errorOnNotFound) {
|
|
136
|
-
throw Error(`Could not find status list credential id ${credentialId} for status list id ${statusList.id}`)
|
|
137
|
-
}
|
|
138
|
-
return result ?? undefined
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
async removeStatusListEntryByCredentialId(args: IGetStatusListEntryByCredentialIdArgs): Promise<boolean> {
|
|
142
|
-
let error = false
|
|
143
|
-
try {
|
|
144
|
-
await this.getStatusListEntryByCredentialId(args) // only used to check it exists
|
|
145
|
-
} catch (error) {
|
|
146
|
-
error = true
|
|
147
|
-
}
|
|
148
|
-
if (!error) {
|
|
149
|
-
const result = await (
|
|
150
|
-
await this.getStatusListEntryRepo()
|
|
151
|
-
).delete({
|
|
152
|
-
...(args.statusListId && { statusList: args.statusListId }),
|
|
153
|
-
...(args.entryCorrelationId && { correlationId: args.entryCorrelationId }),
|
|
154
|
-
credentialId: args.credentialId,
|
|
155
|
-
})
|
|
156
|
-
error = !result.affected || result.affected !== 1
|
|
157
|
-
}
|
|
158
|
-
return !error
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
async getStatusListEntries(args: IGetStatusListEntriesArgs): Promise<StatusListEntryEntity[]> {
|
|
162
|
-
return (await this.getStatusListEntryRepo()).find({ where: { ...args?.filter, statusList: args.statusListId } })
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
async getStatusList(args: IGetStatusListArgs): Promise<IStatusListEntity> {
|
|
166
|
-
if (!args.id && !args.correlationId) {
|
|
167
|
-
throw Error(`At least and 'id' or 'correlationId' needs to be provided to lookup a status list`)
|
|
168
|
-
}
|
|
169
|
-
const where = []
|
|
170
|
-
if (args.id) {
|
|
171
|
-
where.push({ id: args.id })
|
|
172
|
-
} else if (args.correlationId) {
|
|
173
|
-
where.push({ correlationId: args.correlationId })
|
|
174
|
-
}
|
|
175
|
-
const result = await (await this.getStatusListRepo()).findOne({where})
|
|
176
|
-
if (!result) {
|
|
177
|
-
throw Error(`No status list found for id ${args.id}`)
|
|
178
|
-
}
|
|
179
|
-
return result
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
async getStatusLists(args: IGetStatusListsArgs): Promise<Array<IStatusListEntity>> {
|
|
183
|
-
const result = await (
|
|
184
|
-
await this.getStatusListRepo()
|
|
185
|
-
).find({
|
|
186
|
-
where: args.filter,
|
|
187
|
-
})
|
|
188
|
-
|
|
189
|
-
if (!result) {
|
|
190
|
-
return []
|
|
191
|
-
}
|
|
192
|
-
return result
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
async addStatusList(args: IAddStatusListArgs): Promise<IStatusListEntity> {
|
|
196
|
-
const { id, correlationId } = args
|
|
197
|
-
|
|
198
|
-
const result = await (
|
|
199
|
-
await this.getStatusListRepo()
|
|
200
|
-
).findOne({
|
|
201
|
-
where: [{ id }, { correlationId }],
|
|
202
|
-
})
|
|
203
|
-
if (result) {
|
|
204
|
-
throw Error(`Status list for id ${id}, correlationId ${correlationId} already exists`)
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
debug('Adding status list ', id)
|
|
208
|
-
const createdResult = await (await this.getStatusListRepo()).save(args)
|
|
209
|
-
|
|
210
|
-
return createdResult
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
async updateStatusList(args: IUpdateStatusListIndexArgs): Promise<IStatusListEntity> {
|
|
214
|
-
const result = await this.getStatusList(args)
|
|
215
|
-
debug('Updating status list', result)
|
|
216
|
-
const updatedResult = await (await this.getStatusListRepo()).save(args, { transaction: true })
|
|
217
|
-
return updatedResult
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
async removeStatusList(args: IRemoveStatusListArgs): Promise<void> {
|
|
221
|
-
const result = await this.getStatusList(args)
|
|
222
|
-
await (await this.getStatusListRepo()).delete(result)
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
private async getDS(): Promise<DataSource> {
|
|
226
|
-
return this._dbConnection
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
async getStatusListRepo(): Promise<Repository<StatusListEntity>> {
|
|
230
|
-
return (await this.getDS()).getRepository(StatusListEntity)
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
async getStatusListEntryRepo(): Promise<Repository<StatusListEntryEntity>> {
|
|
234
|
-
return (await this.getDS()).getRepository(StatusListEntryEntity)
|
|
235
|
-
}
|
|
236
|
-
}
|
|
1
|
+
import { OrPromise } from '@sphereon/ssi-types'
|
|
2
|
+
import Debug from 'debug'
|
|
3
|
+
import { DataSource, In, Repository } from 'typeorm'
|
|
4
|
+
import { StatusListEntity } from '../entities/statusList2021/StatusList2021Entity'
|
|
5
|
+
import { StatusListEntryEntity } from '../entities/statusList2021/StatusList2021EntryEntity'
|
|
6
|
+
import {
|
|
7
|
+
IAddStatusListArgs,
|
|
8
|
+
IAddStatusListEntryArgs,
|
|
9
|
+
IGetStatusListArgs,
|
|
10
|
+
IGetStatusListEntriesArgs,
|
|
11
|
+
IGetStatusListEntryByCredentialIdArgs,
|
|
12
|
+
IGetStatusListEntryByIndexArgs,
|
|
13
|
+
IGetStatusListsArgs,
|
|
14
|
+
IRemoveStatusListArgs,
|
|
15
|
+
IStatusListEntryAvailableArgs,
|
|
16
|
+
IUpdateStatusListIndexArgs,
|
|
17
|
+
IStatusListEntity,
|
|
18
|
+
IStatusListEntryEntity,
|
|
19
|
+
} from '../types'
|
|
20
|
+
import { IStatusListStore } from './IStatusListStore'
|
|
21
|
+
|
|
22
|
+
const debug = Debug('sphereon:ssi-sdk:data-store:status-list')
|
|
23
|
+
|
|
24
|
+
export class StatusListStore implements IStatusListStore {
|
|
25
|
+
private readonly _dbConnection: OrPromise<DataSource>
|
|
26
|
+
|
|
27
|
+
constructor(dbConnection: OrPromise<DataSource>) {
|
|
28
|
+
this._dbConnection = dbConnection
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Gets the available status list indices from the provided indices. Meaning it will filter out any index that is already known.
|
|
33
|
+
*
|
|
34
|
+
* The idea is that the caller provides a set of random status list indices. We can relatively easy check against the DB in an optimized way.
|
|
35
|
+
* If the status list is large it is probably best to also provide at least a good number of indices. So something like 10 or 20 values.
|
|
36
|
+
* Callers are also expected to call this function multiple times if it does not yield results
|
|
37
|
+
*
|
|
38
|
+
* @param args
|
|
39
|
+
*/
|
|
40
|
+
async availableStatusListEntries(args: IStatusListEntryAvailableArgs): Promise<number[]> {
|
|
41
|
+
const statusListIndex = Array.isArray(args.statusListIndex) ? args.statusListIndex : [args.statusListIndex]
|
|
42
|
+
const statusList = await this.getStatusList({ ...args, id: args.statusListId })
|
|
43
|
+
const repo = await this.getStatusListEntryRepo()
|
|
44
|
+
const results = (
|
|
45
|
+
await repo.find({
|
|
46
|
+
where: {
|
|
47
|
+
statusList,
|
|
48
|
+
statusListIndex: In(statusListIndex),
|
|
49
|
+
},
|
|
50
|
+
})
|
|
51
|
+
).map((index) => index.statusListIndex)
|
|
52
|
+
return statusListIndex.filter((index) => !results.includes(index))
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async addStatusListEntry(args: IAddStatusListEntryArgs): Promise<IStatusListEntryEntity> {
|
|
56
|
+
return (await this.getStatusListEntryRepo()).save(args)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async updateStatusListEntry(args: IAddStatusListEntryArgs): Promise<IStatusListEntryEntity> {
|
|
60
|
+
const statusListId = typeof args.statusList === 'string' ? args.statusList : args.statusList.id
|
|
61
|
+
const result = await this.getStatusListEntryByIndex({ ...args, statusListId, errorOnNotFound: false })
|
|
62
|
+
const updatedEntry: Partial<IStatusListEntryEntity> = {
|
|
63
|
+
value: args.value,
|
|
64
|
+
correlationId: args.correlationId,
|
|
65
|
+
credentialHash: args.credentialHash,
|
|
66
|
+
credentialId: args.credentialId,
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const updateResult = await (
|
|
70
|
+
await this.getStatusListEntryRepo()
|
|
71
|
+
).upsert(
|
|
72
|
+
{ ...(result ?? { statusList: args.statusList, statusListIndex: args.statusListIndex }), ...updatedEntry },
|
|
73
|
+
{ conflictPaths: ['statusList', 'statusListIndex'] },
|
|
74
|
+
)
|
|
75
|
+
console.log(updateResult)
|
|
76
|
+
return (await this.getStatusListEntryByIndex({ ...args, statusListId, errorOnNotFound: true })) as IStatusListEntryEntity
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async getStatusListEntryByIndex(args: IGetStatusListEntryByIndexArgs): Promise<StatusListEntryEntity | undefined> {
|
|
80
|
+
if (!args.statusListId && !args.correlationId) {
|
|
81
|
+
throw Error(`Cannot get statusList entry if not either a statusList id or correlationId is provided`)
|
|
82
|
+
}
|
|
83
|
+
const result = await (
|
|
84
|
+
await this.getStatusListEntryRepo()
|
|
85
|
+
).findOne({
|
|
86
|
+
where: {
|
|
87
|
+
...(args.statusListId && { statusList: args.statusListId }),
|
|
88
|
+
...(args.correlationId && { correlationId: args.correlationId }),
|
|
89
|
+
statusListIndex: args.statusListIndex,
|
|
90
|
+
},
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
if (!result && args.errorOnNotFound) {
|
|
94
|
+
throw Error(`Could not find status list index ${args.statusListIndex} for status list id ${args.statusListId}`)
|
|
95
|
+
}
|
|
96
|
+
return result ?? undefined
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async removeStatusListEntryByIndex(args: IGetStatusListEntryByIndexArgs): Promise<boolean> {
|
|
100
|
+
let error = false
|
|
101
|
+
try {
|
|
102
|
+
await this.getStatusListEntryByIndex(args) // only used to check it exists
|
|
103
|
+
} catch (error) {
|
|
104
|
+
error = true
|
|
105
|
+
}
|
|
106
|
+
if (error) {
|
|
107
|
+
console.log(`Could not delete statusList ${args.statusListId} entry by index ${args.statusListIndex}`)
|
|
108
|
+
} else {
|
|
109
|
+
const result = await (
|
|
110
|
+
await this.getStatusListEntryRepo()
|
|
111
|
+
).delete({
|
|
112
|
+
...(args.statusListId && { statusList: args.statusListId }),
|
|
113
|
+
...(args.correlationId && { correlationId: args.correlationId }),
|
|
114
|
+
statusListIndex: args.statusListIndex,
|
|
115
|
+
})
|
|
116
|
+
error = !result.affected || result.affected !== 1
|
|
117
|
+
}
|
|
118
|
+
return !error
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async getStatusListEntryByCredentialId(args: IGetStatusListEntryByCredentialIdArgs): Promise<StatusListEntryEntity | undefined> {
|
|
122
|
+
const credentialId = args.credentialId
|
|
123
|
+
if (!credentialId) {
|
|
124
|
+
throw Error('Can only get a credential by credentialId when a credentialId is supplied')
|
|
125
|
+
}
|
|
126
|
+
const statusList = await this.getStatusList({ id: args.statusListId, correlationId: args.statusListCorrelationId })
|
|
127
|
+
const where = {
|
|
128
|
+
statusList: statusList.id,
|
|
129
|
+
...(args.entryCorrelationId && { correlationId: args.entryCorrelationId }),
|
|
130
|
+
credentialId,
|
|
131
|
+
}
|
|
132
|
+
console.log(`Entries: ${JSON.stringify(await (await this.getStatusListEntryRepo()).find(), null, 2)}`)
|
|
133
|
+
const result = await (await this.getStatusListEntryRepo()).findOne({ where })
|
|
134
|
+
|
|
135
|
+
if (!result && args.errorOnNotFound) {
|
|
136
|
+
throw Error(`Could not find status list credential id ${credentialId} for status list id ${statusList.id}`)
|
|
137
|
+
}
|
|
138
|
+
return result ?? undefined
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async removeStatusListEntryByCredentialId(args: IGetStatusListEntryByCredentialIdArgs): Promise<boolean> {
|
|
142
|
+
let error = false
|
|
143
|
+
try {
|
|
144
|
+
await this.getStatusListEntryByCredentialId(args) // only used to check it exists
|
|
145
|
+
} catch (error) {
|
|
146
|
+
error = true
|
|
147
|
+
}
|
|
148
|
+
if (!error) {
|
|
149
|
+
const result = await (
|
|
150
|
+
await this.getStatusListEntryRepo()
|
|
151
|
+
).delete({
|
|
152
|
+
...(args.statusListId && { statusList: args.statusListId }),
|
|
153
|
+
...(args.entryCorrelationId && { correlationId: args.entryCorrelationId }),
|
|
154
|
+
credentialId: args.credentialId,
|
|
155
|
+
})
|
|
156
|
+
error = !result.affected || result.affected !== 1
|
|
157
|
+
}
|
|
158
|
+
return !error
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async getStatusListEntries(args: IGetStatusListEntriesArgs): Promise<StatusListEntryEntity[]> {
|
|
162
|
+
return (await this.getStatusListEntryRepo()).find({ where: { ...args?.filter, statusList: args.statusListId } })
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async getStatusList(args: IGetStatusListArgs): Promise<IStatusListEntity> {
|
|
166
|
+
if (!args.id && !args.correlationId) {
|
|
167
|
+
throw Error(`At least and 'id' or 'correlationId' needs to be provided to lookup a status list`)
|
|
168
|
+
}
|
|
169
|
+
const where = []
|
|
170
|
+
if (args.id) {
|
|
171
|
+
where.push({ id: args.id })
|
|
172
|
+
} else if (args.correlationId) {
|
|
173
|
+
where.push({ correlationId: args.correlationId })
|
|
174
|
+
}
|
|
175
|
+
const result = await (await this.getStatusListRepo()).findOne({where})
|
|
176
|
+
if (!result) {
|
|
177
|
+
throw Error(`No status list found for id ${args.id}`)
|
|
178
|
+
}
|
|
179
|
+
return result
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async getStatusLists(args: IGetStatusListsArgs): Promise<Array<IStatusListEntity>> {
|
|
183
|
+
const result = await (
|
|
184
|
+
await this.getStatusListRepo()
|
|
185
|
+
).find({
|
|
186
|
+
where: args.filter,
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
if (!result) {
|
|
190
|
+
return []
|
|
191
|
+
}
|
|
192
|
+
return result
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async addStatusList(args: IAddStatusListArgs): Promise<IStatusListEntity> {
|
|
196
|
+
const { id, correlationId } = args
|
|
197
|
+
|
|
198
|
+
const result = await (
|
|
199
|
+
await this.getStatusListRepo()
|
|
200
|
+
).findOne({
|
|
201
|
+
where: [{ id }, { correlationId }],
|
|
202
|
+
})
|
|
203
|
+
if (result) {
|
|
204
|
+
throw Error(`Status list for id ${id}, correlationId ${correlationId} already exists`)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
debug('Adding status list ', id)
|
|
208
|
+
const createdResult = await (await this.getStatusListRepo()).save(args)
|
|
209
|
+
|
|
210
|
+
return createdResult
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async updateStatusList(args: IUpdateStatusListIndexArgs): Promise<IStatusListEntity> {
|
|
214
|
+
const result = await this.getStatusList(args)
|
|
215
|
+
debug('Updating status list', result)
|
|
216
|
+
const updatedResult = await (await this.getStatusListRepo()).save(args, { transaction: true })
|
|
217
|
+
return updatedResult
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
async removeStatusList(args: IRemoveStatusListArgs): Promise<void> {
|
|
221
|
+
const result = await this.getStatusList(args)
|
|
222
|
+
await (await this.getStatusListRepo()).delete(result)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
private async getDS(): Promise<DataSource> {
|
|
226
|
+
return this._dbConnection
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async getStatusListRepo(): Promise<Repository<StatusListEntity>> {
|
|
230
|
+
return (await this.getDS()).getRepository(StatusListEntity)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async getStatusListEntryRepo(): Promise<Repository<StatusListEntryEntity>> {
|
|
234
|
+
return (await this.getDS()).getRepository(StatusListEntryEntity)
|
|
235
|
+
}
|
|
236
|
+
}
|