@cipherstash/stack 0.1.0
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/CHANGELOG.md +7 -0
- package/LICENSE.md +21 -0
- package/README.md +670 -0
- package/dist/bin/stash.js +5049 -0
- package/dist/bin/stash.js.map +1 -0
- package/dist/chunk-2GZMIJFO.js +2400 -0
- package/dist/chunk-2GZMIJFO.js.map +1 -0
- package/dist/chunk-5DCT6YU2.js +138 -0
- package/dist/chunk-5DCT6YU2.js.map +1 -0
- package/dist/chunk-7XRPN2KX.js +336 -0
- package/dist/chunk-7XRPN2KX.js.map +1 -0
- package/dist/chunk-SJ7JO4ME.js +28 -0
- package/dist/chunk-SJ7JO4ME.js.map +1 -0
- package/dist/chunk-SUYMGQBY.js +67 -0
- package/dist/chunk-SUYMGQBY.js.map +1 -0
- package/dist/client-BxJG56Ey.d.cts +647 -0
- package/dist/client-DtGq9dJp.d.ts +647 -0
- package/dist/client.cjs +347 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +7 -0
- package/dist/client.d.ts +7 -0
- package/dist/client.js +11 -0
- package/dist/client.js.map +1 -0
- package/dist/drizzle/index.cjs +1528 -0
- package/dist/drizzle/index.cjs.map +1 -0
- package/dist/drizzle/index.d.cts +350 -0
- package/dist/drizzle/index.d.ts +350 -0
- package/dist/drizzle/index.js +1212 -0
- package/dist/drizzle/index.js.map +1 -0
- package/dist/dynamodb/index.cjs +382 -0
- package/dist/dynamodb/index.cjs.map +1 -0
- package/dist/dynamodb/index.d.cts +125 -0
- package/dist/dynamodb/index.d.ts +125 -0
- package/dist/dynamodb/index.js +355 -0
- package/dist/dynamodb/index.js.map +1 -0
- package/dist/identity/index.cjs +271 -0
- package/dist/identity/index.cjs.map +1 -0
- package/dist/identity/index.d.cts +3 -0
- package/dist/identity/index.d.ts +3 -0
- package/dist/identity/index.js +117 -0
- package/dist/identity/index.js.map +1 -0
- package/dist/index-9-Ya3fDK.d.cts +169 -0
- package/dist/index-9-Ya3fDK.d.ts +169 -0
- package/dist/index.cjs +2915 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +22 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/schema/index.cjs +368 -0
- package/dist/schema/index.cjs.map +1 -0
- package/dist/schema/index.d.cts +4 -0
- package/dist/schema/index.d.ts +4 -0
- package/dist/schema/index.js +23 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/secrets/index.cjs +3207 -0
- package/dist/secrets/index.cjs.map +1 -0
- package/dist/secrets/index.d.cts +227 -0
- package/dist/secrets/index.d.ts +227 -0
- package/dist/secrets/index.js +323 -0
- package/dist/secrets/index.js.map +1 -0
- package/dist/supabase/index.cjs +1113 -0
- package/dist/supabase/index.cjs.map +1 -0
- package/dist/supabase/index.d.cts +144 -0
- package/dist/supabase/index.d.ts +144 -0
- package/dist/supabase/index.js +864 -0
- package/dist/supabase/index.js.map +1 -0
- package/dist/types-public-BCj1L4fi.d.cts +1013 -0
- package/dist/types-public-BCj1L4fi.d.ts +1013 -0
- package/dist/types-public.cjs +40 -0
- package/dist/types-public.cjs.map +1 -0
- package/dist/types-public.d.cts +4 -0
- package/dist/types-public.d.ts +4 -0
- package/dist/types-public.js +7 -0
- package/dist/types-public.js.map +1 -0
- package/package.json +202 -0
|
@@ -0,0 +1,1528 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc2) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc2 = __getOwnPropDesc(from, key)) || desc2.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/drizzle/index.ts
|
|
21
|
+
var drizzle_exports = {};
|
|
22
|
+
__export(drizzle_exports, {
|
|
23
|
+
EncryptionConfigError: () => EncryptionConfigError,
|
|
24
|
+
EncryptionOperatorError: () => EncryptionOperatorError,
|
|
25
|
+
createEncryptionOperators: () => createEncryptionOperators,
|
|
26
|
+
encryptedType: () => encryptedType,
|
|
27
|
+
extractEncryptionSchema: () => extractEncryptionSchema,
|
|
28
|
+
getEncryptedColumnConfig: () => getEncryptedColumnConfig
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(drizzle_exports);
|
|
31
|
+
var import_pg_core = require("drizzle-orm/pg-core");
|
|
32
|
+
|
|
33
|
+
// src/schema/index.ts
|
|
34
|
+
var import_zod = require("zod");
|
|
35
|
+
var castAsEnum = import_zod.z.enum(["bigint", "boolean", "date", "number", "string", "json"]).default("string");
|
|
36
|
+
var tokenFilterSchema = import_zod.z.object({
|
|
37
|
+
kind: import_zod.z.literal("downcase")
|
|
38
|
+
});
|
|
39
|
+
var tokenizerSchema = import_zod.z.union([
|
|
40
|
+
import_zod.z.object({
|
|
41
|
+
kind: import_zod.z.literal("standard")
|
|
42
|
+
}),
|
|
43
|
+
import_zod.z.object({
|
|
44
|
+
kind: import_zod.z.literal("ngram"),
|
|
45
|
+
token_length: import_zod.z.number()
|
|
46
|
+
})
|
|
47
|
+
]).default({ kind: "ngram", token_length: 3 }).optional();
|
|
48
|
+
var oreIndexOptsSchema = import_zod.z.object({});
|
|
49
|
+
var uniqueIndexOptsSchema = import_zod.z.object({
|
|
50
|
+
token_filters: import_zod.z.array(tokenFilterSchema).default([]).optional()
|
|
51
|
+
});
|
|
52
|
+
var matchIndexOptsSchema = import_zod.z.object({
|
|
53
|
+
tokenizer: tokenizerSchema,
|
|
54
|
+
token_filters: import_zod.z.array(tokenFilterSchema).default([]).optional(),
|
|
55
|
+
k: import_zod.z.number().default(6).optional(),
|
|
56
|
+
m: import_zod.z.number().default(2048).optional(),
|
|
57
|
+
include_original: import_zod.z.boolean().default(false).optional()
|
|
58
|
+
});
|
|
59
|
+
var steVecIndexOptsSchema = import_zod.z.object({
|
|
60
|
+
prefix: import_zod.z.string()
|
|
61
|
+
});
|
|
62
|
+
var indexesSchema = import_zod.z.object({
|
|
63
|
+
ore: oreIndexOptsSchema.optional(),
|
|
64
|
+
unique: uniqueIndexOptsSchema.optional(),
|
|
65
|
+
match: matchIndexOptsSchema.optional(),
|
|
66
|
+
ste_vec: steVecIndexOptsSchema.optional()
|
|
67
|
+
}).default({});
|
|
68
|
+
var columnSchema = import_zod.z.object({
|
|
69
|
+
cast_as: castAsEnum,
|
|
70
|
+
indexes: indexesSchema
|
|
71
|
+
}).default({});
|
|
72
|
+
var tableSchema = import_zod.z.record(columnSchema).default({});
|
|
73
|
+
var tablesSchema = import_zod.z.record(tableSchema).default({});
|
|
74
|
+
var encryptConfigSchema = import_zod.z.object({
|
|
75
|
+
v: import_zod.z.number(),
|
|
76
|
+
tables: tablesSchema
|
|
77
|
+
});
|
|
78
|
+
var ProtectValue = class {
|
|
79
|
+
valueName;
|
|
80
|
+
castAsValue;
|
|
81
|
+
constructor(valueName) {
|
|
82
|
+
this.valueName = valueName;
|
|
83
|
+
this.castAsValue = "string";
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Set or override the plaintext data type for this value.
|
|
87
|
+
*
|
|
88
|
+
* By default all values are treated as `'string'`. Use this method to specify
|
|
89
|
+
* a different type so the encryption layer knows how to encode the plaintext
|
|
90
|
+
* before encrypting.
|
|
91
|
+
*
|
|
92
|
+
* @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'bigint'`, or `'json'`.
|
|
93
|
+
* @returns This `ProtectValue` instance for method chaining.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```typescript
|
|
97
|
+
* import { encryptedValue } from "@cipherstash/stack/schema"
|
|
98
|
+
*
|
|
99
|
+
* const age = encryptedValue("age").dataType("number")
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
dataType(castAs) {
|
|
103
|
+
this.castAsValue = castAs;
|
|
104
|
+
return this;
|
|
105
|
+
}
|
|
106
|
+
build() {
|
|
107
|
+
return {
|
|
108
|
+
cast_as: this.castAsValue,
|
|
109
|
+
indexes: {}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
getName() {
|
|
113
|
+
return this.valueName;
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
var ProtectColumn = class {
|
|
117
|
+
columnName;
|
|
118
|
+
castAsValue;
|
|
119
|
+
indexesValue = {};
|
|
120
|
+
constructor(columnName) {
|
|
121
|
+
this.columnName = columnName;
|
|
122
|
+
this.castAsValue = "string";
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Set or override the plaintext data type for this column.
|
|
126
|
+
*
|
|
127
|
+
* By default all columns are treated as `'string'`. Use this method to specify
|
|
128
|
+
* a different type so the encryption layer knows how to encode the plaintext
|
|
129
|
+
* before encrypting.
|
|
130
|
+
*
|
|
131
|
+
* @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'bigint'`, or `'json'`.
|
|
132
|
+
* @returns This `ProtectColumn` instance for method chaining.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```typescript
|
|
136
|
+
* import { encryptedColumn } from "@cipherstash/stack/schema"
|
|
137
|
+
*
|
|
138
|
+
* const dateOfBirth = encryptedColumn("date_of_birth").dataType("date")
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
dataType(castAs) {
|
|
142
|
+
this.castAsValue = castAs;
|
|
143
|
+
return this;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Enable Order-Revealing Encryption (ORE) indexing on this column.
|
|
147
|
+
*
|
|
148
|
+
* ORE allows sorting, comparison, and range queries on encrypted data.
|
|
149
|
+
* Use with `encryptQuery` and `queryType: 'orderAndRange'`.
|
|
150
|
+
*
|
|
151
|
+
* @returns This `ProtectColumn` instance for method chaining.
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```typescript
|
|
155
|
+
* import { encryptedTable, encryptedColumn } from "@cipherstash/stack/schema"
|
|
156
|
+
*
|
|
157
|
+
* const users = encryptedTable("users", {
|
|
158
|
+
* email: encryptedColumn("email").orderAndRange(),
|
|
159
|
+
* })
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
orderAndRange() {
|
|
163
|
+
this.indexesValue.ore = {};
|
|
164
|
+
return this;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Enable an exact-match (unique) index on this column.
|
|
168
|
+
*
|
|
169
|
+
* Allows equality queries on encrypted data. Use with `encryptQuery`
|
|
170
|
+
* and `queryType: 'equality'`.
|
|
171
|
+
*
|
|
172
|
+
* @param tokenFilters - Optional array of token filters (e.g. `[{ kind: 'downcase' }]`).
|
|
173
|
+
* When omitted, no token filters are applied.
|
|
174
|
+
* @returns This `ProtectColumn` instance for method chaining.
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```typescript
|
|
178
|
+
* import { encryptedTable, encryptedColumn } from "@cipherstash/stack/schema"
|
|
179
|
+
*
|
|
180
|
+
* const users = encryptedTable("users", {
|
|
181
|
+
* email: encryptedColumn("email").equality(),
|
|
182
|
+
* })
|
|
183
|
+
* ```
|
|
184
|
+
*/
|
|
185
|
+
equality(tokenFilters) {
|
|
186
|
+
this.indexesValue.unique = {
|
|
187
|
+
token_filters: tokenFilters ?? []
|
|
188
|
+
};
|
|
189
|
+
return this;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Enable a full-text / fuzzy search (match) index on this column.
|
|
193
|
+
*
|
|
194
|
+
* Uses n-gram tokenization by default for substring and fuzzy matching.
|
|
195
|
+
* Use with `encryptQuery` and `queryType: 'freeTextSearch'`.
|
|
196
|
+
*
|
|
197
|
+
* @param opts - Optional match index configuration. Defaults to 3-character ngram
|
|
198
|
+
* tokenization with a downcase filter, `k=6`, `m=2048`, and `include_original=true`.
|
|
199
|
+
* @returns This `ProtectColumn` instance for method chaining.
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```typescript
|
|
203
|
+
* import { encryptedTable, encryptedColumn } from "@cipherstash/stack/schema"
|
|
204
|
+
*
|
|
205
|
+
* const users = encryptedTable("users", {
|
|
206
|
+
* email: encryptedColumn("email").freeTextSearch(),
|
|
207
|
+
* })
|
|
208
|
+
*
|
|
209
|
+
* // With custom options
|
|
210
|
+
* const posts = encryptedTable("posts", {
|
|
211
|
+
* body: encryptedColumn("body").freeTextSearch({
|
|
212
|
+
* tokenizer: { kind: "ngram", token_length: 4 },
|
|
213
|
+
* k: 8,
|
|
214
|
+
* m: 4096,
|
|
215
|
+
* }),
|
|
216
|
+
* })
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
219
|
+
freeTextSearch(opts) {
|
|
220
|
+
this.indexesValue.match = {
|
|
221
|
+
tokenizer: opts?.tokenizer ?? { kind: "ngram", token_length: 3 },
|
|
222
|
+
token_filters: opts?.token_filters ?? [
|
|
223
|
+
{
|
|
224
|
+
kind: "downcase"
|
|
225
|
+
}
|
|
226
|
+
],
|
|
227
|
+
k: opts?.k ?? 6,
|
|
228
|
+
m: opts?.m ?? 2048,
|
|
229
|
+
include_original: opts?.include_original ?? true
|
|
230
|
+
};
|
|
231
|
+
return this;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Configure this column for searchable encrypted JSON (STE-Vec).
|
|
235
|
+
*
|
|
236
|
+
* Enables encrypted JSONPath selector queries (e.g. `'$.user.email'`) and
|
|
237
|
+
* containment queries (e.g. `{ role: 'admin' }`). Automatically sets the
|
|
238
|
+
* data type to `'json'`.
|
|
239
|
+
*
|
|
240
|
+
* When used with `encryptQuery`, the query operation is auto-inferred from
|
|
241
|
+
* the plaintext type: strings become selector queries, objects/arrays become
|
|
242
|
+
* containment queries.
|
|
243
|
+
*
|
|
244
|
+
* @returns This `ProtectColumn` instance for method chaining.
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* ```typescript
|
|
248
|
+
* import { encryptedTable, encryptedColumn } from "@cipherstash/stack/schema"
|
|
249
|
+
*
|
|
250
|
+
* const documents = encryptedTable("documents", {
|
|
251
|
+
* metadata: encryptedColumn("metadata").searchableJson(),
|
|
252
|
+
* })
|
|
253
|
+
* ```
|
|
254
|
+
*/
|
|
255
|
+
searchableJson() {
|
|
256
|
+
this.castAsValue = "json";
|
|
257
|
+
this.indexesValue.ste_vec = { prefix: "enabled" };
|
|
258
|
+
return this;
|
|
259
|
+
}
|
|
260
|
+
build() {
|
|
261
|
+
return {
|
|
262
|
+
cast_as: this.castAsValue,
|
|
263
|
+
indexes: this.indexesValue
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
getName() {
|
|
267
|
+
return this.columnName;
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
var ProtectTable = class {
|
|
271
|
+
constructor(tableName, columnBuilders) {
|
|
272
|
+
this.tableName = tableName;
|
|
273
|
+
this.columnBuilders = columnBuilders;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Compile this table schema into a `TableDefinition` used internally by the encryption client.
|
|
277
|
+
*
|
|
278
|
+
* Iterates over all column builders, calls `.build()` on each, and assembles
|
|
279
|
+
* the final `{ tableName, columns }` structure. For `searchableJson()` columns,
|
|
280
|
+
* the STE-Vec prefix is automatically set to `"<tableName>/<columnName>"`.
|
|
281
|
+
*
|
|
282
|
+
* @returns A `TableDefinition` containing the table name and built column configs.
|
|
283
|
+
*
|
|
284
|
+
* @example
|
|
285
|
+
* ```typescript
|
|
286
|
+
* const users = encryptedTable("users", {
|
|
287
|
+
* email: encryptedColumn("email").equality(),
|
|
288
|
+
* })
|
|
289
|
+
*
|
|
290
|
+
* const definition = users.build()
|
|
291
|
+
* // { tableName: "users", columns: { email: { cast_as: "string", indexes: { unique: ... } } } }
|
|
292
|
+
* ```
|
|
293
|
+
*/
|
|
294
|
+
build() {
|
|
295
|
+
const builtColumns = {};
|
|
296
|
+
const processColumn = (builder, colName) => {
|
|
297
|
+
if (builder instanceof ProtectColumn) {
|
|
298
|
+
const builtColumn = builder.build();
|
|
299
|
+
if (builtColumn.cast_as === "json" && builtColumn.indexes.ste_vec?.prefix === "enabled") {
|
|
300
|
+
builtColumns[colName] = {
|
|
301
|
+
...builtColumn,
|
|
302
|
+
indexes: {
|
|
303
|
+
...builtColumn.indexes,
|
|
304
|
+
ste_vec: {
|
|
305
|
+
prefix: `${this.tableName}/${colName}`
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
} else {
|
|
310
|
+
builtColumns[colName] = builtColumn;
|
|
311
|
+
}
|
|
312
|
+
} else {
|
|
313
|
+
for (const [key, value] of Object.entries(builder)) {
|
|
314
|
+
if (value instanceof ProtectValue) {
|
|
315
|
+
builtColumns[value.getName()] = value.build();
|
|
316
|
+
} else {
|
|
317
|
+
processColumn(value, key);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
for (const [colName, builder] of Object.entries(this.columnBuilders)) {
|
|
323
|
+
processColumn(builder, colName);
|
|
324
|
+
}
|
|
325
|
+
return {
|
|
326
|
+
tableName: this.tableName,
|
|
327
|
+
columns: builtColumns
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
function encryptedTable(tableName, columns) {
|
|
332
|
+
const tableBuilder = new ProtectTable(tableName, columns);
|
|
333
|
+
for (const [colName, colBuilder] of Object.entries(columns)) {
|
|
334
|
+
;
|
|
335
|
+
tableBuilder[colName] = colBuilder;
|
|
336
|
+
}
|
|
337
|
+
return tableBuilder;
|
|
338
|
+
}
|
|
339
|
+
function encryptedColumn(columnName) {
|
|
340
|
+
return new ProtectColumn(columnName);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// src/drizzle/schema-extraction.ts
|
|
344
|
+
function extractEncryptionSchema(table) {
|
|
345
|
+
const tableName = table[Symbol.for("drizzle:Name")];
|
|
346
|
+
if (!tableName) {
|
|
347
|
+
throw new Error(
|
|
348
|
+
"Unable to extract table name from Drizzle table. Ensure you are using a table created with pgTable()."
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
const columns = {};
|
|
352
|
+
for (const [columnName, column] of Object.entries(table)) {
|
|
353
|
+
if (typeof column !== "object" || column === null) {
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
const config = getEncryptedColumnConfig(columnName, column);
|
|
357
|
+
if (config) {
|
|
358
|
+
const actualColumnName = column.name || config.name;
|
|
359
|
+
const csCol = encryptedColumn(actualColumnName);
|
|
360
|
+
if (config.dataType && config.dataType !== "string") {
|
|
361
|
+
csCol.dataType(config.dataType);
|
|
362
|
+
}
|
|
363
|
+
if (config.orderAndRange) {
|
|
364
|
+
csCol.orderAndRange();
|
|
365
|
+
}
|
|
366
|
+
if (config.equality) {
|
|
367
|
+
if (Array.isArray(config.equality)) {
|
|
368
|
+
csCol.equality(config.equality);
|
|
369
|
+
} else {
|
|
370
|
+
csCol.equality();
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
if (config.freeTextSearch) {
|
|
374
|
+
if (typeof config.freeTextSearch === "object") {
|
|
375
|
+
csCol.freeTextSearch(config.freeTextSearch);
|
|
376
|
+
} else {
|
|
377
|
+
csCol.freeTextSearch();
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
if (config.searchableJson) {
|
|
381
|
+
if (config.dataType !== "json") {
|
|
382
|
+
throw new Error(
|
|
383
|
+
`Column "${columnName}" has searchableJson enabled but dataType is "${config.dataType ?? "string"}". searchableJson requires dataType: 'json'.`
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
csCol.searchableJson();
|
|
387
|
+
}
|
|
388
|
+
columns[actualColumnName] = csCol;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
if (Object.keys(columns).length === 0) {
|
|
392
|
+
throw new Error(
|
|
393
|
+
`No encrypted columns found in table "${tableName}". Use encryptedType() to define encrypted columns.`
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
return encryptedTable(tableName, columns);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// src/types.ts
|
|
400
|
+
var queryTypes = {
|
|
401
|
+
orderAndRange: "orderAndRange",
|
|
402
|
+
freeTextSearch: "freeTextSearch",
|
|
403
|
+
equality: "equality",
|
|
404
|
+
steVecSelector: "steVecSelector",
|
|
405
|
+
steVecTerm: "steVecTerm",
|
|
406
|
+
searchableJson: "searchableJson"
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
// src/drizzle/operators.ts
|
|
410
|
+
var import_drizzle_orm = require("drizzle-orm");
|
|
411
|
+
var import_drizzle_orm2 = require("drizzle-orm");
|
|
412
|
+
function isSQLWrapper(value) {
|
|
413
|
+
return typeof value === "object" && value !== null && "sql" in value && typeof value.sql !== "undefined";
|
|
414
|
+
}
|
|
415
|
+
function isPgTable(value) {
|
|
416
|
+
return typeof value === "object" && value !== null && Symbol.for("drizzle:Name") in value;
|
|
417
|
+
}
|
|
418
|
+
var EncryptionOperatorError = class extends Error {
|
|
419
|
+
constructor(message, context) {
|
|
420
|
+
super(message);
|
|
421
|
+
this.context = context;
|
|
422
|
+
this.name = "EncryptionOperatorError";
|
|
423
|
+
}
|
|
424
|
+
};
|
|
425
|
+
var EncryptionConfigError = class extends EncryptionOperatorError {
|
|
426
|
+
constructor(message, context) {
|
|
427
|
+
super(message, context);
|
|
428
|
+
this.name = "EncryptionConfigError";
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
function getDrizzleTableName(drizzleTable) {
|
|
432
|
+
if (!isPgTable(drizzleTable)) {
|
|
433
|
+
return void 0;
|
|
434
|
+
}
|
|
435
|
+
const tableWithSymbol = drizzleTable;
|
|
436
|
+
return tableWithSymbol[Symbol.for("drizzle:Name")];
|
|
437
|
+
}
|
|
438
|
+
function getDrizzleTableFromColumn(drizzleColumn) {
|
|
439
|
+
const column = drizzleColumn;
|
|
440
|
+
return column.table;
|
|
441
|
+
}
|
|
442
|
+
function getEncryptedTableFromColumn(drizzleColumn, tableCache) {
|
|
443
|
+
const drizzleTable = getDrizzleTableFromColumn(drizzleColumn);
|
|
444
|
+
if (!drizzleTable) {
|
|
445
|
+
return void 0;
|
|
446
|
+
}
|
|
447
|
+
const tableName = getDrizzleTableName(drizzleTable);
|
|
448
|
+
if (!tableName) {
|
|
449
|
+
return void 0;
|
|
450
|
+
}
|
|
451
|
+
let encryptedTable2 = tableCache.get(tableName);
|
|
452
|
+
if (encryptedTable2) {
|
|
453
|
+
return encryptedTable2;
|
|
454
|
+
}
|
|
455
|
+
try {
|
|
456
|
+
encryptedTable2 = extractEncryptionSchema(drizzleTable);
|
|
457
|
+
tableCache.set(tableName, encryptedTable2);
|
|
458
|
+
return encryptedTable2;
|
|
459
|
+
} catch {
|
|
460
|
+
return void 0;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
function getEncryptedColumn(drizzleColumn, encryptedTable2) {
|
|
464
|
+
const column = drizzleColumn;
|
|
465
|
+
const columnName = column.name;
|
|
466
|
+
if (!columnName) {
|
|
467
|
+
return void 0;
|
|
468
|
+
}
|
|
469
|
+
const tableRecord = encryptedTable2;
|
|
470
|
+
return tableRecord[columnName];
|
|
471
|
+
}
|
|
472
|
+
function getColumnInfo(drizzleColumn, encryptedTable2, tableCache) {
|
|
473
|
+
const column = drizzleColumn;
|
|
474
|
+
const columnName = column.name || "unknown";
|
|
475
|
+
let resolvedTable = encryptedTable2;
|
|
476
|
+
if (!resolvedTable) {
|
|
477
|
+
resolvedTable = getEncryptedTableFromColumn(drizzleColumn, tableCache);
|
|
478
|
+
}
|
|
479
|
+
const drizzleTable = getDrizzleTableFromColumn(drizzleColumn);
|
|
480
|
+
const tableName = getDrizzleTableName(drizzleTable);
|
|
481
|
+
if (!resolvedTable) {
|
|
482
|
+
const config2 = getEncryptedColumnConfig(columnName, drizzleColumn);
|
|
483
|
+
return {
|
|
484
|
+
encryptedColumn: void 0,
|
|
485
|
+
config: config2,
|
|
486
|
+
encryptedTable: void 0,
|
|
487
|
+
columnName,
|
|
488
|
+
tableName
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
const encryptedColumn2 = getEncryptedColumn(drizzleColumn, resolvedTable);
|
|
492
|
+
const config = getEncryptedColumnConfig(columnName, drizzleColumn);
|
|
493
|
+
return {
|
|
494
|
+
encryptedColumn: encryptedColumn2,
|
|
495
|
+
config,
|
|
496
|
+
encryptedTable: resolvedTable,
|
|
497
|
+
columnName,
|
|
498
|
+
tableName
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
function toPlaintext(value) {
|
|
502
|
+
if (typeof value === "boolean") {
|
|
503
|
+
return value ? 1 : 0;
|
|
504
|
+
}
|
|
505
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
506
|
+
return value;
|
|
507
|
+
}
|
|
508
|
+
if (value instanceof Date) {
|
|
509
|
+
return value.toISOString();
|
|
510
|
+
}
|
|
511
|
+
return String(value);
|
|
512
|
+
}
|
|
513
|
+
async function encryptValues(encryptionClient, values, encryptedTable2, tableCache) {
|
|
514
|
+
if (values.length === 0) {
|
|
515
|
+
return [];
|
|
516
|
+
}
|
|
517
|
+
const valuesToEncrypt = [];
|
|
518
|
+
const results = new Array(values.length);
|
|
519
|
+
for (let i = 0; i < values.length; i++) {
|
|
520
|
+
const { value, column, queryType } = values[i];
|
|
521
|
+
const columnInfo = getColumnInfo(column, encryptedTable2, tableCache);
|
|
522
|
+
if (!columnInfo.encryptedColumn || !columnInfo.config || !columnInfo.encryptedTable) {
|
|
523
|
+
results[i] = value;
|
|
524
|
+
continue;
|
|
525
|
+
}
|
|
526
|
+
const plaintextValue = toPlaintext(value);
|
|
527
|
+
valuesToEncrypt.push({
|
|
528
|
+
value: plaintextValue,
|
|
529
|
+
column,
|
|
530
|
+
columnInfo,
|
|
531
|
+
queryType,
|
|
532
|
+
originalIndex: i
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
if (valuesToEncrypt.length === 0) {
|
|
536
|
+
return results;
|
|
537
|
+
}
|
|
538
|
+
const columnGroups = /* @__PURE__ */ new Map();
|
|
539
|
+
let valueIndex = 0;
|
|
540
|
+
for (const {
|
|
541
|
+
value,
|
|
542
|
+
columnInfo,
|
|
543
|
+
queryType,
|
|
544
|
+
originalIndex
|
|
545
|
+
} of valuesToEncrypt) {
|
|
546
|
+
if (!columnInfo.config || !columnInfo.encryptedColumn || !columnInfo.encryptedTable) {
|
|
547
|
+
continue;
|
|
548
|
+
}
|
|
549
|
+
const columnName = columnInfo.config.name;
|
|
550
|
+
const groupKey = `${columnInfo.tableName ?? "unknown"}/${columnName}`;
|
|
551
|
+
let group = columnGroups.get(groupKey);
|
|
552
|
+
if (!group) {
|
|
553
|
+
group = {
|
|
554
|
+
column: columnInfo.encryptedColumn,
|
|
555
|
+
table: columnInfo.encryptedTable,
|
|
556
|
+
columnName,
|
|
557
|
+
values: [],
|
|
558
|
+
resultIndices: []
|
|
559
|
+
};
|
|
560
|
+
columnGroups.set(groupKey, group);
|
|
561
|
+
}
|
|
562
|
+
group.values.push({ value, index: valueIndex++, queryType });
|
|
563
|
+
group.resultIndices.push(originalIndex);
|
|
564
|
+
}
|
|
565
|
+
for (const [, group] of columnGroups) {
|
|
566
|
+
const { columnName } = group;
|
|
567
|
+
try {
|
|
568
|
+
const terms = group.values.map((v) => ({
|
|
569
|
+
value: v.value,
|
|
570
|
+
column: group.column,
|
|
571
|
+
table: group.table,
|
|
572
|
+
queryType: v.queryType
|
|
573
|
+
}));
|
|
574
|
+
const encryptedTerms = await encryptionClient.encryptQuery(terms);
|
|
575
|
+
if (encryptedTerms.failure) {
|
|
576
|
+
throw new EncryptionOperatorError(
|
|
577
|
+
`Failed to encrypt query terms for column "${columnName}": ${encryptedTerms.failure.message}`,
|
|
578
|
+
{ columnName }
|
|
579
|
+
);
|
|
580
|
+
}
|
|
581
|
+
for (let i = 0; i < group.values.length; i++) {
|
|
582
|
+
const resultIndex = group.resultIndices[i] ?? -1;
|
|
583
|
+
if (resultIndex >= 0 && resultIndex < results.length) {
|
|
584
|
+
results[resultIndex] = encryptedTerms.data[i];
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
} catch (error) {
|
|
588
|
+
if (error instanceof EncryptionOperatorError) {
|
|
589
|
+
throw error;
|
|
590
|
+
}
|
|
591
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
592
|
+
throw new EncryptionOperatorError(
|
|
593
|
+
`Unexpected error encrypting values for column "${columnName}": ${errorMessage}`,
|
|
594
|
+
{ columnName }
|
|
595
|
+
);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
return results;
|
|
599
|
+
}
|
|
600
|
+
async function encryptValue(encryptionClient, value, drizzleColumn, encryptedTable2, tableCache, queryType) {
|
|
601
|
+
const results = await encryptValues(
|
|
602
|
+
encryptionClient,
|
|
603
|
+
[{ value, column: drizzleColumn, queryType }],
|
|
604
|
+
encryptedTable2,
|
|
605
|
+
tableCache
|
|
606
|
+
);
|
|
607
|
+
return results[0];
|
|
608
|
+
}
|
|
609
|
+
function isLazyOperator(value) {
|
|
610
|
+
return typeof value === "object" && value !== null && "__isLazyOperator" in value && value.__isLazyOperator === true;
|
|
611
|
+
}
|
|
612
|
+
function createLazyOperator(operator, left, right, execute, needsEncryption, columnInfo, encryptionClient, defaultTable, tableCache, min, max, queryType) {
|
|
613
|
+
let resolvedSQL;
|
|
614
|
+
let encryptionPromise;
|
|
615
|
+
const lazyOp = {
|
|
616
|
+
__isLazyOperator: true,
|
|
617
|
+
operator,
|
|
618
|
+
queryType,
|
|
619
|
+
left,
|
|
620
|
+
right,
|
|
621
|
+
min,
|
|
622
|
+
max,
|
|
623
|
+
needsEncryption,
|
|
624
|
+
columnInfo,
|
|
625
|
+
execute
|
|
626
|
+
};
|
|
627
|
+
const promise = new Promise((resolve, reject) => {
|
|
628
|
+
queueMicrotask(async () => {
|
|
629
|
+
if (resolvedSQL !== void 0) {
|
|
630
|
+
resolve(resolvedSQL);
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
try {
|
|
634
|
+
if (!encryptionPromise) {
|
|
635
|
+
encryptionPromise = executeLazyOperatorDirect(
|
|
636
|
+
lazyOp,
|
|
637
|
+
encryptionClient,
|
|
638
|
+
defaultTable,
|
|
639
|
+
tableCache
|
|
640
|
+
);
|
|
641
|
+
}
|
|
642
|
+
const sql2 = await encryptionPromise;
|
|
643
|
+
resolvedSQL = sql2;
|
|
644
|
+
resolve(sql2);
|
|
645
|
+
} catch (error) {
|
|
646
|
+
reject(error);
|
|
647
|
+
}
|
|
648
|
+
});
|
|
649
|
+
});
|
|
650
|
+
return Object.assign(promise, lazyOp);
|
|
651
|
+
}
|
|
652
|
+
async function executeLazyOperator(lazyOp, encryptedValues) {
|
|
653
|
+
if (!lazyOp.needsEncryption) {
|
|
654
|
+
return lazyOp.execute(lazyOp.right);
|
|
655
|
+
}
|
|
656
|
+
if (lazyOp.min !== void 0 && lazyOp.max !== void 0) {
|
|
657
|
+
let encryptedMin;
|
|
658
|
+
let encryptedMax;
|
|
659
|
+
if (encryptedValues && encryptedValues.length >= 2) {
|
|
660
|
+
encryptedMin = encryptedValues[0]?.encrypted;
|
|
661
|
+
encryptedMax = encryptedValues[1]?.encrypted;
|
|
662
|
+
} else {
|
|
663
|
+
throw new EncryptionOperatorError(
|
|
664
|
+
"Between operator requires both min and max encrypted values",
|
|
665
|
+
{
|
|
666
|
+
columnName: lazyOp.columnInfo.columnName,
|
|
667
|
+
tableName: lazyOp.columnInfo.tableName,
|
|
668
|
+
operator: lazyOp.operator
|
|
669
|
+
}
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
if (encryptedMin === void 0 || encryptedMax === void 0) {
|
|
673
|
+
throw new EncryptionOperatorError(
|
|
674
|
+
"Between operator requires both min and max values to be encrypted",
|
|
675
|
+
{
|
|
676
|
+
columnName: lazyOp.columnInfo.columnName,
|
|
677
|
+
tableName: lazyOp.columnInfo.tableName,
|
|
678
|
+
operator: lazyOp.operator
|
|
679
|
+
}
|
|
680
|
+
);
|
|
681
|
+
}
|
|
682
|
+
return lazyOp.execute(void 0, encryptedMin, encryptedMax);
|
|
683
|
+
}
|
|
684
|
+
let encrypted;
|
|
685
|
+
if (encryptedValues && encryptedValues.length > 0) {
|
|
686
|
+
encrypted = encryptedValues[0]?.encrypted;
|
|
687
|
+
} else {
|
|
688
|
+
throw new EncryptionOperatorError(
|
|
689
|
+
"Operator requires encrypted value but none provided",
|
|
690
|
+
{
|
|
691
|
+
columnName: lazyOp.columnInfo.columnName,
|
|
692
|
+
tableName: lazyOp.columnInfo.tableName,
|
|
693
|
+
operator: lazyOp.operator
|
|
694
|
+
}
|
|
695
|
+
);
|
|
696
|
+
}
|
|
697
|
+
if (encrypted === void 0) {
|
|
698
|
+
throw new EncryptionOperatorError(
|
|
699
|
+
"Encryption failed or value was not encrypted",
|
|
700
|
+
{
|
|
701
|
+
columnName: lazyOp.columnInfo.columnName,
|
|
702
|
+
tableName: lazyOp.columnInfo.tableName,
|
|
703
|
+
operator: lazyOp.operator
|
|
704
|
+
}
|
|
705
|
+
);
|
|
706
|
+
}
|
|
707
|
+
return lazyOp.execute(encrypted);
|
|
708
|
+
}
|
|
709
|
+
async function executeLazyOperatorDirect(lazyOp, encryptionClient, defaultTable, tableCache) {
|
|
710
|
+
if (!lazyOp.needsEncryption) {
|
|
711
|
+
return lazyOp.execute(lazyOp.right);
|
|
712
|
+
}
|
|
713
|
+
if (lazyOp.min !== void 0 && lazyOp.max !== void 0) {
|
|
714
|
+
const [encryptedMin, encryptedMax] = await encryptValues(
|
|
715
|
+
encryptionClient,
|
|
716
|
+
[
|
|
717
|
+
{ value: lazyOp.min, column: lazyOp.left, queryType: lazyOp.queryType },
|
|
718
|
+
{ value: lazyOp.max, column: lazyOp.left, queryType: lazyOp.queryType }
|
|
719
|
+
],
|
|
720
|
+
defaultTable,
|
|
721
|
+
tableCache
|
|
722
|
+
);
|
|
723
|
+
return lazyOp.execute(void 0, encryptedMin, encryptedMax);
|
|
724
|
+
}
|
|
725
|
+
const encrypted = await encryptValue(
|
|
726
|
+
encryptionClient,
|
|
727
|
+
lazyOp.right,
|
|
728
|
+
lazyOp.left,
|
|
729
|
+
defaultTable,
|
|
730
|
+
tableCache,
|
|
731
|
+
lazyOp.queryType
|
|
732
|
+
);
|
|
733
|
+
return lazyOp.execute(encrypted);
|
|
734
|
+
}
|
|
735
|
+
function createComparisonOperator(operator, left, right, columnInfo, encryptionClient, defaultTable, tableCache) {
|
|
736
|
+
const { config } = columnInfo;
|
|
737
|
+
const requiresOrderAndRange = ["gt", "gte", "lt", "lte"].includes(operator);
|
|
738
|
+
if (requiresOrderAndRange) {
|
|
739
|
+
if (!config?.orderAndRange) {
|
|
740
|
+
switch (operator) {
|
|
741
|
+
case "gt":
|
|
742
|
+
return (0, import_drizzle_orm.gt)(left, right);
|
|
743
|
+
case "gte":
|
|
744
|
+
return (0, import_drizzle_orm.gte)(left, right);
|
|
745
|
+
case "lt":
|
|
746
|
+
return (0, import_drizzle_orm.lt)(left, right);
|
|
747
|
+
case "lte":
|
|
748
|
+
return (0, import_drizzle_orm.lte)(left, right);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
const executeFn = (encrypted) => {
|
|
752
|
+
if (encrypted === void 0) {
|
|
753
|
+
throw new EncryptionOperatorError(
|
|
754
|
+
`Encryption failed for ${operator} operator`,
|
|
755
|
+
{
|
|
756
|
+
columnName: columnInfo.columnName,
|
|
757
|
+
tableName: columnInfo.tableName,
|
|
758
|
+
operator
|
|
759
|
+
}
|
|
760
|
+
);
|
|
761
|
+
}
|
|
762
|
+
return import_drizzle_orm2.sql`eql_v2.${import_drizzle_orm2.sql.raw(operator)}(${left}, ${(0, import_drizzle_orm2.bindIfParam)(encrypted, left)})`;
|
|
763
|
+
};
|
|
764
|
+
return createLazyOperator(
|
|
765
|
+
operator,
|
|
766
|
+
left,
|
|
767
|
+
right,
|
|
768
|
+
executeFn,
|
|
769
|
+
true,
|
|
770
|
+
columnInfo,
|
|
771
|
+
encryptionClient,
|
|
772
|
+
defaultTable,
|
|
773
|
+
tableCache,
|
|
774
|
+
void 0,
|
|
775
|
+
// min
|
|
776
|
+
void 0,
|
|
777
|
+
// max
|
|
778
|
+
queryTypes.orderAndRange
|
|
779
|
+
);
|
|
780
|
+
}
|
|
781
|
+
const requiresEquality = ["eq", "ne"].includes(operator);
|
|
782
|
+
if (requiresEquality && config?.equality) {
|
|
783
|
+
const executeFn = (encrypted) => {
|
|
784
|
+
if (encrypted === void 0) {
|
|
785
|
+
throw new EncryptionOperatorError(
|
|
786
|
+
`Encryption failed for ${operator} operator`,
|
|
787
|
+
{
|
|
788
|
+
columnName: columnInfo.columnName,
|
|
789
|
+
tableName: columnInfo.tableName,
|
|
790
|
+
operator
|
|
791
|
+
}
|
|
792
|
+
);
|
|
793
|
+
}
|
|
794
|
+
return operator === "eq" ? (0, import_drizzle_orm.eq)(left, encrypted) : (0, import_drizzle_orm.ne)(left, encrypted);
|
|
795
|
+
};
|
|
796
|
+
return createLazyOperator(
|
|
797
|
+
operator,
|
|
798
|
+
left,
|
|
799
|
+
right,
|
|
800
|
+
executeFn,
|
|
801
|
+
true,
|
|
802
|
+
columnInfo,
|
|
803
|
+
encryptionClient,
|
|
804
|
+
defaultTable,
|
|
805
|
+
tableCache,
|
|
806
|
+
void 0,
|
|
807
|
+
// min
|
|
808
|
+
void 0,
|
|
809
|
+
// max
|
|
810
|
+
queryTypes.equality
|
|
811
|
+
);
|
|
812
|
+
}
|
|
813
|
+
return operator === "eq" ? (0, import_drizzle_orm.eq)(left, right) : (0, import_drizzle_orm.ne)(left, right);
|
|
814
|
+
}
|
|
815
|
+
function createRangeOperator(operator, left, min, max, columnInfo, encryptionClient, defaultTable, tableCache) {
|
|
816
|
+
const { config } = columnInfo;
|
|
817
|
+
if (!config?.orderAndRange) {
|
|
818
|
+
return operator === "between" ? (0, import_drizzle_orm.between)(left, min, max) : (0, import_drizzle_orm.notBetween)(left, min, max);
|
|
819
|
+
}
|
|
820
|
+
const executeFn = (_encrypted, encryptedMin, encryptedMax) => {
|
|
821
|
+
if (encryptedMin === void 0 || encryptedMax === void 0) {
|
|
822
|
+
throw new EncryptionOperatorError(
|
|
823
|
+
`${operator} operator requires both min and max values`,
|
|
824
|
+
{
|
|
825
|
+
columnName: columnInfo.columnName,
|
|
826
|
+
tableName: columnInfo.tableName,
|
|
827
|
+
operator
|
|
828
|
+
}
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
const rangeCondition = import_drizzle_orm2.sql`eql_v2.gte(${left}, ${(0, import_drizzle_orm2.bindIfParam)(encryptedMin, left)}) AND eql_v2.lte(${left}, ${(0, import_drizzle_orm2.bindIfParam)(encryptedMax, left)})`;
|
|
832
|
+
return operator === "between" ? rangeCondition : import_drizzle_orm2.sql`NOT (${rangeCondition})`;
|
|
833
|
+
};
|
|
834
|
+
return createLazyOperator(
|
|
835
|
+
operator,
|
|
836
|
+
left,
|
|
837
|
+
void 0,
|
|
838
|
+
executeFn,
|
|
839
|
+
true,
|
|
840
|
+
columnInfo,
|
|
841
|
+
encryptionClient,
|
|
842
|
+
defaultTable,
|
|
843
|
+
tableCache,
|
|
844
|
+
min,
|
|
845
|
+
max,
|
|
846
|
+
queryTypes.orderAndRange
|
|
847
|
+
);
|
|
848
|
+
}
|
|
849
|
+
function createTextSearchOperator(operator, left, right, columnInfo, encryptionClient, defaultTable, tableCache) {
|
|
850
|
+
const { config } = columnInfo;
|
|
851
|
+
if (!config?.freeTextSearch) {
|
|
852
|
+
const rightValue = right;
|
|
853
|
+
switch (operator) {
|
|
854
|
+
case "like":
|
|
855
|
+
return (0, import_drizzle_orm.like)(left, rightValue);
|
|
856
|
+
case "ilike":
|
|
857
|
+
return (0, import_drizzle_orm.ilike)(left, rightValue);
|
|
858
|
+
case "notIlike":
|
|
859
|
+
return (0, import_drizzle_orm.notIlike)(left, rightValue);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
const executeFn = (encrypted) => {
|
|
863
|
+
if (encrypted === void 0) {
|
|
864
|
+
throw new EncryptionOperatorError(
|
|
865
|
+
`Encryption failed for ${operator} operator`,
|
|
866
|
+
{
|
|
867
|
+
columnName: columnInfo.columnName,
|
|
868
|
+
tableName: columnInfo.tableName,
|
|
869
|
+
operator
|
|
870
|
+
}
|
|
871
|
+
);
|
|
872
|
+
}
|
|
873
|
+
const sqlFn = import_drizzle_orm2.sql`eql_v2.${import_drizzle_orm2.sql.raw(operator === "notIlike" ? "ilike" : operator)}(${left}, ${(0, import_drizzle_orm2.bindIfParam)(encrypted, left)})`;
|
|
874
|
+
return operator === "notIlike" ? import_drizzle_orm2.sql`NOT (${sqlFn})` : sqlFn;
|
|
875
|
+
};
|
|
876
|
+
return createLazyOperator(
|
|
877
|
+
operator,
|
|
878
|
+
left,
|
|
879
|
+
right,
|
|
880
|
+
executeFn,
|
|
881
|
+
true,
|
|
882
|
+
columnInfo,
|
|
883
|
+
encryptionClient,
|
|
884
|
+
defaultTable,
|
|
885
|
+
tableCache,
|
|
886
|
+
void 0,
|
|
887
|
+
// min
|
|
888
|
+
void 0,
|
|
889
|
+
// max
|
|
890
|
+
queryTypes.freeTextSearch
|
|
891
|
+
);
|
|
892
|
+
}
|
|
893
|
+
function createJsonbOperator(operator, left, right, columnInfo, encryptionClient, defaultTable, tableCache) {
|
|
894
|
+
const { config } = columnInfo;
|
|
895
|
+
const encryptedSelector = (value) => import_drizzle_orm2.sql`${(0, import_drizzle_orm2.bindIfParam)(value, left)}::eql_v2_encrypted`;
|
|
896
|
+
if (!config?.searchableJson) {
|
|
897
|
+
throw new EncryptionOperatorError(
|
|
898
|
+
`The ${operator} operator requires searchableJson to be enabled on the column configuration.`,
|
|
899
|
+
{
|
|
900
|
+
columnName: columnInfo.columnName,
|
|
901
|
+
tableName: columnInfo.tableName,
|
|
902
|
+
operator
|
|
903
|
+
}
|
|
904
|
+
);
|
|
905
|
+
}
|
|
906
|
+
const executeFn = (encrypted) => {
|
|
907
|
+
if (encrypted === void 0) {
|
|
908
|
+
throw new EncryptionOperatorError(
|
|
909
|
+
`Encryption failed for ${operator} operator`,
|
|
910
|
+
{
|
|
911
|
+
columnName: columnInfo.columnName,
|
|
912
|
+
tableName: columnInfo.tableName,
|
|
913
|
+
operator
|
|
914
|
+
}
|
|
915
|
+
);
|
|
916
|
+
}
|
|
917
|
+
switch (operator) {
|
|
918
|
+
case "jsonbPathQueryFirst":
|
|
919
|
+
return import_drizzle_orm2.sql`eql_v2.jsonb_path_query_first(${left}, ${encryptedSelector(encrypted)})`;
|
|
920
|
+
case "jsonbGet":
|
|
921
|
+
return import_drizzle_orm2.sql`${left} -> ${encryptedSelector(encrypted)}`;
|
|
922
|
+
case "jsonbPathExists":
|
|
923
|
+
return import_drizzle_orm2.sql`eql_v2.jsonb_path_exists(${left}, ${encryptedSelector(encrypted)})`;
|
|
924
|
+
}
|
|
925
|
+
};
|
|
926
|
+
return createLazyOperator(
|
|
927
|
+
operator,
|
|
928
|
+
left,
|
|
929
|
+
right,
|
|
930
|
+
executeFn,
|
|
931
|
+
true,
|
|
932
|
+
columnInfo,
|
|
933
|
+
encryptionClient,
|
|
934
|
+
defaultTable,
|
|
935
|
+
tableCache,
|
|
936
|
+
void 0,
|
|
937
|
+
void 0,
|
|
938
|
+
queryTypes.steVecSelector
|
|
939
|
+
);
|
|
940
|
+
}
|
|
941
|
+
function createEncryptionOperators(encryptionClient) {
|
|
942
|
+
const tableCache = /* @__PURE__ */ new Map();
|
|
943
|
+
const defaultTable = void 0;
|
|
944
|
+
const encryptedEq = (left, right) => {
|
|
945
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
946
|
+
return createComparisonOperator(
|
|
947
|
+
"eq",
|
|
948
|
+
left,
|
|
949
|
+
right,
|
|
950
|
+
columnInfo,
|
|
951
|
+
encryptionClient,
|
|
952
|
+
defaultTable,
|
|
953
|
+
tableCache
|
|
954
|
+
);
|
|
955
|
+
};
|
|
956
|
+
const encryptedNe = (left, right) => {
|
|
957
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
958
|
+
return createComparisonOperator(
|
|
959
|
+
"ne",
|
|
960
|
+
left,
|
|
961
|
+
right,
|
|
962
|
+
columnInfo,
|
|
963
|
+
encryptionClient,
|
|
964
|
+
defaultTable,
|
|
965
|
+
tableCache
|
|
966
|
+
);
|
|
967
|
+
};
|
|
968
|
+
const encryptedGt = (left, right) => {
|
|
969
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
970
|
+
return createComparisonOperator(
|
|
971
|
+
"gt",
|
|
972
|
+
left,
|
|
973
|
+
right,
|
|
974
|
+
columnInfo,
|
|
975
|
+
encryptionClient,
|
|
976
|
+
defaultTable,
|
|
977
|
+
tableCache
|
|
978
|
+
);
|
|
979
|
+
};
|
|
980
|
+
const encryptedGte = (left, right) => {
|
|
981
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
982
|
+
return createComparisonOperator(
|
|
983
|
+
"gte",
|
|
984
|
+
left,
|
|
985
|
+
right,
|
|
986
|
+
columnInfo,
|
|
987
|
+
encryptionClient,
|
|
988
|
+
defaultTable,
|
|
989
|
+
tableCache
|
|
990
|
+
);
|
|
991
|
+
};
|
|
992
|
+
const encryptedLt = (left, right) => {
|
|
993
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
994
|
+
return createComparisonOperator(
|
|
995
|
+
"lt",
|
|
996
|
+
left,
|
|
997
|
+
right,
|
|
998
|
+
columnInfo,
|
|
999
|
+
encryptionClient,
|
|
1000
|
+
defaultTable,
|
|
1001
|
+
tableCache
|
|
1002
|
+
);
|
|
1003
|
+
};
|
|
1004
|
+
const encryptedLte = (left, right) => {
|
|
1005
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
1006
|
+
return createComparisonOperator(
|
|
1007
|
+
"lte",
|
|
1008
|
+
left,
|
|
1009
|
+
right,
|
|
1010
|
+
columnInfo,
|
|
1011
|
+
encryptionClient,
|
|
1012
|
+
defaultTable,
|
|
1013
|
+
tableCache
|
|
1014
|
+
);
|
|
1015
|
+
};
|
|
1016
|
+
const encryptedBetween = (left, min, max) => {
|
|
1017
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
1018
|
+
return createRangeOperator(
|
|
1019
|
+
"between",
|
|
1020
|
+
left,
|
|
1021
|
+
min,
|
|
1022
|
+
max,
|
|
1023
|
+
columnInfo,
|
|
1024
|
+
encryptionClient,
|
|
1025
|
+
defaultTable,
|
|
1026
|
+
tableCache
|
|
1027
|
+
);
|
|
1028
|
+
};
|
|
1029
|
+
const encryptedNotBetween = (left, min, max) => {
|
|
1030
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
1031
|
+
return createRangeOperator(
|
|
1032
|
+
"notBetween",
|
|
1033
|
+
left,
|
|
1034
|
+
min,
|
|
1035
|
+
max,
|
|
1036
|
+
columnInfo,
|
|
1037
|
+
encryptionClient,
|
|
1038
|
+
defaultTable,
|
|
1039
|
+
tableCache
|
|
1040
|
+
);
|
|
1041
|
+
};
|
|
1042
|
+
const encryptedLike = (left, right) => {
|
|
1043
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
1044
|
+
return createTextSearchOperator(
|
|
1045
|
+
"like",
|
|
1046
|
+
left,
|
|
1047
|
+
right,
|
|
1048
|
+
columnInfo,
|
|
1049
|
+
encryptionClient,
|
|
1050
|
+
defaultTable,
|
|
1051
|
+
tableCache
|
|
1052
|
+
);
|
|
1053
|
+
};
|
|
1054
|
+
const encryptedIlike = (left, right) => {
|
|
1055
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
1056
|
+
return createTextSearchOperator(
|
|
1057
|
+
"ilike",
|
|
1058
|
+
left,
|
|
1059
|
+
right,
|
|
1060
|
+
columnInfo,
|
|
1061
|
+
encryptionClient,
|
|
1062
|
+
defaultTable,
|
|
1063
|
+
tableCache
|
|
1064
|
+
);
|
|
1065
|
+
};
|
|
1066
|
+
const encryptedNotIlike = (left, right) => {
|
|
1067
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
1068
|
+
return createTextSearchOperator(
|
|
1069
|
+
"notIlike",
|
|
1070
|
+
left,
|
|
1071
|
+
right,
|
|
1072
|
+
columnInfo,
|
|
1073
|
+
encryptionClient,
|
|
1074
|
+
defaultTable,
|
|
1075
|
+
tableCache
|
|
1076
|
+
);
|
|
1077
|
+
};
|
|
1078
|
+
const encryptedJsonbPathQueryFirst = (left, right) => {
|
|
1079
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
1080
|
+
return createJsonbOperator(
|
|
1081
|
+
"jsonbPathQueryFirst",
|
|
1082
|
+
left,
|
|
1083
|
+
right,
|
|
1084
|
+
columnInfo,
|
|
1085
|
+
encryptionClient,
|
|
1086
|
+
defaultTable,
|
|
1087
|
+
tableCache
|
|
1088
|
+
);
|
|
1089
|
+
};
|
|
1090
|
+
const encryptedJsonbGet = (left, right) => {
|
|
1091
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
1092
|
+
return createJsonbOperator(
|
|
1093
|
+
"jsonbGet",
|
|
1094
|
+
left,
|
|
1095
|
+
right,
|
|
1096
|
+
columnInfo,
|
|
1097
|
+
encryptionClient,
|
|
1098
|
+
defaultTable,
|
|
1099
|
+
tableCache
|
|
1100
|
+
);
|
|
1101
|
+
};
|
|
1102
|
+
const encryptedJsonbPathExists = (left, right) => {
|
|
1103
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
1104
|
+
return createJsonbOperator(
|
|
1105
|
+
"jsonbPathExists",
|
|
1106
|
+
left,
|
|
1107
|
+
right,
|
|
1108
|
+
columnInfo,
|
|
1109
|
+
encryptionClient,
|
|
1110
|
+
defaultTable,
|
|
1111
|
+
tableCache
|
|
1112
|
+
);
|
|
1113
|
+
};
|
|
1114
|
+
const encryptedInArray = async (left, right) => {
|
|
1115
|
+
if (isSQLWrapper(right)) {
|
|
1116
|
+
return (0, import_drizzle_orm.inArray)(left, right);
|
|
1117
|
+
}
|
|
1118
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
1119
|
+
if (!columnInfo.config?.equality || !Array.isArray(right)) {
|
|
1120
|
+
return (0, import_drizzle_orm.inArray)(left, right);
|
|
1121
|
+
}
|
|
1122
|
+
const encryptedValues = await encryptValues(
|
|
1123
|
+
encryptionClient,
|
|
1124
|
+
right.map((value) => ({
|
|
1125
|
+
value,
|
|
1126
|
+
column: left,
|
|
1127
|
+
queryType: queryTypes.equality
|
|
1128
|
+
})),
|
|
1129
|
+
defaultTable,
|
|
1130
|
+
tableCache
|
|
1131
|
+
);
|
|
1132
|
+
const conditions = encryptedValues.filter((encrypted) => encrypted !== void 0).map((encrypted) => (0, import_drizzle_orm.eq)(left, encrypted));
|
|
1133
|
+
if (conditions.length === 0) {
|
|
1134
|
+
return import_drizzle_orm2.sql`false`;
|
|
1135
|
+
}
|
|
1136
|
+
const combined = (0, import_drizzle_orm.or)(...conditions);
|
|
1137
|
+
return combined ?? import_drizzle_orm2.sql`false`;
|
|
1138
|
+
};
|
|
1139
|
+
const encryptedNotInArray = async (left, right) => {
|
|
1140
|
+
if (isSQLWrapper(right)) {
|
|
1141
|
+
return (0, import_drizzle_orm.notInArray)(
|
|
1142
|
+
left,
|
|
1143
|
+
right
|
|
1144
|
+
);
|
|
1145
|
+
}
|
|
1146
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
1147
|
+
if (!columnInfo.config?.equality || !Array.isArray(right)) {
|
|
1148
|
+
return (0, import_drizzle_orm.notInArray)(left, right);
|
|
1149
|
+
}
|
|
1150
|
+
const encryptedValues = await encryptValues(
|
|
1151
|
+
encryptionClient,
|
|
1152
|
+
right.map((value) => ({
|
|
1153
|
+
value,
|
|
1154
|
+
column: left,
|
|
1155
|
+
queryType: queryTypes.equality
|
|
1156
|
+
})),
|
|
1157
|
+
defaultTable,
|
|
1158
|
+
tableCache
|
|
1159
|
+
);
|
|
1160
|
+
const conditions = encryptedValues.filter((encrypted) => encrypted !== void 0).map((encrypted) => (0, import_drizzle_orm.ne)(left, encrypted));
|
|
1161
|
+
if (conditions.length === 0) {
|
|
1162
|
+
return import_drizzle_orm2.sql`true`;
|
|
1163
|
+
}
|
|
1164
|
+
const combined = (0, import_drizzle_orm.and)(...conditions);
|
|
1165
|
+
return combined ?? import_drizzle_orm2.sql`true`;
|
|
1166
|
+
};
|
|
1167
|
+
const encryptedAsc = (column) => {
|
|
1168
|
+
const columnInfo = getColumnInfo(column, defaultTable, tableCache);
|
|
1169
|
+
if (columnInfo.config?.orderAndRange) {
|
|
1170
|
+
return (0, import_drizzle_orm.asc)(import_drizzle_orm2.sql`eql_v2.order_by(${column})`);
|
|
1171
|
+
}
|
|
1172
|
+
return (0, import_drizzle_orm.asc)(column);
|
|
1173
|
+
};
|
|
1174
|
+
const encryptedDesc = (column) => {
|
|
1175
|
+
const columnInfo = getColumnInfo(column, defaultTable, tableCache);
|
|
1176
|
+
if (columnInfo.config?.orderAndRange) {
|
|
1177
|
+
return (0, import_drizzle_orm.desc)(import_drizzle_orm2.sql`eql_v2.order_by(${column})`);
|
|
1178
|
+
}
|
|
1179
|
+
return (0, import_drizzle_orm.desc)(column);
|
|
1180
|
+
};
|
|
1181
|
+
const encryptedAnd = async (...conditions) => {
|
|
1182
|
+
const lazyOperators = [];
|
|
1183
|
+
const regularConditions = [];
|
|
1184
|
+
const regularPromises = [];
|
|
1185
|
+
for (const condition of conditions) {
|
|
1186
|
+
if (condition === void 0) {
|
|
1187
|
+
continue;
|
|
1188
|
+
}
|
|
1189
|
+
if (isLazyOperator(condition)) {
|
|
1190
|
+
lazyOperators.push(condition);
|
|
1191
|
+
} else if (condition instanceof Promise) {
|
|
1192
|
+
if (isLazyOperator(condition)) {
|
|
1193
|
+
lazyOperators.push(condition);
|
|
1194
|
+
} else {
|
|
1195
|
+
regularPromises.push(condition);
|
|
1196
|
+
}
|
|
1197
|
+
} else {
|
|
1198
|
+
regularConditions.push(condition);
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
if (lazyOperators.length === 0) {
|
|
1202
|
+
const allConditions2 = [
|
|
1203
|
+
...regularConditions,
|
|
1204
|
+
...await Promise.all(regularPromises)
|
|
1205
|
+
];
|
|
1206
|
+
return (0, import_drizzle_orm.and)(...allConditions2) ?? import_drizzle_orm2.sql`true`;
|
|
1207
|
+
}
|
|
1208
|
+
const valuesToEncrypt = [];
|
|
1209
|
+
for (let i = 0; i < lazyOperators.length; i++) {
|
|
1210
|
+
const lazyOp = lazyOperators[i];
|
|
1211
|
+
if (!lazyOp.needsEncryption) {
|
|
1212
|
+
continue;
|
|
1213
|
+
}
|
|
1214
|
+
if (lazyOp.min !== void 0 && lazyOp.max !== void 0) {
|
|
1215
|
+
valuesToEncrypt.push({
|
|
1216
|
+
value: lazyOp.min,
|
|
1217
|
+
column: lazyOp.left,
|
|
1218
|
+
columnInfo: lazyOp.columnInfo,
|
|
1219
|
+
queryType: lazyOp.queryType,
|
|
1220
|
+
lazyOpIndex: i,
|
|
1221
|
+
isMin: true
|
|
1222
|
+
});
|
|
1223
|
+
valuesToEncrypt.push({
|
|
1224
|
+
value: lazyOp.max,
|
|
1225
|
+
column: lazyOp.left,
|
|
1226
|
+
columnInfo: lazyOp.columnInfo,
|
|
1227
|
+
queryType: lazyOp.queryType,
|
|
1228
|
+
lazyOpIndex: i,
|
|
1229
|
+
isMax: true
|
|
1230
|
+
});
|
|
1231
|
+
} else if (lazyOp.right !== void 0) {
|
|
1232
|
+
valuesToEncrypt.push({
|
|
1233
|
+
value: lazyOp.right,
|
|
1234
|
+
column: lazyOp.left,
|
|
1235
|
+
columnInfo: lazyOp.columnInfo,
|
|
1236
|
+
queryType: lazyOp.queryType,
|
|
1237
|
+
lazyOpIndex: i
|
|
1238
|
+
});
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
const encryptedResults = await encryptValues(
|
|
1242
|
+
encryptionClient,
|
|
1243
|
+
valuesToEncrypt.map((v) => ({
|
|
1244
|
+
value: v.value,
|
|
1245
|
+
column: v.column,
|
|
1246
|
+
queryType: v.queryType
|
|
1247
|
+
})),
|
|
1248
|
+
defaultTable,
|
|
1249
|
+
tableCache
|
|
1250
|
+
);
|
|
1251
|
+
const encryptedByLazyOp = /* @__PURE__ */ new Map();
|
|
1252
|
+
for (let i = 0; i < valuesToEncrypt.length; i++) {
|
|
1253
|
+
const { lazyOpIndex, isMin, isMax } = valuesToEncrypt[i];
|
|
1254
|
+
const encrypted = encryptedResults[i];
|
|
1255
|
+
let group = encryptedByLazyOp.get(lazyOpIndex);
|
|
1256
|
+
if (!group) {
|
|
1257
|
+
group = {};
|
|
1258
|
+
encryptedByLazyOp.set(lazyOpIndex, group);
|
|
1259
|
+
}
|
|
1260
|
+
if (isMin) {
|
|
1261
|
+
group.min = encrypted;
|
|
1262
|
+
} else if (isMax) {
|
|
1263
|
+
group.max = encrypted;
|
|
1264
|
+
} else {
|
|
1265
|
+
group.value = encrypted;
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
const sqlConditions = [];
|
|
1269
|
+
for (let i = 0; i < lazyOperators.length; i++) {
|
|
1270
|
+
const lazyOp = lazyOperators[i];
|
|
1271
|
+
const encrypted = encryptedByLazyOp.get(i);
|
|
1272
|
+
let sqlCondition;
|
|
1273
|
+
if (lazyOp.needsEncryption && encrypted) {
|
|
1274
|
+
const encryptedValues = [];
|
|
1275
|
+
if (encrypted.value !== void 0) {
|
|
1276
|
+
encryptedValues.push({
|
|
1277
|
+
value: lazyOp.right,
|
|
1278
|
+
encrypted: encrypted.value
|
|
1279
|
+
});
|
|
1280
|
+
}
|
|
1281
|
+
if (encrypted.min !== void 0) {
|
|
1282
|
+
encryptedValues.push({ value: lazyOp.min, encrypted: encrypted.min });
|
|
1283
|
+
}
|
|
1284
|
+
if (encrypted.max !== void 0) {
|
|
1285
|
+
encryptedValues.push({ value: lazyOp.max, encrypted: encrypted.max });
|
|
1286
|
+
}
|
|
1287
|
+
sqlCondition = await executeLazyOperator(lazyOp, encryptedValues);
|
|
1288
|
+
} else {
|
|
1289
|
+
sqlCondition = lazyOp.execute(lazyOp.right);
|
|
1290
|
+
}
|
|
1291
|
+
sqlConditions.push(sqlCondition);
|
|
1292
|
+
}
|
|
1293
|
+
const regularPromisesResults = await Promise.all(regularPromises);
|
|
1294
|
+
const allConditions = [
|
|
1295
|
+
...regularConditions,
|
|
1296
|
+
...sqlConditions,
|
|
1297
|
+
...regularPromisesResults
|
|
1298
|
+
];
|
|
1299
|
+
return (0, import_drizzle_orm.and)(...allConditions) ?? import_drizzle_orm2.sql`true`;
|
|
1300
|
+
};
|
|
1301
|
+
const encryptedOr = async (...conditions) => {
|
|
1302
|
+
const lazyOperators = [];
|
|
1303
|
+
const regularConditions = [];
|
|
1304
|
+
const regularPromises = [];
|
|
1305
|
+
for (const condition of conditions) {
|
|
1306
|
+
if (condition === void 0) {
|
|
1307
|
+
continue;
|
|
1308
|
+
}
|
|
1309
|
+
if (isLazyOperator(condition)) {
|
|
1310
|
+
lazyOperators.push(condition);
|
|
1311
|
+
} else if (condition instanceof Promise) {
|
|
1312
|
+
if (isLazyOperator(condition)) {
|
|
1313
|
+
lazyOperators.push(condition);
|
|
1314
|
+
} else {
|
|
1315
|
+
regularPromises.push(condition);
|
|
1316
|
+
}
|
|
1317
|
+
} else {
|
|
1318
|
+
regularConditions.push(condition);
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
if (lazyOperators.length === 0) {
|
|
1322
|
+
const allConditions2 = [
|
|
1323
|
+
...regularConditions,
|
|
1324
|
+
...await Promise.all(regularPromises)
|
|
1325
|
+
];
|
|
1326
|
+
return (0, import_drizzle_orm.or)(...allConditions2) ?? import_drizzle_orm2.sql`false`;
|
|
1327
|
+
}
|
|
1328
|
+
const valuesToEncrypt = [];
|
|
1329
|
+
for (let i = 0; i < lazyOperators.length; i++) {
|
|
1330
|
+
const lazyOp = lazyOperators[i];
|
|
1331
|
+
if (!lazyOp.needsEncryption) {
|
|
1332
|
+
continue;
|
|
1333
|
+
}
|
|
1334
|
+
if (lazyOp.min !== void 0 && lazyOp.max !== void 0) {
|
|
1335
|
+
valuesToEncrypt.push({
|
|
1336
|
+
value: lazyOp.min,
|
|
1337
|
+
column: lazyOp.left,
|
|
1338
|
+
columnInfo: lazyOp.columnInfo,
|
|
1339
|
+
queryType: lazyOp.queryType,
|
|
1340
|
+
lazyOpIndex: i,
|
|
1341
|
+
isMin: true
|
|
1342
|
+
});
|
|
1343
|
+
valuesToEncrypt.push({
|
|
1344
|
+
value: lazyOp.max,
|
|
1345
|
+
column: lazyOp.left,
|
|
1346
|
+
columnInfo: lazyOp.columnInfo,
|
|
1347
|
+
queryType: lazyOp.queryType,
|
|
1348
|
+
lazyOpIndex: i,
|
|
1349
|
+
isMax: true
|
|
1350
|
+
});
|
|
1351
|
+
} else if (lazyOp.right !== void 0) {
|
|
1352
|
+
valuesToEncrypt.push({
|
|
1353
|
+
value: lazyOp.right,
|
|
1354
|
+
column: lazyOp.left,
|
|
1355
|
+
columnInfo: lazyOp.columnInfo,
|
|
1356
|
+
queryType: lazyOp.queryType,
|
|
1357
|
+
lazyOpIndex: i
|
|
1358
|
+
});
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
const encryptedResults = await encryptValues(
|
|
1362
|
+
encryptionClient,
|
|
1363
|
+
valuesToEncrypt.map((v) => ({
|
|
1364
|
+
value: v.value,
|
|
1365
|
+
column: v.column,
|
|
1366
|
+
queryType: v.queryType
|
|
1367
|
+
})),
|
|
1368
|
+
defaultTable,
|
|
1369
|
+
tableCache
|
|
1370
|
+
);
|
|
1371
|
+
const encryptedByLazyOp = /* @__PURE__ */ new Map();
|
|
1372
|
+
for (let i = 0; i < valuesToEncrypt.length; i++) {
|
|
1373
|
+
const { lazyOpIndex, isMin, isMax } = valuesToEncrypt[i];
|
|
1374
|
+
const encrypted = encryptedResults[i];
|
|
1375
|
+
let group = encryptedByLazyOp.get(lazyOpIndex);
|
|
1376
|
+
if (!group) {
|
|
1377
|
+
group = {};
|
|
1378
|
+
encryptedByLazyOp.set(lazyOpIndex, group);
|
|
1379
|
+
}
|
|
1380
|
+
if (isMin) {
|
|
1381
|
+
group.min = encrypted;
|
|
1382
|
+
} else if (isMax) {
|
|
1383
|
+
group.max = encrypted;
|
|
1384
|
+
} else {
|
|
1385
|
+
group.value = encrypted;
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
const sqlConditions = [];
|
|
1389
|
+
for (let i = 0; i < lazyOperators.length; i++) {
|
|
1390
|
+
const lazyOp = lazyOperators[i];
|
|
1391
|
+
const encrypted = encryptedByLazyOp.get(i);
|
|
1392
|
+
let sqlCondition;
|
|
1393
|
+
if (lazyOp.needsEncryption && encrypted) {
|
|
1394
|
+
const encryptedValues = [];
|
|
1395
|
+
if (encrypted.value !== void 0) {
|
|
1396
|
+
encryptedValues.push({
|
|
1397
|
+
value: lazyOp.right,
|
|
1398
|
+
encrypted: encrypted.value
|
|
1399
|
+
});
|
|
1400
|
+
}
|
|
1401
|
+
if (encrypted.min !== void 0) {
|
|
1402
|
+
encryptedValues.push({ value: lazyOp.min, encrypted: encrypted.min });
|
|
1403
|
+
}
|
|
1404
|
+
if (encrypted.max !== void 0) {
|
|
1405
|
+
encryptedValues.push({ value: lazyOp.max, encrypted: encrypted.max });
|
|
1406
|
+
}
|
|
1407
|
+
sqlCondition = await executeLazyOperator(lazyOp, encryptedValues);
|
|
1408
|
+
} else {
|
|
1409
|
+
sqlCondition = lazyOp.execute(lazyOp.right);
|
|
1410
|
+
}
|
|
1411
|
+
sqlConditions.push(sqlCondition);
|
|
1412
|
+
}
|
|
1413
|
+
const regularPromisesResults = await Promise.all(regularPromises);
|
|
1414
|
+
const allConditions = [
|
|
1415
|
+
...regularConditions,
|
|
1416
|
+
...sqlConditions,
|
|
1417
|
+
...regularPromisesResults
|
|
1418
|
+
];
|
|
1419
|
+
return (0, import_drizzle_orm.or)(...allConditions) ?? import_drizzle_orm2.sql`false`;
|
|
1420
|
+
};
|
|
1421
|
+
return {
|
|
1422
|
+
// Comparison operators
|
|
1423
|
+
eq: encryptedEq,
|
|
1424
|
+
ne: encryptedNe,
|
|
1425
|
+
gt: encryptedGt,
|
|
1426
|
+
gte: encryptedGte,
|
|
1427
|
+
lt: encryptedLt,
|
|
1428
|
+
lte: encryptedLte,
|
|
1429
|
+
// Range operators
|
|
1430
|
+
between: encryptedBetween,
|
|
1431
|
+
notBetween: encryptedNotBetween,
|
|
1432
|
+
// Text search operators
|
|
1433
|
+
like: encryptedLike,
|
|
1434
|
+
ilike: encryptedIlike,
|
|
1435
|
+
notIlike: encryptedNotIlike,
|
|
1436
|
+
// Searchable JSON operators
|
|
1437
|
+
jsonbPathQueryFirst: encryptedJsonbPathQueryFirst,
|
|
1438
|
+
jsonbGet: encryptedJsonbGet,
|
|
1439
|
+
jsonbPathExists: encryptedJsonbPathExists,
|
|
1440
|
+
// Array operators
|
|
1441
|
+
inArray: encryptedInArray,
|
|
1442
|
+
notInArray: encryptedNotInArray,
|
|
1443
|
+
// Sorting operators
|
|
1444
|
+
asc: encryptedAsc,
|
|
1445
|
+
desc: encryptedDesc,
|
|
1446
|
+
// AND operator - batches encryption operations
|
|
1447
|
+
and: encryptedAnd,
|
|
1448
|
+
// OR operator - batches encryption operations
|
|
1449
|
+
or: encryptedOr,
|
|
1450
|
+
// Operators that don't need encryption (pass through to Drizzle)
|
|
1451
|
+
exists: import_drizzle_orm.exists,
|
|
1452
|
+
notExists: import_drizzle_orm.notExists,
|
|
1453
|
+
isNull: import_drizzle_orm.isNull,
|
|
1454
|
+
isNotNull: import_drizzle_orm.isNotNull,
|
|
1455
|
+
not: import_drizzle_orm.not,
|
|
1456
|
+
// Array operators that work with arrays directly (not encrypted values)
|
|
1457
|
+
arrayContains: import_drizzle_orm.arrayContains,
|
|
1458
|
+
arrayContained: import_drizzle_orm.arrayContained,
|
|
1459
|
+
arrayOverlaps: import_drizzle_orm.arrayOverlaps
|
|
1460
|
+
};
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
// src/drizzle/index.ts
|
|
1464
|
+
var columnConfigMap = /* @__PURE__ */ new Map();
|
|
1465
|
+
var encryptedType = (name, config) => {
|
|
1466
|
+
const customColumnType = (0, import_pg_core.customType)({
|
|
1467
|
+
dataType() {
|
|
1468
|
+
return "eql_v2_encrypted";
|
|
1469
|
+
},
|
|
1470
|
+
toDriver(value) {
|
|
1471
|
+
const jsonStr = JSON.stringify(value);
|
|
1472
|
+
const escaped = jsonStr.replace(/"/g, '""');
|
|
1473
|
+
return `("${escaped}")`;
|
|
1474
|
+
},
|
|
1475
|
+
fromDriver(value) {
|
|
1476
|
+
const parseComposite = (str) => {
|
|
1477
|
+
if (!str || str === "") return null;
|
|
1478
|
+
const trimmed = str.trim();
|
|
1479
|
+
if (trimmed.startsWith("(") && trimmed.endsWith(")")) {
|
|
1480
|
+
let inner = trimmed.slice(1, -1);
|
|
1481
|
+
inner = inner.replace(/""/g, '"');
|
|
1482
|
+
if (inner.startsWith('"') && inner.endsWith('"')) {
|
|
1483
|
+
const stripped = inner.slice(1, -1);
|
|
1484
|
+
return JSON.parse(stripped);
|
|
1485
|
+
}
|
|
1486
|
+
if (inner.startsWith("{") || inner.startsWith("[")) {
|
|
1487
|
+
return JSON.parse(inner);
|
|
1488
|
+
}
|
|
1489
|
+
return inner;
|
|
1490
|
+
}
|
|
1491
|
+
return JSON.parse(str);
|
|
1492
|
+
};
|
|
1493
|
+
return parseComposite(value);
|
|
1494
|
+
}
|
|
1495
|
+
});
|
|
1496
|
+
const column = customColumnType(name);
|
|
1497
|
+
const fullConfig = {
|
|
1498
|
+
name,
|
|
1499
|
+
...config
|
|
1500
|
+
};
|
|
1501
|
+
columnConfigMap.set(name, fullConfig);
|
|
1502
|
+
column._encryptionConfig = fullConfig;
|
|
1503
|
+
return column;
|
|
1504
|
+
};
|
|
1505
|
+
function getEncryptedColumnConfig(columnName, column) {
|
|
1506
|
+
if (column && typeof column === "object") {
|
|
1507
|
+
const columnAny = column;
|
|
1508
|
+
const isEncrypted = columnAny.sqlName === "eql_v2_encrypted" || columnAny.dataType === "eql_v2_encrypted" || columnAny.dataType && typeof columnAny.dataType === "function" && columnAny.dataType() === "eql_v2_encrypted";
|
|
1509
|
+
if (isEncrypted) {
|
|
1510
|
+
if (columnAny._encryptionConfig) {
|
|
1511
|
+
return columnAny._encryptionConfig;
|
|
1512
|
+
}
|
|
1513
|
+
const lookupName = columnAny.name || columnName;
|
|
1514
|
+
return columnConfigMap.get(lookupName);
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
return void 0;
|
|
1518
|
+
}
|
|
1519
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1520
|
+
0 && (module.exports = {
|
|
1521
|
+
EncryptionConfigError,
|
|
1522
|
+
EncryptionOperatorError,
|
|
1523
|
+
createEncryptionOperators,
|
|
1524
|
+
encryptedType,
|
|
1525
|
+
extractEncryptionSchema,
|
|
1526
|
+
getEncryptedColumnConfig
|
|
1527
|
+
});
|
|
1528
|
+
//# sourceMappingURL=index.cjs.map
|