@credo-ts/drizzle-storage 0.6.0-pr-2324-20250708122805 → 0.6.0-pr-2324-20250709075226
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/cli/drizzle.config.ts +1 -1
- package/cli-build/drizzle.config.js +1 -1
- package/cli-build/drizzle.config.js.map +1 -1
- package/package.json +18 -17
- package/src/DrizzleDatabase.ts +29 -0
- package/src/DrizzleRecord.ts +73 -0
- package/src/DrizzleStorageModule.ts +112 -0
- package/src/DrizzleStorageModuleConfig.ts +48 -0
- package/src/action-menu/action-menu/DrizzleDidcommActionMenuRecordAdapter.ts +46 -0
- package/src/action-menu/action-menu/index.ts +10 -0
- package/src/action-menu/action-menu/postgres.ts +31 -0
- package/src/action-menu/action-menu/sqlite.ts +34 -0
- package/src/action-menu/bundle.ts +18 -0
- package/src/action-menu/postgres.ts +1 -0
- package/src/action-menu/sqlite.ts +1 -0
- package/src/adapter/BaseDrizzleRecordAdapter.ts +319 -0
- package/src/adapter/__tests__/queryToDrizzlePostgres.drizzle.e2e.test.ts +330 -0
- package/src/adapter/__tests__/queryToDrizzleSqlite.test.ts +324 -0
- package/src/adapter/index.ts +6 -0
- package/src/adapter/queryToDrizzlePostgres.ts +217 -0
- package/src/adapter/queryToDrizzleSqlite.ts +213 -0
- package/src/anoncreds/bundle.ts +34 -0
- package/src/anoncreds/credential/DrizzleAnonCredsCredentialRecordAdapter.ts +93 -0
- package/src/anoncreds/credential/index.ts +10 -0
- package/src/anoncreds/credential/postgres.ts +27 -0
- package/src/anoncreds/credential/sqlite.ts +27 -0
- package/src/anoncreds/credential-definition/DrizzleAnonCredsCredentialDefinitionRecordAdapter.ts +72 -0
- package/src/anoncreds/credential-definition/index.ts +10 -0
- package/src/anoncreds/credential-definition/postgres.ts +23 -0
- package/src/anoncreds/credential-definition/sqlite.ts +23 -0
- package/src/anoncreds/credential-definition-private/DrizzleAnonCredsCredentialDefinitionPrivateRecordAdapter.ts +48 -0
- package/src/anoncreds/credential-definition-private/index.ts +10 -0
- package/src/anoncreds/credential-definition-private/postgres.ts +14 -0
- package/src/anoncreds/credential-definition-private/sqlite.ts +14 -0
- package/src/anoncreds/key-correctness-proof/DrizzleAnonCredsKeyCorrectnessProofRecordAdapter.ts +46 -0
- package/src/anoncreds/key-correctness-proof/index.ts +10 -0
- package/src/anoncreds/key-correctness-proof/postgres.ts +13 -0
- package/src/anoncreds/key-correctness-proof/sqlite.ts +14 -0
- package/src/anoncreds/link-secret/DrizzleAnonCredsLinkSecretRecordAdapter.ts +45 -0
- package/src/anoncreds/link-secret/index.ts +10 -0
- package/src/anoncreds/link-secret/postgres.ts +18 -0
- package/src/anoncreds/link-secret/sqlite.ts +18 -0
- package/src/anoncreds/postgres.ts +8 -0
- package/src/anoncreds/revocation-registry-definition/DrizzleAnonCredsRevocationRegistryDefinitionRecordAdapter.ts +52 -0
- package/src/anoncreds/revocation-registry-definition/index.ts +10 -0
- package/src/anoncreds/revocation-registry-definition/postgres.ts +18 -0
- package/src/anoncreds/revocation-registry-definition/sqlite.ts +20 -0
- package/src/anoncreds/revocation-registry-definition-private/DrizzleAnonCredsRevocationRegistryDefinitionPrivateRecordAdapter.ts +53 -0
- package/src/anoncreds/revocation-registry-definition-private/index.ts +10 -0
- package/src/anoncreds/revocation-registry-definition-private/postgres.ts +22 -0
- package/src/anoncreds/revocation-registry-definition-private/sqlite.ts +18 -0
- package/src/anoncreds/schema/DrizzleAnonCredsSchemaRecordAdapter.ts +54 -0
- package/src/anoncreds/schema/__tests__/schema.drizzle.e2e.test.ts +70 -0
- package/src/anoncreds/schema/index.ts +10 -0
- package/src/anoncreds/schema/postgres.ts +22 -0
- package/src/anoncreds/schema/sqlite.ts +22 -0
- package/src/anoncreds/sqlite.ts +8 -0
- package/src/applyReactNativeMigrations.ts +24 -0
- package/src/combineSchemas.ts +44 -0
- package/src/core/bundle.ts +33 -0
- package/src/core/context/index.ts +8 -0
- package/src/core/context/postgres.ts +5 -0
- package/src/core/context/sqlite.ts +5 -0
- package/src/core/did/DrizzleDidRecordAdapter.ts +71 -0
- package/src/core/did/index.ts +10 -0
- package/src/core/did/postgres.ts +28 -0
- package/src/core/did/sqlite.ts +26 -0
- package/src/core/genericRecord/DrizzleGenericRecordAdapter.ts +36 -0
- package/src/core/genericRecord/index.ts +10 -0
- package/src/core/genericRecord/postgres.ts +12 -0
- package/src/core/genericRecord/sqlite.ts +12 -0
- package/src/core/mdoc/DrizzleMdocRecordAdapter.ts +44 -0
- package/src/core/mdoc/index.ts +10 -0
- package/src/core/mdoc/postgres.ts +15 -0
- package/src/core/mdoc/sqlite.ts +15 -0
- package/src/core/postgres.ts +8 -0
- package/src/core/sdJwtVc/DrizzleSdJwtVcRecordAdapter.ts +46 -0
- package/src/core/sdJwtVc/index.ts +10 -0
- package/src/core/sdJwtVc/postgres.ts +17 -0
- package/src/core/sdJwtVc/sqlite.ts +17 -0
- package/src/core/singleContextLruCache/DrizzleSingleContextLruCacheRecordAdapter.ts +43 -0
- package/src/core/singleContextLruCache/index.ts +10 -0
- package/src/core/singleContextLruCache/postgres.ts +12 -0
- package/src/core/singleContextLruCache/sqlite.ts +13 -0
- package/src/core/sqlite.ts +8 -0
- package/src/core/storageVersion/DrizzleStorageVersionRecordAdapter.ts +36 -0
- package/src/core/storageVersion/index.ts +10 -0
- package/src/core/storageVersion/postgres.ts +13 -0
- package/src/core/storageVersion/sqlite.ts +13 -0
- package/src/core/w3cCredential/DrizzleW3cCredentialRecordAdapter.ts +95 -0
- package/src/core/w3cCredential/index.ts +10 -0
- package/src/core/w3cCredential/postgres.ts +31 -0
- package/src/core/w3cCredential/sqlite.ts +29 -0
- package/src/didcomm/basic-message/DrizzleDidcommBasicMessageRecordAdapter.ts +54 -0
- package/src/didcomm/basic-message/index.ts +10 -0
- package/src/didcomm/basic-message/postgres.ts +30 -0
- package/src/didcomm/basic-message/sqlite.ts +29 -0
- package/src/didcomm/bundle.ts +34 -0
- package/src/didcomm/connection/DrizzleDidcommConnectionRecordAdapter.ts +70 -0
- package/src/didcomm/connection/index.ts +10 -0
- package/src/didcomm/connection/postgres.ts +55 -0
- package/src/didcomm/connection/sqlite.ts +39 -0
- package/src/didcomm/credential-exchange/DrizzleDidcommCredentialExchangeRecordAdapter.ts +64 -0
- package/src/didcomm/credential-exchange/__tests__/credentialExchange.drizzle.e2e.test.ts +104 -0
- package/src/didcomm/credential-exchange/index.ts +10 -0
- package/src/didcomm/credential-exchange/postgres.ts +45 -0
- package/src/didcomm/credential-exchange/sqlite.ts +39 -0
- package/src/didcomm/didcomm-message/DrizzleDidcommMessageRecordAdapter.ts +75 -0
- package/src/didcomm/didcomm-message/index.ts +10 -0
- package/src/didcomm/didcomm-message/postgres.ts +27 -0
- package/src/didcomm/didcomm-message/sqlite.ts +26 -0
- package/src/didcomm/mediation/DrizzleDidcommMediationRecordAdapter.ts +51 -0
- package/src/didcomm/mediation/index.ts +10 -0
- package/src/didcomm/mediation/postgres.ts +33 -0
- package/src/didcomm/mediation/sqlite.ts +31 -0
- package/src/didcomm/mediator-routing/DrizzleDidcommMediatorRoutingRecordAdapter.ts +49 -0
- package/src/didcomm/mediator-routing/index.ts +10 -0
- package/src/didcomm/mediator-routing/postgres.ts +14 -0
- package/src/didcomm/mediator-routing/sqlite.ts +17 -0
- package/src/didcomm/out-of-band/DrizzleDidcommOutOfBandRecordAdapter.ts +85 -0
- package/src/didcomm/out-of-band/__tests__/outOfBand.drizzle.e2e.test.ts +88 -0
- package/src/didcomm/out-of-band/index.ts +10 -0
- package/src/didcomm/out-of-band/postgres.ts +46 -0
- package/src/didcomm/out-of-band/sqlite.ts +46 -0
- package/src/didcomm/postgres.ts +8 -0
- package/src/didcomm/proof-exchange/DrizzleDidcommProofExchangeRecordAdapter.ts +51 -0
- package/src/didcomm/proof-exchange/index.ts +10 -0
- package/src/didcomm/proof-exchange/postgres.ts +33 -0
- package/src/didcomm/proof-exchange/sqlite.ts +29 -0
- package/src/didcomm/sqlite.ts +8 -0
- package/src/drpc/bundle.ts +18 -0
- package/src/drpc/drpc/DrizzleDidcommDrpcRecordAdapter.ts +44 -0
- package/src/drpc/drpc/index.ts +10 -0
- package/src/drpc/drpc/postgres.ts +31 -0
- package/src/drpc/drpc/sqlite.ts +29 -0
- package/src/drpc/postgres.ts +1 -0
- package/src/drpc/sqlite.ts +1 -0
- package/src/error/CredoDrizzleColumnDoesNotExistError.ts +21 -0
- package/src/error/CredoDrizzleStorageError.ts +7 -0
- package/src/error/index.ts +2 -0
- package/src/index.ts +29 -0
- package/src/openid4vc/bundle.ts +26 -0
- package/src/openid4vc/openid4vc-issuance-session/DrizzleOpenId4VcIssuanceSessionRecordAdapter.ts +90 -0
- package/src/openid4vc/openid4vc-issuance-session/index.ts +10 -0
- package/src/openid4vc/openid4vc-issuance-session/postgres.ts +54 -0
- package/src/openid4vc/openid4vc-issuance-session/sqlite.ts +54 -0
- package/src/openid4vc/openid4vc-issuer/DrizzleOpenid4vcIssuerRecordAdapter.ts +50 -0
- package/src/openid4vc/openid4vc-issuer/index.ts +10 -0
- package/src/openid4vc/openid4vc-issuer/postgres.ts +31 -0
- package/src/openid4vc/openid4vc-issuer/sqlite.ts +40 -0
- package/src/openid4vc/openid4vc-verification-session/DrizzleOpenId4VcVerificationSessionRecordAdapter.ts +62 -0
- package/src/openid4vc/openid4vc-verification-session/index.ts +10 -0
- package/src/openid4vc/openid4vc-verification-session/postgres.ts +46 -0
- package/src/openid4vc/openid4vc-verification-session/sqlite.ts +40 -0
- package/src/openid4vc/openid4vc-verifier/DrizzleOpenid4vcVerifierRecordAdapter.ts +43 -0
- package/src/openid4vc/openid4vc-verifier/index.ts +10 -0
- package/src/openid4vc/openid4vc-verifier/postgres.ts +14 -0
- package/src/openid4vc/openid4vc-verifier/sqlite.ts +19 -0
- package/src/openid4vc/postgres.ts +4 -0
- package/src/openid4vc/sqlite.ts +4 -0
- package/src/postgres/baseRecord.ts +44 -0
- package/src/postgres/index.ts +1 -0
- package/src/question-answer/bundle.ts +18 -0
- package/src/question-answer/postgres.ts +1 -0
- package/src/question-answer/question-answer/DrizzleDidcommQuestionAnswerRecordAdapter.ts +52 -0
- package/src/question-answer/question-answer/index.ts +10 -0
- package/src/question-answer/question-answer/postgres.ts +34 -0
- package/src/question-answer/question-answer/sqlite.ts +32 -0
- package/src/question-answer/sqlite.ts +1 -0
- package/src/sqlite/baseRecord.ts +38 -0
- package/src/sqlite/index.ts +1 -0
- package/src/storage/DrizzleStorageService.ts +87 -0
- package/src/storage/index.ts +1 -0
- package/src/tenants/bundle.ts +19 -0
- package/src/tenants/postgres.ts +2 -0
- package/src/tenants/sqlite.ts +2 -0
- package/src/tenants/tenant/DrizzleTenantRecordAdapter.ts +45 -0
- package/src/tenants/tenant/index.ts +10 -0
- package/src/tenants/tenant/postgres.ts +16 -0
- package/src/tenants/tenant/sqlite.ts +16 -0
- package/src/tenants/tenant-routing/DrizzleTenantRoutingRecordAdapter.ts +44 -0
- package/src/tenants/tenant-routing/index.ts +10 -0
- package/src/tenants/tenant-routing/postgres.ts +20 -0
- package/src/tenants/tenant-routing/sqlite.ts +20 -0
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import { ConnectionRecord, DidExchangeRole, DidExchangeState } from '@credo-ts/didcomm'
|
|
2
|
+
import { pushSQLiteSchema } from 'drizzle-kit/api'
|
|
3
|
+
import { drizzle } from 'drizzle-orm/libsql'
|
|
4
|
+
import { DrizzleSqliteDatabase } from '../../DrizzleDatabase'
|
|
5
|
+
import * as coreContextSchema from '../../core/context/sqlite'
|
|
6
|
+
import * as didcommConnectionSchema from '../../didcomm/connection/sqlite'
|
|
7
|
+
import { queryToDrizzleSqlite } from '../queryToDrizzleSqlite'
|
|
8
|
+
|
|
9
|
+
const { context } = coreContextSchema
|
|
10
|
+
const { didcommConnection } = didcommConnectionSchema
|
|
11
|
+
|
|
12
|
+
const db = drizzle(':memory:', {
|
|
13
|
+
schema: { ...didcommConnectionSchema, ...coreContextSchema },
|
|
14
|
+
}) as unknown as DrizzleSqliteDatabase<typeof didcommConnectionSchema>
|
|
15
|
+
|
|
16
|
+
describe('queryToDrizzleSqlite', () => {
|
|
17
|
+
beforeAll(async () => {
|
|
18
|
+
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
19
|
+
const { apply } = await pushSQLiteSchema({ ...didcommConnectionSchema, ...coreContextSchema }, db as any)
|
|
20
|
+
await apply()
|
|
21
|
+
|
|
22
|
+
await db.insert(context).values({
|
|
23
|
+
contextCorrelationId: 'something',
|
|
24
|
+
})
|
|
25
|
+
await db.insert(didcommConnection).values({
|
|
26
|
+
contextCorrelationId: 'something',
|
|
27
|
+
createdAt: new Date(),
|
|
28
|
+
updatedAt: new Date(),
|
|
29
|
+
id: 'something',
|
|
30
|
+
role: DidExchangeRole.Requester,
|
|
31
|
+
state: DidExchangeState.Abandoned,
|
|
32
|
+
connectionTypes: ['one', 'three', 'four'],
|
|
33
|
+
invitationDid: 'some string',
|
|
34
|
+
customTags: {
|
|
35
|
+
myCustomTag: ['First', 'Second'],
|
|
36
|
+
anotherCustomTag: true,
|
|
37
|
+
},
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
test('should correctly query column', async () => {
|
|
42
|
+
expect(
|
|
43
|
+
await db
|
|
44
|
+
.select()
|
|
45
|
+
.from(didcommConnection)
|
|
46
|
+
.where(
|
|
47
|
+
queryToDrizzleSqlite<ConnectionRecord>(
|
|
48
|
+
{
|
|
49
|
+
invitationDid: 'some string',
|
|
50
|
+
},
|
|
51
|
+
didcommConnection
|
|
52
|
+
)
|
|
53
|
+
)
|
|
54
|
+
).toHaveLength(1)
|
|
55
|
+
|
|
56
|
+
expect(
|
|
57
|
+
await db
|
|
58
|
+
.select()
|
|
59
|
+
.from(didcommConnection)
|
|
60
|
+
.where(
|
|
61
|
+
queryToDrizzleSqlite<ConnectionRecord>(
|
|
62
|
+
{
|
|
63
|
+
invitationDid: 'some other string',
|
|
64
|
+
},
|
|
65
|
+
didcommConnection
|
|
66
|
+
)
|
|
67
|
+
)
|
|
68
|
+
).toHaveLength(0)
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
test('should correctly query array value column', async () => {
|
|
72
|
+
expect(
|
|
73
|
+
await db
|
|
74
|
+
.select()
|
|
75
|
+
.from(didcommConnection)
|
|
76
|
+
.where(
|
|
77
|
+
queryToDrizzleSqlite<ConnectionRecord>(
|
|
78
|
+
{
|
|
79
|
+
connectionTypes: ['one', 'three'],
|
|
80
|
+
invitationDid: 'some string',
|
|
81
|
+
},
|
|
82
|
+
didcommConnection
|
|
83
|
+
)
|
|
84
|
+
)
|
|
85
|
+
).toHaveLength(1)
|
|
86
|
+
|
|
87
|
+
expect(
|
|
88
|
+
await db
|
|
89
|
+
.select()
|
|
90
|
+
.from(didcommConnection)
|
|
91
|
+
.where(
|
|
92
|
+
queryToDrizzleSqlite<ConnectionRecord>(
|
|
93
|
+
{
|
|
94
|
+
connectionTypes: ['one', 'two', 'five'],
|
|
95
|
+
invitationDid: 'some string',
|
|
96
|
+
},
|
|
97
|
+
didcommConnection
|
|
98
|
+
)
|
|
99
|
+
)
|
|
100
|
+
).toHaveLength(0)
|
|
101
|
+
|
|
102
|
+
expect(
|
|
103
|
+
await db
|
|
104
|
+
.select()
|
|
105
|
+
.from(didcommConnection)
|
|
106
|
+
.where(
|
|
107
|
+
queryToDrizzleSqlite<ConnectionRecord>(
|
|
108
|
+
{
|
|
109
|
+
connectionTypes: ['one'],
|
|
110
|
+
invitationDid: 'some string',
|
|
111
|
+
},
|
|
112
|
+
didcommConnection
|
|
113
|
+
)
|
|
114
|
+
)
|
|
115
|
+
).toHaveLength(1)
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
test('should correctly query custom tag column value', async () => {
|
|
119
|
+
expect(
|
|
120
|
+
await db
|
|
121
|
+
.select()
|
|
122
|
+
.from(didcommConnection)
|
|
123
|
+
.where(
|
|
124
|
+
queryToDrizzleSqlite<ConnectionRecord>(
|
|
125
|
+
{
|
|
126
|
+
anotherCustomTag: true,
|
|
127
|
+
invitationDid: 'some string',
|
|
128
|
+
},
|
|
129
|
+
didcommConnection
|
|
130
|
+
)
|
|
131
|
+
)
|
|
132
|
+
).toHaveLength(1)
|
|
133
|
+
|
|
134
|
+
expect(
|
|
135
|
+
await db
|
|
136
|
+
.select()
|
|
137
|
+
.from(didcommConnection)
|
|
138
|
+
.where(
|
|
139
|
+
queryToDrizzleSqlite<ConnectionRecord>(
|
|
140
|
+
{
|
|
141
|
+
anotherCustomTag: false,
|
|
142
|
+
invitationDid: 'some string',
|
|
143
|
+
},
|
|
144
|
+
didcommConnection
|
|
145
|
+
)
|
|
146
|
+
)
|
|
147
|
+
).toHaveLength(0)
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
test('should correctly query custom tag column array value', async () => {
|
|
151
|
+
expect(
|
|
152
|
+
await db
|
|
153
|
+
.select()
|
|
154
|
+
.from(didcommConnection)
|
|
155
|
+
.where(
|
|
156
|
+
queryToDrizzleSqlite<ConnectionRecord>(
|
|
157
|
+
{
|
|
158
|
+
myCustomTag: ['First', 'Second'],
|
|
159
|
+
invitationDid: 'some string',
|
|
160
|
+
},
|
|
161
|
+
didcommConnection
|
|
162
|
+
)
|
|
163
|
+
)
|
|
164
|
+
).toHaveLength(1)
|
|
165
|
+
|
|
166
|
+
expect(
|
|
167
|
+
await db
|
|
168
|
+
.select()
|
|
169
|
+
.from(didcommConnection)
|
|
170
|
+
.where(
|
|
171
|
+
queryToDrizzleSqlite<ConnectionRecord>(
|
|
172
|
+
{
|
|
173
|
+
myCustomTag: ['Third'],
|
|
174
|
+
invitationDid: 'some string',
|
|
175
|
+
},
|
|
176
|
+
didcommConnection
|
|
177
|
+
)
|
|
178
|
+
)
|
|
179
|
+
).toHaveLength(0)
|
|
180
|
+
|
|
181
|
+
expect(
|
|
182
|
+
await db
|
|
183
|
+
.select()
|
|
184
|
+
.from(didcommConnection)
|
|
185
|
+
.where(
|
|
186
|
+
queryToDrizzleSqlite<ConnectionRecord>(
|
|
187
|
+
{
|
|
188
|
+
myCustomTag: ['First'],
|
|
189
|
+
invitationDid: 'some string',
|
|
190
|
+
},
|
|
191
|
+
didcommConnection
|
|
192
|
+
)
|
|
193
|
+
)
|
|
194
|
+
).toHaveLength(1)
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
test('should correctly query with and/or', async () => {
|
|
198
|
+
expect(
|
|
199
|
+
await db
|
|
200
|
+
.select()
|
|
201
|
+
.from(didcommConnection)
|
|
202
|
+
.where(
|
|
203
|
+
queryToDrizzleSqlite<ConnectionRecord>(
|
|
204
|
+
{
|
|
205
|
+
connectionTypes: ['one'],
|
|
206
|
+
$or: [
|
|
207
|
+
{
|
|
208
|
+
connectionTypes: ['two'],
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
connectionTypes: ['three'],
|
|
212
|
+
},
|
|
213
|
+
],
|
|
214
|
+
$and: [
|
|
215
|
+
{
|
|
216
|
+
connectionTypes: ['four'],
|
|
217
|
+
},
|
|
218
|
+
],
|
|
219
|
+
},
|
|
220
|
+
didcommConnection
|
|
221
|
+
)
|
|
222
|
+
)
|
|
223
|
+
).toHaveLength(1)
|
|
224
|
+
|
|
225
|
+
expect(
|
|
226
|
+
await db
|
|
227
|
+
.select()
|
|
228
|
+
.from(didcommConnection)
|
|
229
|
+
.where(
|
|
230
|
+
queryToDrizzleSqlite<ConnectionRecord>(
|
|
231
|
+
{
|
|
232
|
+
connectionTypes: ['one'],
|
|
233
|
+
$or: [
|
|
234
|
+
{
|
|
235
|
+
connectionTypes: ['two'],
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
connectionTypes: ['three'],
|
|
239
|
+
},
|
|
240
|
+
],
|
|
241
|
+
$and: [
|
|
242
|
+
{
|
|
243
|
+
connectionTypes: ['four'],
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
connectionTypes: ['two'],
|
|
247
|
+
},
|
|
248
|
+
],
|
|
249
|
+
},
|
|
250
|
+
didcommConnection
|
|
251
|
+
)
|
|
252
|
+
)
|
|
253
|
+
).toHaveLength(0)
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
test('should correctly query with not', async () => {
|
|
257
|
+
expect(
|
|
258
|
+
await db
|
|
259
|
+
.select()
|
|
260
|
+
.from(didcommConnection)
|
|
261
|
+
.where(
|
|
262
|
+
queryToDrizzleSqlite<ConnectionRecord>(
|
|
263
|
+
{
|
|
264
|
+
connectionTypes: ['one'],
|
|
265
|
+
$not: {
|
|
266
|
+
$and: [
|
|
267
|
+
{
|
|
268
|
+
connectionTypes: ['two'],
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
connectionTypes: ['five'],
|
|
272
|
+
},
|
|
273
|
+
],
|
|
274
|
+
$or: [
|
|
275
|
+
{
|
|
276
|
+
connectionTypes: ['two'],
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
connectionTypes: ['three'],
|
|
280
|
+
},
|
|
281
|
+
],
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
didcommConnection
|
|
285
|
+
)
|
|
286
|
+
)
|
|
287
|
+
).toHaveLength(1)
|
|
288
|
+
|
|
289
|
+
expect(
|
|
290
|
+
await db
|
|
291
|
+
.select()
|
|
292
|
+
.from(didcommConnection)
|
|
293
|
+
.where(
|
|
294
|
+
queryToDrizzleSqlite<ConnectionRecord>(
|
|
295
|
+
{
|
|
296
|
+
connectionTypes: ['one'],
|
|
297
|
+
$not: {
|
|
298
|
+
$and: [
|
|
299
|
+
{
|
|
300
|
+
connectionTypes: ['two'],
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
connectionTypes: ['five'],
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
connectionTypes: ['three'],
|
|
307
|
+
},
|
|
308
|
+
],
|
|
309
|
+
$or: [
|
|
310
|
+
{
|
|
311
|
+
connectionTypes: ['two'],
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
connectionTypes: ['three'],
|
|
315
|
+
},
|
|
316
|
+
],
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
didcommConnection
|
|
320
|
+
)
|
|
321
|
+
)
|
|
322
|
+
).toHaveLength(0)
|
|
323
|
+
})
|
|
324
|
+
})
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { BaseRecord, Query, TagValue } from '@credo-ts/core'
|
|
2
|
+
import { SQL, SQLWrapper, and, eq, not, or, sql } from 'drizzle-orm'
|
|
3
|
+
import { PgColumn, pgTable } from 'drizzle-orm/pg-core'
|
|
4
|
+
import { CredoDrizzleStorageError } from '../error'
|
|
5
|
+
import { getPostgresBaseRecordTable } from '../postgres'
|
|
6
|
+
|
|
7
|
+
// We only support one layer of nesting at the moment for mapped keys
|
|
8
|
+
export type DrizzleCustomTagKeyMapping = Record<string, readonly [string, string]>
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Checks if a PostgreSQL array column contains all values from the given array
|
|
12
|
+
*
|
|
13
|
+
* @param column The array column to check
|
|
14
|
+
* @param values Array of values that should be contained in the column
|
|
15
|
+
* @returns SQL condition that checks if all values are in the array column
|
|
16
|
+
*/
|
|
17
|
+
function arrayContainsAll<T extends PgColumn>(column: T, values: unknown[]): SQL<unknown> {
|
|
18
|
+
if (values.length === 0) {
|
|
19
|
+
return sql`true` // Empty array always matches
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Instead of manually formatting, let Drizzle handle the parameter binding
|
|
23
|
+
// We create an array literal in PostgreSQL syntax and bind the values safely
|
|
24
|
+
return sql`to_jsonb(${column}) @> to_jsonb(array[${sql.join(
|
|
25
|
+
values.map((v) => sql`${v}`),
|
|
26
|
+
sql`, `
|
|
27
|
+
)}])`
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Checks if a JSONB array contains all values from a given array
|
|
32
|
+
*
|
|
33
|
+
* @param column The JSON/JSONB column to access
|
|
34
|
+
* @param paths Path segments to the JSON array property
|
|
35
|
+
* @param values Array of values to check for containment
|
|
36
|
+
* @returns SQL condition that checks if all values are contained in the array
|
|
37
|
+
*/
|
|
38
|
+
function jsonArrayContainsAll<T extends PgColumn>(column: T, field: string, values: unknown[]): SQL<unknown> {
|
|
39
|
+
if (values.length === 0) {
|
|
40
|
+
return sql`true` // Empty array always matches
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const path = sql`to_jsonb(${column})->'${sql.raw(field)}'`
|
|
44
|
+
|
|
45
|
+
// Create conditions for each value in the array
|
|
46
|
+
const conditions = values.map((value) => {
|
|
47
|
+
return sql`${path} @> ${sql`'[${sql.raw(JSON.stringify(value))}]'::jsonb`}`
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
// Combine all conditions with AND
|
|
51
|
+
return sql.join(conditions, sql` AND `)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function jsonEqual<T extends PgColumn>(column: T, field: string, value: TagValue) {
|
|
55
|
+
const valueType = typeof value === 'boolean' ? 'boolean' : typeof value === 'number' ? 'numeric' : 'text'
|
|
56
|
+
return sql`(${column} ->> '${sql.raw(field)}')::${sql.raw(valueType)} = ${value}`
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Converts a WQL object to Drizzle where conditions
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
64
|
+
export function queryToDrizzlePostgres<CredoRecord extends BaseRecord<any, any, any> = BaseRecord>(
|
|
65
|
+
query: Query<CredoRecord>,
|
|
66
|
+
table: ReturnType<typeof pgTable<string, ReturnType<typeof getPostgresBaseRecordTable>>>,
|
|
67
|
+
customTagKeyMapping?: DrizzleCustomTagKeyMapping
|
|
68
|
+
): SQL {
|
|
69
|
+
// Handle empty WQL
|
|
70
|
+
if (!query || Object.keys(query).length === 0) {
|
|
71
|
+
return sql`true`
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const conditions: Array<SQLWrapper> = []
|
|
75
|
+
|
|
76
|
+
// Process $or operator
|
|
77
|
+
if (query.$or && Array.isArray(query.$or) && query.$or.length > 0) {
|
|
78
|
+
const _$or = query.$or as Query<BaseRecord>[]
|
|
79
|
+
|
|
80
|
+
const orCondition = or(
|
|
81
|
+
..._$or.map((or) => queryToDrizzlePostgres(or, table, customTagKeyMapping)).filter((sql) => sql !== undefined)
|
|
82
|
+
)
|
|
83
|
+
if (orCondition) {
|
|
84
|
+
conditions.push(orCondition)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Process $and operator
|
|
89
|
+
if (query.$and && Array.isArray(query.$and) && query.$and.length > 0) {
|
|
90
|
+
const _$and = query.$and as Query<BaseRecord>[]
|
|
91
|
+
|
|
92
|
+
const andCondition = and(
|
|
93
|
+
..._$and.map((and) => queryToDrizzlePostgres(and, table, customTagKeyMapping)).filter((sql) => sql !== undefined)
|
|
94
|
+
)
|
|
95
|
+
if (andCondition) {
|
|
96
|
+
conditions.push(andCondition)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Process $not operator
|
|
101
|
+
if (query.$not) {
|
|
102
|
+
const notQuery = query.$not as Query<BaseRecord>
|
|
103
|
+
const notConditions: Array<SQLWrapper> = []
|
|
104
|
+
|
|
105
|
+
// Process $and within $not - all statements must be false
|
|
106
|
+
if (notQuery.$and && Array.isArray(notQuery.$and) && notQuery.$and.length > 0) {
|
|
107
|
+
const _$and = notQuery.$and as Query<BaseRecord>[]
|
|
108
|
+
|
|
109
|
+
// We need NOT(condition1 OR condition2 OR condition3)
|
|
110
|
+
// This is equivalent to NOT(condition1) AND NOT(condition2) AND NOT(condition3)
|
|
111
|
+
const andNotConditions = _$and
|
|
112
|
+
.map((andItem) => {
|
|
113
|
+
const condition = queryToDrizzlePostgres(andItem, table, customTagKeyMapping)
|
|
114
|
+
return condition ? not(condition) : undefined
|
|
115
|
+
})
|
|
116
|
+
.filter((condition) => condition !== undefined)
|
|
117
|
+
|
|
118
|
+
const andCondition = and(...andNotConditions)
|
|
119
|
+
if (andCondition) {
|
|
120
|
+
notConditions.push(andCondition)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Process $or within $not - at least one statement must be false
|
|
125
|
+
if (notQuery.$or && Array.isArray(notQuery.$or) && notQuery.$or.length > 0) {
|
|
126
|
+
const _$or = notQuery.$or as Query<BaseRecord>[]
|
|
127
|
+
|
|
128
|
+
// We need at least one false, so NOT(condition1 AND condition2 AND condition3)
|
|
129
|
+
const orCondition = and(
|
|
130
|
+
..._$or.map((orItem) => queryToDrizzlePostgres(orItem, table, customTagKeyMapping)).filter(Boolean)
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
if (orCondition) {
|
|
134
|
+
notConditions.push(not(orCondition))
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Process other fields in $not
|
|
139
|
+
for (const field in notQuery) {
|
|
140
|
+
if (field === '$not') {
|
|
141
|
+
throw new Error('Nested $not in $not is not supported')
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (field === '$or' || field === '$and') {
|
|
145
|
+
continue
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const condition = queryToDrizzlePostgres(
|
|
149
|
+
{ [field]: notQuery[field as keyof typeof notQuery] } as Query<BaseRecord>,
|
|
150
|
+
table,
|
|
151
|
+
customTagKeyMapping
|
|
152
|
+
)
|
|
153
|
+
if (condition) {
|
|
154
|
+
notConditions.push(not(condition))
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Combine all $not conditions with AND
|
|
159
|
+
const combinedNotCondition = notConditions.length === 1 ? notConditions[0] : and(...notConditions)
|
|
160
|
+
if (combinedNotCondition) {
|
|
161
|
+
conditions.push(combinedNotCondition)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Process regular field conditions
|
|
166
|
+
for (const field in query) {
|
|
167
|
+
// Skip special operators we've already handled
|
|
168
|
+
if (field === '$or' || field === '$and' || field === '$not') {
|
|
169
|
+
continue
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const value = query[field as keyof typeof query]
|
|
173
|
+
|
|
174
|
+
// Skip undefined values
|
|
175
|
+
if (value === undefined) continue
|
|
176
|
+
|
|
177
|
+
// Check if the field exists in the table
|
|
178
|
+
// In that case, query the column
|
|
179
|
+
if (field in table && table[field as keyof typeof table] instanceof PgColumn) {
|
|
180
|
+
const column = table[field as keyof typeof table] as PgColumn
|
|
181
|
+
if (Array.isArray(value)) {
|
|
182
|
+
conditions.push(arrayContainsAll(column, value))
|
|
183
|
+
} else {
|
|
184
|
+
conditions.push(eq(column, value))
|
|
185
|
+
}
|
|
186
|
+
} else {
|
|
187
|
+
// Check if field has a custom mapping
|
|
188
|
+
let targetField = field
|
|
189
|
+
let targetColumn: PgColumn = table.customTags
|
|
190
|
+
|
|
191
|
+
if (customTagKeyMapping && field in customTagKeyMapping) {
|
|
192
|
+
const mapping = customTagKeyMapping[field]
|
|
193
|
+
const [columnName, fieldName] = mapping
|
|
194
|
+
|
|
195
|
+
// Check if the mapped column exists in the table
|
|
196
|
+
if (columnName in table && table[columnName as keyof typeof table] instanceof PgColumn) {
|
|
197
|
+
targetColumn = table[columnName as keyof typeof table] as PgColumn
|
|
198
|
+
targetField = fieldName
|
|
199
|
+
} else {
|
|
200
|
+
throw new CredoDrizzleStorageError(
|
|
201
|
+
`Query defined custom mapping from key '${field}' to column ${columnName}, but the column does not exist in the table.`
|
|
202
|
+
)
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Handle custom tag or mapped field
|
|
207
|
+
if (Array.isArray(value)) {
|
|
208
|
+
conditions.push(jsonArrayContainsAll(targetColumn, targetField, value))
|
|
209
|
+
} else {
|
|
210
|
+
conditions.push(jsonEqual(targetColumn, targetField, value as TagValue))
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Combine all conditions with AND
|
|
216
|
+
return conditions.length === 1 ? conditions[0].getSQL() : (and(...conditions) ?? sql`true`)
|
|
217
|
+
}
|