@credo-ts/drizzle-storage 0.6.0-pr-2324-20250708122332 → 0.6.0-pr-2324-20250708123651

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/cli-build/utils.js +4 -1
  2. package/cli-build/utils.js.map +1 -1
  3. package/package.json +15 -14
  4. package/src/DrizzleDatabase.ts +29 -0
  5. package/src/DrizzleRecord.ts +73 -0
  6. package/src/DrizzleStorageModule.ts +112 -0
  7. package/src/DrizzleStorageModuleConfig.ts +48 -0
  8. package/src/action-menu/action-menu/DrizzleDidcommActionMenuRecordAdapter.ts +46 -0
  9. package/src/action-menu/action-menu/index.ts +10 -0
  10. package/src/action-menu/action-menu/postgres.ts +31 -0
  11. package/src/action-menu/action-menu/sqlite.ts +34 -0
  12. package/src/action-menu/bundle.ts +18 -0
  13. package/src/action-menu/postgres.ts +1 -0
  14. package/src/action-menu/sqlite.ts +1 -0
  15. package/src/adapter/BaseDrizzleRecordAdapter.ts +319 -0
  16. package/src/adapter/__tests__/queryToDrizzlePostgres.test.ts +328 -0
  17. package/src/adapter/__tests__/queryToDrizzleSqlite.test.ts +324 -0
  18. package/src/adapter/index.ts +6 -0
  19. package/src/adapter/queryToDrizzlePostgres.ts +217 -0
  20. package/src/adapter/queryToDrizzleSqlite.ts +213 -0
  21. package/src/anoncreds/bundle.ts +34 -0
  22. package/src/anoncreds/credential/DrizzleAnonCredsCredentialRecordAdapter.ts +93 -0
  23. package/src/anoncreds/credential/index.ts +10 -0
  24. package/src/anoncreds/credential/postgres.ts +27 -0
  25. package/src/anoncreds/credential/sqlite.ts +27 -0
  26. package/src/anoncreds/credential-definition/DrizzleAnonCredsCredentialDefinitionRecordAdapter.ts +72 -0
  27. package/src/anoncreds/credential-definition/index.ts +10 -0
  28. package/src/anoncreds/credential-definition/postgres.ts +23 -0
  29. package/src/anoncreds/credential-definition/sqlite.ts +23 -0
  30. package/src/anoncreds/credential-definition-private/DrizzleAnonCredsCredentialDefinitionPrivateRecordAdapter.ts +48 -0
  31. package/src/anoncreds/credential-definition-private/index.ts +10 -0
  32. package/src/anoncreds/credential-definition-private/postgres.ts +14 -0
  33. package/src/anoncreds/credential-definition-private/sqlite.ts +14 -0
  34. package/src/anoncreds/key-correctness-proof/DrizzleAnonCredsKeyCorrectnessProofRecordAdapter.ts +46 -0
  35. package/src/anoncreds/key-correctness-proof/index.ts +10 -0
  36. package/src/anoncreds/key-correctness-proof/postgres.ts +13 -0
  37. package/src/anoncreds/key-correctness-proof/sqlite.ts +14 -0
  38. package/src/anoncreds/link-secret/DrizzleAnonCredsLinkSecretRecordAdapter.ts +45 -0
  39. package/src/anoncreds/link-secret/index.ts +10 -0
  40. package/src/anoncreds/link-secret/postgres.ts +18 -0
  41. package/src/anoncreds/link-secret/sqlite.ts +18 -0
  42. package/src/anoncreds/postgres.ts +8 -0
  43. package/src/anoncreds/revocation-registry-definition/DrizzleAnonCredsRevocationRegistryDefinitionRecordAdapter.ts +52 -0
  44. package/src/anoncreds/revocation-registry-definition/index.ts +10 -0
  45. package/src/anoncreds/revocation-registry-definition/postgres.ts +18 -0
  46. package/src/anoncreds/revocation-registry-definition/sqlite.ts +20 -0
  47. package/src/anoncreds/revocation-registry-definition-private/DrizzleAnonCredsRevocationRegistryDefinitionPrivateRecordAdapter.ts +53 -0
  48. package/src/anoncreds/revocation-registry-definition-private/index.ts +10 -0
  49. package/src/anoncreds/revocation-registry-definition-private/postgres.ts +22 -0
  50. package/src/anoncreds/revocation-registry-definition-private/sqlite.ts +18 -0
  51. package/src/anoncreds/schema/DrizzleAnonCredsSchemaRecordAdapter.ts +54 -0
  52. package/src/anoncreds/schema/__tests__/schema.test.ts +66 -0
  53. package/src/anoncreds/schema/index.ts +10 -0
  54. package/src/anoncreds/schema/postgres.ts +22 -0
  55. package/src/anoncreds/schema/sqlite.ts +22 -0
  56. package/src/anoncreds/sqlite.ts +8 -0
  57. package/src/applyReactNativeMigrations.ts +24 -0
  58. package/src/combineSchemas.ts +44 -0
  59. package/src/core/bundle.ts +33 -0
  60. package/src/core/context/index.ts +8 -0
  61. package/src/core/context/postgres.ts +5 -0
  62. package/src/core/context/sqlite.ts +5 -0
  63. package/src/core/did/DrizzleDidRecordAdapter.ts +71 -0
  64. package/src/core/did/index.ts +10 -0
  65. package/src/core/did/postgres.ts +28 -0
  66. package/src/core/did/sqlite.ts +26 -0
  67. package/src/core/genericRecord/DrizzleGenericRecordAdapter.ts +36 -0
  68. package/src/core/genericRecord/index.ts +10 -0
  69. package/src/core/genericRecord/postgres.ts +12 -0
  70. package/src/core/genericRecord/sqlite.ts +12 -0
  71. package/src/core/mdoc/DrizzleMdocRecordAdapter.ts +44 -0
  72. package/src/core/mdoc/index.ts +10 -0
  73. package/src/core/mdoc/postgres.ts +15 -0
  74. package/src/core/mdoc/sqlite.ts +15 -0
  75. package/src/core/postgres.ts +8 -0
  76. package/src/core/sdJwtVc/DrizzleSdJwtVcRecordAdapter.ts +46 -0
  77. package/src/core/sdJwtVc/index.ts +10 -0
  78. package/src/core/sdJwtVc/postgres.ts +17 -0
  79. package/src/core/sdJwtVc/sqlite.ts +17 -0
  80. package/src/core/singleContextLruCache/DrizzleSingleContextLruCacheRecordAdapter.ts +43 -0
  81. package/src/core/singleContextLruCache/index.ts +10 -0
  82. package/src/core/singleContextLruCache/postgres.ts +12 -0
  83. package/src/core/singleContextLruCache/sqlite.ts +13 -0
  84. package/src/core/sqlite.ts +8 -0
  85. package/src/core/storageVersion/DrizzleStorageVersionRecordAdapter.ts +36 -0
  86. package/src/core/storageVersion/index.ts +10 -0
  87. package/src/core/storageVersion/postgres.ts +13 -0
  88. package/src/core/storageVersion/sqlite.ts +13 -0
  89. package/src/core/w3cCredential/DrizzleW3cCredentialRecordAdapter.ts +95 -0
  90. package/src/core/w3cCredential/index.ts +10 -0
  91. package/src/core/w3cCredential/postgres.ts +31 -0
  92. package/src/core/w3cCredential/sqlite.ts +29 -0
  93. package/src/didcomm/basic-message/DrizzleDidcommBasicMessageRecordAdapter.ts +54 -0
  94. package/src/didcomm/basic-message/index.ts +10 -0
  95. package/src/didcomm/basic-message/postgres.ts +30 -0
  96. package/src/didcomm/basic-message/sqlite.ts +29 -0
  97. package/src/didcomm/bundle.ts +34 -0
  98. package/src/didcomm/connection/DrizzleDidcommConnectionRecordAdapter.ts +70 -0
  99. package/src/didcomm/connection/index.ts +10 -0
  100. package/src/didcomm/connection/postgres.ts +55 -0
  101. package/src/didcomm/connection/sqlite.ts +39 -0
  102. package/src/didcomm/credential-exchange/DrizzleDidcommCredentialExchangeRecordAdapter.ts +64 -0
  103. package/src/didcomm/credential-exchange/__tests__/credentialExchange.test.ts +97 -0
  104. package/src/didcomm/credential-exchange/index.ts +10 -0
  105. package/src/didcomm/credential-exchange/postgres.ts +45 -0
  106. package/src/didcomm/credential-exchange/sqlite.ts +39 -0
  107. package/src/didcomm/didcomm-message/DrizzleDidcommMessageRecordAdapter.ts +75 -0
  108. package/src/didcomm/didcomm-message/index.ts +10 -0
  109. package/src/didcomm/didcomm-message/postgres.ts +27 -0
  110. package/src/didcomm/didcomm-message/sqlite.ts +26 -0
  111. package/src/didcomm/mediation/DrizzleDidcommMediationRecordAdapter.ts +51 -0
  112. package/src/didcomm/mediation/index.ts +10 -0
  113. package/src/didcomm/mediation/postgres.ts +33 -0
  114. package/src/didcomm/mediation/sqlite.ts +31 -0
  115. package/src/didcomm/mediator-routing/DrizzleDidcommMediatorRoutingRecordAdapter.ts +49 -0
  116. package/src/didcomm/mediator-routing/index.ts +10 -0
  117. package/src/didcomm/mediator-routing/postgres.ts +14 -0
  118. package/src/didcomm/mediator-routing/sqlite.ts +17 -0
  119. package/src/didcomm/out-of-band/DrizzleDidcommOutOfBandRecordAdapter.ts +85 -0
  120. package/src/didcomm/out-of-band/__tests__/outOfBand.test.ts +84 -0
  121. package/src/didcomm/out-of-band/index.ts +10 -0
  122. package/src/didcomm/out-of-band/postgres.ts +46 -0
  123. package/src/didcomm/out-of-band/sqlite.ts +46 -0
  124. package/src/didcomm/postgres.ts +8 -0
  125. package/src/didcomm/proof-exchange/DrizzleDidcommProofExchangeRecordAdapter.ts +51 -0
  126. package/src/didcomm/proof-exchange/index.ts +10 -0
  127. package/src/didcomm/proof-exchange/postgres.ts +33 -0
  128. package/src/didcomm/proof-exchange/sqlite.ts +29 -0
  129. package/src/didcomm/sqlite.ts +8 -0
  130. package/src/drpc/bundle.ts +18 -0
  131. package/src/drpc/drpc/DrizzleDidcommDrpcRecordAdapter.ts +44 -0
  132. package/src/drpc/drpc/index.ts +10 -0
  133. package/src/drpc/drpc/postgres.ts +31 -0
  134. package/src/drpc/drpc/sqlite.ts +29 -0
  135. package/src/drpc/postgres.ts +1 -0
  136. package/src/drpc/sqlite.ts +1 -0
  137. package/src/error/CredoDrizzleColumnDoesNotExistError.ts +21 -0
  138. package/src/error/CredoDrizzleStorageError.ts +7 -0
  139. package/src/error/index.ts +2 -0
  140. package/src/index.ts +29 -0
  141. package/src/openid4vc/bundle.ts +26 -0
  142. package/src/openid4vc/openid4vc-issuance-session/DrizzleOpenId4VcIssuanceSessionRecordAdapter.ts +90 -0
  143. package/src/openid4vc/openid4vc-issuance-session/index.ts +10 -0
  144. package/src/openid4vc/openid4vc-issuance-session/postgres.ts +54 -0
  145. package/src/openid4vc/openid4vc-issuance-session/sqlite.ts +54 -0
  146. package/src/openid4vc/openid4vc-issuer/DrizzleOpenid4vcIssuerRecordAdapter.ts +50 -0
  147. package/src/openid4vc/openid4vc-issuer/index.ts +10 -0
  148. package/src/openid4vc/openid4vc-issuer/postgres.ts +31 -0
  149. package/src/openid4vc/openid4vc-issuer/sqlite.ts +40 -0
  150. package/src/openid4vc/openid4vc-verification-session/DrizzleOpenId4VcVerificationSessionRecordAdapter.ts +62 -0
  151. package/src/openid4vc/openid4vc-verification-session/index.ts +10 -0
  152. package/src/openid4vc/openid4vc-verification-session/postgres.ts +46 -0
  153. package/src/openid4vc/openid4vc-verification-session/sqlite.ts +40 -0
  154. package/src/openid4vc/openid4vc-verifier/DrizzleOpenid4vcVerifierRecordAdapter.ts +43 -0
  155. package/src/openid4vc/openid4vc-verifier/index.ts +10 -0
  156. package/src/openid4vc/openid4vc-verifier/postgres.ts +14 -0
  157. package/src/openid4vc/openid4vc-verifier/sqlite.ts +19 -0
  158. package/src/openid4vc/postgres.ts +4 -0
  159. package/src/openid4vc/sqlite.ts +4 -0
  160. package/src/postgres/baseRecord.ts +44 -0
  161. package/src/postgres/index.ts +1 -0
  162. package/src/question-answer/bundle.ts +18 -0
  163. package/src/question-answer/postgres.ts +1 -0
  164. package/src/question-answer/question-answer/DrizzleDidcommQuestionAnswerRecordAdapter.ts +52 -0
  165. package/src/question-answer/question-answer/index.ts +10 -0
  166. package/src/question-answer/question-answer/postgres.ts +34 -0
  167. package/src/question-answer/question-answer/sqlite.ts +32 -0
  168. package/src/question-answer/sqlite.ts +1 -0
  169. package/src/sqlite/baseRecord.ts +38 -0
  170. package/src/sqlite/index.ts +1 -0
  171. package/src/storage/DrizzleStorageService.ts +87 -0
  172. package/src/storage/index.ts +1 -0
  173. package/src/tenants/bundle.ts +19 -0
  174. package/src/tenants/postgres.ts +2 -0
  175. package/src/tenants/sqlite.ts +2 -0
  176. package/src/tenants/tenant/DrizzleTenantRecordAdapter.ts +45 -0
  177. package/src/tenants/tenant/index.ts +10 -0
  178. package/src/tenants/tenant/postgres.ts +16 -0
  179. package/src/tenants/tenant/sqlite.ts +16 -0
  180. package/src/tenants/tenant-routing/DrizzleTenantRoutingRecordAdapter.ts +44 -0
  181. package/src/tenants/tenant-routing/index.ts +10 -0
  182. package/src/tenants/tenant-routing/postgres.ts +20 -0
  183. package/src/tenants/tenant-routing/sqlite.ts +20 -0
@@ -0,0 +1,319 @@
1
+ /**
2
+ * Adapter between a specific Record class and the record Type
3
+ */
4
+
5
+ import { AgentContext, BaseRecord, CredoError, Query, QueryOptions, RecordNotFoundError } from '@credo-ts/core'
6
+ import { Simplify, and, eq } from 'drizzle-orm'
7
+ import { PgTable, pgTable } from 'drizzle-orm/pg-core'
8
+ import { SQLiteTable as _SQLiteTable, sqliteTable } from 'drizzle-orm/sqlite-core'
9
+ import { DrizzleDatabase, isDrizzlePostgresDatabase, isDrizzleSqliteDatabase } from '../DrizzleDatabase'
10
+ import { CredoDrizzleStorageError } from '../error'
11
+ import { getPostgresBaseRecordTable } from '../postgres'
12
+ import { getSqliteBaseRecordTable } from '../sqlite'
13
+ import { DrizzleCustomTagKeyMapping, queryToDrizzlePostgres } from './queryToDrizzlePostgres'
14
+ import { queryToDrizzleSqlite } from './queryToDrizzleSqlite'
15
+
16
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
17
+ export type AnyDrizzleAdapter = BaseDrizzleRecordAdapter<any, any, any, any, any>
18
+
19
+ export type DrizzleAdapterValues<Table extends _SQLiteTable> = Simplify<
20
+ Omit<
21
+ { [Key in keyof Table['$inferInsert']]: Table['$inferInsert'][Key] },
22
+ Exclude<keyof ReturnType<typeof getSqliteBaseRecordTable>, 'customTags'>
23
+ >
24
+ >
25
+
26
+ export type DrizzleAdapterRecordValues<Table extends _SQLiteTable> = Simplify<
27
+ Omit<{ [Key in keyof Table['$inferInsert']]: Table['$inferInsert'][Key] }, 'contextCorrelationId'>
28
+ >
29
+
30
+ export abstract class BaseDrizzleRecordAdapter<
31
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
32
+ CredoRecord extends BaseRecord<any, any, any>,
33
+ PostgresTable extends ReturnType<typeof pgTable<string, ReturnType<typeof getPostgresBaseRecordTable>>>,
34
+ PostgresSchema extends Record<string, unknown>,
35
+ SQLiteTable extends ReturnType<typeof sqliteTable<string, ReturnType<typeof getSqliteBaseRecordTable>>>,
36
+ SQLiteSchema extends Record<string, unknown>,
37
+ > {
38
+ public recordType: CredoRecord['type']
39
+
40
+ public table: {
41
+ postgres: PostgresTable
42
+ sqlite: SQLiteTable
43
+ }
44
+
45
+ /**
46
+ * Allows overriding top level tags (as used by Credo record classes)
47
+ * to the database structure. For example mapping from the tag `presentationAuthSession`
48
+ * to the nested database json structure `presentation.authSession`.
49
+ */
50
+ public tagKeyMapping?: DrizzleCustomTagKeyMapping
51
+
52
+ public constructor(
53
+ public database: DrizzleDatabase<PostgresSchema, SQLiteSchema>,
54
+ table: {
55
+ postgres: PostgresTable
56
+ sqlite: SQLiteTable
57
+ },
58
+ recordType: CredoRecord['type']
59
+ ) {
60
+ this.table = table
61
+ this.recordType = recordType
62
+ }
63
+
64
+ public abstract getValues(record: CredoRecord): DrizzleAdapterValues<SQLiteTable>
65
+ public getValuesWithBase(agentContext: AgentContext, record: CredoRecord) {
66
+ return {
67
+ ...this.getValues(record),
68
+
69
+ // Always store based on context correlation id
70
+ contextCorrelationId: agentContext.contextCorrelationId,
71
+
72
+ id: record.id,
73
+ metadata: record.metadata.data,
74
+ createdAt: record.createdAt,
75
+ updatedAt: record.updatedAt,
76
+ }
77
+ }
78
+
79
+ private _toRecord(values: DrizzleAdapterRecordValues<SQLiteTable>): CredoRecord {
80
+ const filteredValues = Object.fromEntries(
81
+ Object.entries(values).filter(([_key, value]) => value !== null)
82
+ ) as DrizzleAdapterRecordValues<SQLiteTable>
83
+
84
+ return this.toRecord(filteredValues)
85
+ }
86
+
87
+ public abstract toRecord(values: DrizzleAdapterRecordValues<SQLiteTable>): CredoRecord
88
+
89
+ public async query(agentContext: AgentContext, query?: Query<CredoRecord>, queryOptions?: QueryOptions) {
90
+ if (isDrizzlePostgresDatabase(this.database)) {
91
+ let queryResult = this.database.select().from(this.table.postgres as PgTable)
92
+
93
+ if (query) {
94
+ queryResult = queryResult.where(
95
+ and(
96
+ // Always filter based on context correlation id
97
+ eq(this.table.postgres.contextCorrelationId, agentContext.contextCorrelationId),
98
+ queryToDrizzlePostgres(query ?? {}, this.table.postgres, this.tagKeyMapping)
99
+ )
100
+ ) as typeof queryResult
101
+ }
102
+
103
+ if (queryOptions?.limit !== undefined) {
104
+ queryResult = queryResult.limit(queryOptions.limit) as typeof queryResult
105
+ }
106
+
107
+ if (queryOptions?.offset !== undefined) {
108
+ queryResult = queryResult.offset(queryOptions.offset ?? 0) as typeof queryResult
109
+ }
110
+
111
+ const result = await queryResult
112
+ return result.map(({ contextCorrelationId, ...item }) =>
113
+ this._toRecord(item as DrizzleAdapterRecordValues<SQLiteTable>)
114
+ )
115
+ }
116
+
117
+ if (isDrizzleSqliteDatabase(this.database)) {
118
+ let queryResult = this.database.select().from(this.table.sqlite as SQLiteTable)
119
+
120
+ if (query) {
121
+ queryResult = queryResult.where(
122
+ and(
123
+ // Always filter based on context correlation id
124
+ eq(this.table.sqlite.contextCorrelationId, agentContext.contextCorrelationId),
125
+ queryToDrizzleSqlite(query ?? {}, this.table.sqlite, this.tagKeyMapping)
126
+ )
127
+ ) as unknown as typeof queryResult
128
+ }
129
+
130
+ if (queryOptions?.limit !== undefined) {
131
+ queryResult = queryResult.limit(queryOptions.limit) as unknown as typeof queryResult
132
+ }
133
+
134
+ if (queryOptions?.offset !== undefined) {
135
+ queryResult = queryResult.offset(queryOptions.offset ?? 0) as unknown as typeof queryResult
136
+ }
137
+
138
+ const result = await queryResult
139
+ return result.map(({ contextCorrelationId, ...item }) =>
140
+ this._toRecord(item as DrizzleAdapterRecordValues<SQLiteTable>)
141
+ )
142
+ }
143
+
144
+ throw new CredoError('Unsupported database type')
145
+ }
146
+
147
+ public async getById(agentContext: AgentContext, id: string) {
148
+ if (isDrizzlePostgresDatabase(this.database)) {
149
+ const [result] = await this.database
150
+ .select()
151
+ .from(this.table.postgres as PgTable)
152
+ .where(
153
+ and(
154
+ eq(this.table.postgres.id, id),
155
+ eq(this.table.postgres.contextCorrelationId, agentContext.contextCorrelationId)
156
+ )
157
+ )
158
+ .limit(1)
159
+
160
+ if (!result) {
161
+ throw new RecordNotFoundError(`record with id ${id} not found.`, {
162
+ recordType: this.recordType,
163
+ })
164
+ }
165
+
166
+ const { contextCorrelationId, ...item } = result
167
+ return this._toRecord(item as DrizzleAdapterRecordValues<SQLiteTable>)
168
+ }
169
+
170
+ if (isDrizzleSqliteDatabase(this.database)) {
171
+ const [result] = await this.database
172
+ .select()
173
+ .from(this.table.sqlite)
174
+ .where(
175
+ and(
176
+ eq(this.table.sqlite.id, id),
177
+ eq(this.table.sqlite.contextCorrelationId, agentContext.contextCorrelationId)
178
+ )
179
+ )
180
+ .limit(1)
181
+
182
+ if (!result) {
183
+ throw new RecordNotFoundError(`record with id ${id} not found.`, {
184
+ recordType: this.recordType,
185
+ })
186
+ }
187
+
188
+ const { contextCorrelationId, ...item } = result
189
+ return this._toRecord(item as DrizzleAdapterRecordValues<SQLiteTable>)
190
+ }
191
+
192
+ throw new CredoError('Unsupported database type')
193
+ }
194
+
195
+ public async insert(agentContext: AgentContext, record: CredoRecord) {
196
+ if (isDrizzlePostgresDatabase(this.database)) {
197
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
198
+ await this.database.insert(this.table.postgres).values(this.getValuesWithBase(agentContext, record) as any)
199
+ return
200
+ }
201
+
202
+ if (isDrizzleSqliteDatabase(this.database)) {
203
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
204
+ await this.database.insert(this.table.sqlite).values(this.getValuesWithBase(agentContext, record) as any)
205
+ return
206
+ }
207
+
208
+ throw new CredoError('Unsupported database type')
209
+ }
210
+
211
+ public async update(agentContext: AgentContext, record: CredoRecord) {
212
+ // Although id should always be set, if for some reason it is not set it can be quite impactful
213
+ if (!record.id) {
214
+ throw new CredoDrizzleStorageError(`Record of type ${record.type}' is missing 'id' column.`)
215
+ }
216
+
217
+ if (isDrizzlePostgresDatabase(this.database)) {
218
+ const updated = await this.database
219
+ .update(this.table.postgres)
220
+ // biome-ignore lint/suspicious/noExplicitAny: generics really don't play well here
221
+ .set(this.getValuesWithBase(agentContext, record) as any)
222
+ .where(
223
+ and(
224
+ eq(this.table.postgres.id, record.id),
225
+ eq(this.table.postgres.contextCorrelationId, agentContext.contextCorrelationId)
226
+ )
227
+ )
228
+ .returning({ id: this.table.postgres.id })
229
+
230
+ if (updated.length === 0) {
231
+ throw new RecordNotFoundError(`record with id ${record.id} not found.`, {
232
+ recordType: this.recordType,
233
+ })
234
+ }
235
+
236
+ return
237
+ }
238
+
239
+ if (isDrizzleSqliteDatabase(this.database)) {
240
+ const updated = await this.database
241
+ .update(this.table.sqlite)
242
+ // biome-ignore lint/suspicious/noExplicitAny: generics really don't play well here
243
+ .set(this.getValuesWithBase(agentContext, record) as any)
244
+ .where(
245
+ and(
246
+ eq(this.table.sqlite.id, record.id),
247
+ eq(this.table.sqlite.contextCorrelationId, agentContext.contextCorrelationId)
248
+ )
249
+ )
250
+ .returning({
251
+ id: this.table.sqlite.id,
252
+ })
253
+
254
+ if (updated.length === 0) {
255
+ throw new RecordNotFoundError(`record with id ${record.id} not found.`, {
256
+ recordType: this.recordType,
257
+ })
258
+ }
259
+
260
+ return
261
+ }
262
+
263
+ throw new CredoError('Unsupported database type')
264
+ }
265
+
266
+ public async delete(agentContext: AgentContext, id: string) {
267
+ // Although id should always be set, if for some reason it is not set it can be quite impactful
268
+ if (!id) {
269
+ throw new CredoDrizzleStorageError(`Missing required 'id' for delete.`)
270
+ }
271
+
272
+ if (isDrizzlePostgresDatabase(this.database)) {
273
+ const deleted = await this.database
274
+ .delete(this.table.postgres)
275
+ .where(
276
+ and(
277
+ eq(this.table.postgres.id, id),
278
+ eq(this.table.postgres.contextCorrelationId, agentContext.contextCorrelationId)
279
+ )
280
+ )
281
+ .returning({
282
+ id: this.table.postgres.id,
283
+ })
284
+
285
+ if (deleted.length === 0) {
286
+ throw new RecordNotFoundError(`record with id ${id} not found.`, {
287
+ recordType: this.recordType,
288
+ })
289
+ }
290
+
291
+ return
292
+ }
293
+
294
+ if (isDrizzleSqliteDatabase(this.database)) {
295
+ const deleted = await this.database
296
+ .delete(this.table.postgres)
297
+ .where(
298
+ and(
299
+ eq(this.table.sqlite.id, id),
300
+ eq(this.table.sqlite.contextCorrelationId, agentContext.contextCorrelationId)
301
+ )
302
+ )
303
+ .returning({
304
+ id: this.table.sqlite.id,
305
+ })
306
+
307
+ if (deleted.length === 0) {
308
+ throw new RecordNotFoundError(`record with id ${id} not found.`, {
309
+ recordType: this.recordType,
310
+ })
311
+ }
312
+
313
+ return
314
+ }
315
+
316
+ // @ts-expect-error
317
+ throw new CredoError(`Unsupported database type '${database.type}'`)
318
+ }
319
+ }
@@ -0,0 +1,328 @@
1
+ import { ConnectionRecord, DidExchangeRole, DidExchangeState } from '@credo-ts/didcomm'
2
+ import { pushSchema } from 'drizzle-kit/api'
3
+ import { PgDatabase } from 'drizzle-orm/pg-core'
4
+ import { drizzle } from 'drizzle-orm/pglite'
5
+ import { DrizzlePostgresDatabase } from '../../DrizzleDatabase'
6
+ import * as coreContextSchema from '../../core/context/postgres'
7
+ import * as didcommConnectionSchema from '../../didcomm/connection/postgres'
8
+ import { queryToDrizzlePostgres } from '../queryToDrizzlePostgres'
9
+
10
+ const { didcommConnection } = didcommConnectionSchema
11
+ const { context } = coreContextSchema
12
+
13
+ const db = drizzle('memory://', {
14
+ schema: { ...didcommConnectionSchema, ...coreContextSchema },
15
+ }) as unknown as DrizzlePostgresDatabase<typeof didcommConnectionSchema>
16
+
17
+ describe('queryToDrizzlePostgres', () => {
18
+ beforeAll(async () => {
19
+ const { apply } = await pushSchema(
20
+ { ...didcommConnectionSchema, ...coreContextSchema },
21
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
22
+ db as unknown as PgDatabase<any>
23
+ )
24
+ await apply()
25
+
26
+ await db.insert(context).values({
27
+ contextCorrelationId: 'b2fc0867-d0d1-4182-ade7-813b695d43c2',
28
+ })
29
+ await db.insert(didcommConnection).values({
30
+ createdAt: new Date(),
31
+ updatedAt: new Date(),
32
+ contextCorrelationId: 'b2fc0867-d0d1-4182-ade7-813b695d43c2',
33
+ id: 'db0ddc8f-5339-431b-9675-749f8a2ac92f',
34
+ role: DidExchangeRole.Requester,
35
+ state: DidExchangeState.Abandoned,
36
+ connectionTypes: ['one', 'three', 'four'],
37
+ invitationDid: 'some string',
38
+ customTags: {
39
+ myCustomTag: ['First', 'Second'],
40
+ anotherCustomTag: true,
41
+ },
42
+ })
43
+ })
44
+
45
+ test('should correctly query column', async () => {
46
+ expect(
47
+ await db
48
+ .select()
49
+ .from(didcommConnection)
50
+ .where(
51
+ queryToDrizzlePostgres<ConnectionRecord>(
52
+ {
53
+ invitationDid: 'some string',
54
+ },
55
+ didcommConnection
56
+ )
57
+ )
58
+ ).toHaveLength(1)
59
+
60
+ expect(
61
+ await db
62
+ .select()
63
+ .from(didcommConnection)
64
+ .where(
65
+ queryToDrizzlePostgres<ConnectionRecord>(
66
+ {
67
+ invitationDid: 'some other string',
68
+ },
69
+ didcommConnection
70
+ )
71
+ )
72
+ ).toHaveLength(0)
73
+ })
74
+
75
+ test('should correctly query array value column', async () => {
76
+ expect(
77
+ await db
78
+ .select()
79
+ .from(didcommConnection)
80
+ .where(
81
+ queryToDrizzlePostgres<ConnectionRecord>(
82
+ {
83
+ connectionTypes: ['one', 'three'],
84
+ invitationDid: 'some string',
85
+ },
86
+ didcommConnection
87
+ )
88
+ )
89
+ ).toHaveLength(1)
90
+
91
+ expect(
92
+ await db
93
+ .select()
94
+ .from(didcommConnection)
95
+ .where(
96
+ queryToDrizzlePostgres<ConnectionRecord>(
97
+ {
98
+ connectionTypes: ['one', 'two', 'five'],
99
+ invitationDid: 'some string',
100
+ },
101
+ didcommConnection
102
+ )
103
+ )
104
+ ).toHaveLength(0)
105
+
106
+ expect(
107
+ await db
108
+ .select()
109
+ .from(didcommConnection)
110
+ .where(
111
+ queryToDrizzlePostgres<ConnectionRecord>(
112
+ {
113
+ connectionTypes: ['one'],
114
+ invitationDid: 'some string',
115
+ },
116
+ didcommConnection
117
+ )
118
+ )
119
+ ).toHaveLength(1)
120
+ })
121
+
122
+ test('should correctly query custom tag column value', async () => {
123
+ expect(
124
+ await db
125
+ .select()
126
+ .from(didcommConnection)
127
+ .where(
128
+ queryToDrizzlePostgres<ConnectionRecord>(
129
+ {
130
+ anotherCustomTag: true,
131
+ invitationDid: 'some string',
132
+ },
133
+ didcommConnection
134
+ )
135
+ )
136
+ ).toHaveLength(1)
137
+
138
+ expect(
139
+ await db
140
+ .select()
141
+ .from(didcommConnection)
142
+ .where(
143
+ queryToDrizzlePostgres<ConnectionRecord>(
144
+ {
145
+ anotherCustomTag: false,
146
+ invitationDid: 'some string',
147
+ },
148
+ didcommConnection
149
+ )
150
+ )
151
+ ).toHaveLength(0)
152
+ })
153
+
154
+ test('should correctly query custom tag column array value', async () => {
155
+ expect(
156
+ await db
157
+ .select()
158
+ .from(didcommConnection)
159
+ .where(
160
+ queryToDrizzlePostgres<ConnectionRecord>(
161
+ {
162
+ myCustomTag: ['First', 'Second'],
163
+ invitationDid: 'some string',
164
+ },
165
+ didcommConnection
166
+ )
167
+ )
168
+ ).toHaveLength(1)
169
+
170
+ expect(
171
+ await db
172
+ .select()
173
+ .from(didcommConnection)
174
+ .where(
175
+ queryToDrizzlePostgres<ConnectionRecord>(
176
+ {
177
+ myCustomTag: ['Third'],
178
+ invitationDid: 'some string',
179
+ },
180
+ didcommConnection
181
+ )
182
+ )
183
+ ).toHaveLength(0)
184
+
185
+ expect(
186
+ await db
187
+ .select()
188
+ .from(didcommConnection)
189
+ .where(
190
+ queryToDrizzlePostgres<ConnectionRecord>(
191
+ {
192
+ myCustomTag: ['First'],
193
+ invitationDid: 'some string',
194
+ },
195
+ didcommConnection
196
+ )
197
+ )
198
+ ).toHaveLength(1)
199
+ })
200
+
201
+ test('should correctly query with and/or', async () => {
202
+ expect(
203
+ await db
204
+ .select()
205
+ .from(didcommConnection)
206
+ .where(
207
+ queryToDrizzlePostgres<ConnectionRecord>(
208
+ {
209
+ connectionTypes: ['one'],
210
+ $or: [
211
+ {
212
+ connectionTypes: ['two'],
213
+ },
214
+ {
215
+ connectionTypes: ['three'],
216
+ },
217
+ ],
218
+ $and: [
219
+ {
220
+ connectionTypes: ['four'],
221
+ },
222
+ ],
223
+ },
224
+ didcommConnection
225
+ )
226
+ )
227
+ ).toHaveLength(1)
228
+
229
+ expect(
230
+ await db
231
+ .select()
232
+ .from(didcommConnection)
233
+ .where(
234
+ queryToDrizzlePostgres<ConnectionRecord>(
235
+ {
236
+ connectionTypes: ['one'],
237
+ $or: [
238
+ {
239
+ connectionTypes: ['two'],
240
+ },
241
+ {
242
+ connectionTypes: ['three'],
243
+ },
244
+ ],
245
+ $and: [
246
+ {
247
+ connectionTypes: ['four'],
248
+ },
249
+ {
250
+ connectionTypes: ['two'],
251
+ },
252
+ ],
253
+ },
254
+ didcommConnection
255
+ )
256
+ )
257
+ ).toHaveLength(0)
258
+ })
259
+
260
+ test('should correctly query with not', async () => {
261
+ expect(
262
+ await db
263
+ .select()
264
+ .from(didcommConnection)
265
+ .where(
266
+ queryToDrizzlePostgres<ConnectionRecord>(
267
+ {
268
+ connectionTypes: ['one'],
269
+ $not: {
270
+ $and: [
271
+ {
272
+ connectionTypes: ['two'],
273
+ },
274
+ {
275
+ connectionTypes: ['five'],
276
+ },
277
+ ],
278
+ $or: [
279
+ {
280
+ connectionTypes: ['two'],
281
+ },
282
+ {
283
+ connectionTypes: ['three'],
284
+ },
285
+ ],
286
+ },
287
+ },
288
+ didcommConnection
289
+ )
290
+ )
291
+ ).toHaveLength(1)
292
+
293
+ expect(
294
+ await db
295
+ .select()
296
+ .from(didcommConnection)
297
+ .where(
298
+ queryToDrizzlePostgres<ConnectionRecord>(
299
+ {
300
+ connectionTypes: ['one'],
301
+ $not: {
302
+ $and: [
303
+ {
304
+ connectionTypes: ['two'],
305
+ },
306
+ {
307
+ connectionTypes: ['five'],
308
+ },
309
+ {
310
+ connectionTypes: ['three'],
311
+ },
312
+ ],
313
+ $or: [
314
+ {
315
+ connectionTypes: ['two'],
316
+ },
317
+ {
318
+ connectionTypes: ['three'],
319
+ },
320
+ ],
321
+ },
322
+ },
323
+ didcommConnection
324
+ )
325
+ )
326
+ ).toHaveLength(0)
327
+ })
328
+ })