@cipherstash/stack 0.2.0 → 0.3.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.
Files changed (64) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +1 -2
  3. package/dist/bin/stash.js +63 -45
  4. package/dist/bin/stash.js.map +1 -1
  5. package/dist/{chunk-5G4F4JJG.js → chunk-JLI27P46.js} +1 -1
  6. package/dist/chunk-JLI27P46.js.map +1 -0
  7. package/dist/{chunk-LHZ6KZIG.js → chunk-MW6D52V2.js} +42 -31
  8. package/dist/chunk-MW6D52V2.js.map +1 -0
  9. package/dist/{chunk-5DCT6YU2.js → chunk-OAPLZLR5.js} +7 -3
  10. package/dist/{chunk-5DCT6YU2.js.map → chunk-OAPLZLR5.js.map} +1 -1
  11. package/dist/{chunk-7XRPN2KX.js → chunk-TBAIVO6T.js} +26 -23
  12. package/dist/chunk-TBAIVO6T.js.map +1 -0
  13. package/dist/{client-D-ZH8SB2.d.cts → client-Bf0Xw2xo.d.cts} +19 -16
  14. package/dist/{client-BV9pXC-d.d.ts → client-Kfp8OsPB.d.ts} +19 -16
  15. package/dist/client.cjs +25 -22
  16. package/dist/client.cjs.map +1 -1
  17. package/dist/client.d.cts +2 -2
  18. package/dist/client.d.ts +2 -2
  19. package/dist/client.js +5 -5
  20. package/dist/drizzle/index.cjs +19 -16
  21. package/dist/drizzle/index.cjs.map +1 -1
  22. package/dist/drizzle/index.d.cts +5 -5
  23. package/dist/drizzle/index.d.ts +5 -5
  24. package/dist/drizzle/index.js +2 -2
  25. package/dist/drizzle/index.js.map +1 -1
  26. package/dist/dynamodb/index.cjs.map +1 -1
  27. package/dist/dynamodb/index.d.cts +10 -10
  28. package/dist/dynamodb/index.d.ts +10 -10
  29. package/dist/dynamodb/index.js.map +1 -1
  30. package/dist/identity/index.cjs +6 -2
  31. package/dist/identity/index.cjs.map +1 -1
  32. package/dist/identity/index.js +1 -1
  33. package/dist/index.cjs +67 -49
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.d.cts +3 -3
  36. package/dist/index.d.ts +3 -3
  37. package/dist/index.js +7 -7
  38. package/dist/schema/index.cjs +31 -28
  39. package/dist/schema/index.cjs.map +1 -1
  40. package/dist/schema/index.d.cts +1 -1
  41. package/dist/schema/index.d.ts +1 -1
  42. package/dist/schema/index.js +11 -11
  43. package/dist/secrets/index.cjs +63 -45
  44. package/dist/secrets/index.cjs.map +1 -1
  45. package/dist/secrets/index.d.cts +1 -1
  46. package/dist/secrets/index.d.ts +1 -1
  47. package/dist/secrets/index.js +4 -4
  48. package/dist/secrets/index.js.map +1 -1
  49. package/dist/supabase/index.cjs +7 -7
  50. package/dist/supabase/index.cjs.map +1 -1
  51. package/dist/supabase/index.d.cts +3 -3
  52. package/dist/supabase/index.d.ts +3 -3
  53. package/dist/supabase/index.js +3 -3
  54. package/dist/supabase/index.js.map +1 -1
  55. package/dist/{types-public-Dfg-hkuQ.d.cts → types-public-0CzBV45X.d.cts} +70 -52
  56. package/dist/{types-public-Dfg-hkuQ.d.ts → types-public-0CzBV45X.d.ts} +70 -52
  57. package/dist/types-public.cjs.map +1 -1
  58. package/dist/types-public.d.cts +1 -1
  59. package/dist/types-public.d.ts +1 -1
  60. package/dist/types-public.js +1 -1
  61. package/package.json +1 -1
  62. package/dist/chunk-5G4F4JJG.js.map +0 -1
  63. package/dist/chunk-7XRPN2KX.js.map +0 -1
  64. package/dist/chunk-LHZ6KZIG.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/drizzle/index.ts","../../src/schema/index.ts","../../src/drizzle/schema-extraction.ts","../../src/types.ts","../../src/drizzle/operators.ts"],"sourcesContent":["import type { CastAs, MatchIndexOpts, TokenFilter } from '@/schema'\nimport { customType } from 'drizzle-orm/pg-core'\n\nexport type { CastAs, MatchIndexOpts, TokenFilter }\n\n/**\n * Configuration for encrypted column indexes and data types\n */\nexport type EncryptedColumnConfig = {\n /**\n * Data type for the column (default: 'string')\n */\n dataType?: CastAs\n /**\n * Enable free text search. Can be a boolean for default options, or an object for custom configuration.\n */\n freeTextSearch?: boolean | MatchIndexOpts\n /**\n * Enable equality index. Can be a boolean for default options, or an array of token filters.\n */\n equality?: boolean | TokenFilter[]\n /**\n * Enable order and range index for sorting and range queries.\n */\n orderAndRange?: boolean\n /**\n * Enable searchable JSON index for JSONB path queries.\n * Requires dataType: 'json'.\n */\n searchableJson?: boolean\n}\n\n/**\n * Map to store configuration for encrypted columns\n * Keyed by column name (the name passed to encryptedType)\n */\nconst columnConfigMap = new Map<\n string,\n EncryptedColumnConfig & { name: string }\n>()\n\n/**\n * Creates an encrypted column type for Drizzle ORM with configurable searchable encryption options.\n *\n * When data is encrypted, the actual stored value is an [EQL v2](/docs/reference/eql) encrypted composite type which includes any searchable encryption indexes defined for the column.\n * Importantly, the original data type is not known until it is decrypted. Therefore, this function allows specifying\n * the original data type via the `dataType` option in the configuration.\n * This ensures that when data is decrypted, it can be correctly interpreted as the intended TypeScript type.\n *\n * @typeParam TData - The TypeScript type of the data stored in the column\n * @param name - The column name in the database\n * @param config - Optional configuration for data type and searchable encryption indexes\n * @returns A Drizzle column type that can be used in pgTable definitions\n *\n * ## Searchable Encryption Options\n *\n * - `dataType`: Specifies the original data type of the column (e.g., 'string', 'number', 'json'). Default is 'string'.\n * - `freeTextSearch`: Enables free text search index. Can be a boolean for default options, or an object for custom configuration.\n * - `equality`: Enables equality index. Can be a boolean for default options, or an array of token filters.\n * - `orderAndRange`: Enables order and range index for sorting and range queries.\n * - `searchableJson`: Enables searchable JSON index for JSONB path queries on encrypted JSON columns.\n *\n * See {@link EncryptedColumnConfig}.\n *\n * @example\n * Defining a drizzle table schema for postgres table with encrypted columns.\n *\n * ```typescript\n * import { pgTable, integer, timestamp } from 'drizzle-orm/pg-core'\n * import { encryptedType } from '@cipherstash/stack/drizzle'\n *\n * const users = pgTable('users', {\n * email: encryptedType('email', {\n * freeTextSearch: true,\n * equality: true,\n * orderAndRange: true,\n * }),\n * age: encryptedType('age', {\n * dataType: 'number',\n * equality: true,\n * orderAndRange: true,\n * }),\n * profile: encryptedType('profile', {\n * dataType: 'json',\n * }),\n * })\n * ```\n */\nexport const encryptedType = <TData>(\n name: string,\n config?: EncryptedColumnConfig,\n) => {\n // Create the Drizzle custom type\n const customColumnType = customType<{ data: TData; driverData: string }>({\n dataType() {\n return 'eql_v2_encrypted'\n },\n toDriver(value: TData): string {\n const jsonStr = JSON.stringify(value)\n const escaped = jsonStr.replace(/\"/g, '\"\"')\n return `(\"${escaped}\")`\n },\n fromDriver(value: string): TData {\n const parseComposite = (str: string) => {\n if (!str || str === '') return null\n\n const trimmed = str.trim()\n\n if (trimmed.startsWith('(') && trimmed.endsWith(')')) {\n let inner = trimmed.slice(1, -1)\n inner = inner.replace(/\"\"/g, '\"')\n\n if (inner.startsWith('\"') && inner.endsWith('\"')) {\n const stripped = inner.slice(1, -1)\n return JSON.parse(stripped)\n }\n\n if (inner.startsWith('{') || inner.startsWith('[')) {\n return JSON.parse(inner)\n }\n\n return inner\n }\n\n return JSON.parse(str)\n }\n\n return parseComposite(value) as TData\n },\n })\n\n // Create the column instance\n const column = customColumnType(name)\n\n // Store configuration keyed by column name\n // This allows us to look it up during schema extraction\n const fullConfig: EncryptedColumnConfig & { name: string } = {\n name,\n ...config,\n }\n\n // Store in Map keyed by column name (will be looked up during extraction)\n columnConfigMap.set(name, fullConfig)\n\n // Also store on property for immediate access (before pgTable processes it)\n // We need to use any here because Drizzle columns don't have a type for custom properties\n // biome-ignore lint/suspicious/noExplicitAny: Drizzle columns don't expose custom property types\n ;(column as any)._encryptionConfig = fullConfig\n\n return column\n}\n\n/**\n * Get configuration for an encrypted column by checking if it's an encrypted type\n * and looking up the config by column name\n * @internal\n */\nexport function getEncryptedColumnConfig(\n columnName: string,\n column: unknown,\n): (EncryptedColumnConfig & { name: string }) | undefined {\n // Check if this is an encrypted column\n if (column && typeof column === 'object') {\n // We need to use any here to access Drizzle column properties\n // biome-ignore lint/suspicious/noExplicitAny: Drizzle column types don't expose all properties\n const columnAny = column as any\n\n // Check if it's an encrypted column by checking sqlName or dataType\n // After pgTable processes it, sqlName will be 'eql_v2_encrypted'\n const isEncrypted =\n columnAny.sqlName === 'eql_v2_encrypted' ||\n columnAny.dataType === 'eql_v2_encrypted' ||\n (columnAny.dataType &&\n typeof columnAny.dataType === 'function' &&\n columnAny.dataType() === 'eql_v2_encrypted')\n\n if (isEncrypted) {\n // Try to get config from property (if still there)\n if (columnAny._encryptionConfig) {\n return columnAny._encryptionConfig\n }\n\n // Look up config by column name (the name passed to encryptedType)\n // The column.name should match what was passed to encryptedType\n const lookupName = columnAny.name || columnName\n return columnConfigMap.get(lookupName)\n }\n }\n return undefined\n}\n\n/**\n * Extract a CipherStash encryption schema from a Drizzle table definition.\n *\n * Inspects columns created with {@link encryptedType} and builds the equivalent\n * `encryptedTable` / `encryptedColumn` schema automatically.\n */\nexport { extractEncryptionSchema } from './schema-extraction.js'\n\n/**\n * Create Drizzle query operators (`eq`, `lt`, `gt`, etc.) that work with\n * encrypted columns. The returned operators encrypt query values before\n * passing them to Drizzle, enabling searchable encryption in standard\n * Drizzle queries.\n */\nexport {\n createEncryptionOperators,\n EncryptionOperatorError,\n EncryptionConfigError,\n} from './operators.js'\n","import type { Encrypted } from '@/types'\nimport { z } from 'zod'\n\n// ------------------------\n// Zod schemas\n// ------------------------\n\n/**\n * Allowed cast types for CipherStash schema fields.\n *\n * **Possible values:**\n * - `\"bigint\"`\n * - `\"boolean\"`\n * - `\"date\"`\n * - `\"number\"`\n * - `\"string\"`\n * - `\"json\"`\n *\n * @remarks\n * This is a Zod enum used at runtime to validate schema definitions.\n * Use {@link CastAs} when typing your own code.\n *\n * @internal\n */\nexport const castAsEnum = z\n .enum(['bigint', 'boolean', 'date', 'number', 'string', 'json'])\n .default('string')\n\nconst tokenFilterSchema = z.object({\n kind: z.literal('downcase'),\n})\n\nconst tokenizerSchema = z\n .union([\n z.object({\n kind: z.literal('standard'),\n }),\n z.object({\n kind: z.literal('ngram'),\n token_length: z.number(),\n }),\n ])\n .default({ kind: 'ngram', token_length: 3 })\n .optional()\n\nconst oreIndexOptsSchema = z.object({})\n\nconst uniqueIndexOptsSchema = z.object({\n token_filters: z.array(tokenFilterSchema).default([]).optional(),\n})\n\nconst matchIndexOptsSchema = z.object({\n tokenizer: tokenizerSchema,\n token_filters: z.array(tokenFilterSchema).default([]).optional(),\n k: z.number().default(6).optional(),\n m: z.number().default(2048).optional(),\n include_original: z.boolean().default(false).optional(),\n})\n\nconst steVecIndexOptsSchema = z.object({\n prefix: z.string(),\n})\n\nconst indexesSchema = z\n .object({\n ore: oreIndexOptsSchema.optional(),\n unique: uniqueIndexOptsSchema.optional(),\n match: matchIndexOptsSchema.optional(),\n ste_vec: steVecIndexOptsSchema.optional(),\n })\n .default({})\n\nconst columnSchema = z\n .object({\n cast_as: castAsEnum,\n indexes: indexesSchema,\n })\n .default({})\n\nconst tableSchema = z.record(columnSchema).default({})\n\nconst tablesSchema = z.record(tableSchema).default({})\n\n/** @internal */\nexport const encryptConfigSchema = z.object({\n v: z.number(),\n tables: tablesSchema,\n})\n\n// ------------------------\n// Type definitions\n// ------------------------\n\n/**\n * Type-safe alias for {@link castAsEnum} used to specify the *unencrypted* data type of a column or value.\n * This is important because once encrypted, all data is stored as binary blobs.\n *\n * @see {@link castAsEnum} for possible values.\n */\nexport type CastAs = z.infer<typeof castAsEnum>\nexport type TokenFilter = z.infer<typeof tokenFilterSchema>\nexport type MatchIndexOpts = z.infer<typeof matchIndexOptsSchema>\nexport type SteVecIndexOpts = z.infer<typeof steVecIndexOptsSchema>\nexport type UniqueIndexOpts = z.infer<typeof uniqueIndexOptsSchema>\nexport type OreIndexOpts = z.infer<typeof oreIndexOptsSchema>\nexport type ColumnSchema = z.infer<typeof columnSchema>\n\nexport type ProtectTableColumn = {\n [key: string]:\n | ProtectColumn\n | {\n [key: string]:\n | ProtectValue\n | {\n [key: string]:\n | ProtectValue\n | {\n [key: string]: ProtectValue\n }\n }\n }\n}\nexport type EncryptConfig = z.infer<typeof encryptConfigSchema>\n\n// ------------------------\n// Interface definitions\n// ------------------------\nexport class ProtectValue {\n private valueName: string\n private castAsValue: CastAs\n\n constructor(valueName: string) {\n this.valueName = valueName\n this.castAsValue = 'string'\n }\n\n /**\n * Set or override the plaintext data type for this value.\n *\n * By default all values are treated as `'string'`. Use this method to specify\n * a different type so the encryption layer knows how to encode the plaintext\n * before encrypting.\n *\n * @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'bigint'`, or `'json'`.\n * @returns This `ProtectValue` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedValue } from \"@cipherstash/stack/schema\"\n *\n * const age = encryptedValue(\"age\").dataType(\"number\")\n * ```\n */\n dataType(castAs: CastAs) {\n this.castAsValue = castAs\n return this\n }\n\n build() {\n return {\n cast_as: this.castAsValue,\n indexes: {},\n }\n }\n\n getName() {\n return this.valueName\n }\n}\n\nexport class ProtectColumn {\n private columnName: string\n private castAsValue: CastAs\n private indexesValue: {\n ore?: OreIndexOpts\n unique?: UniqueIndexOpts\n match?: Required<MatchIndexOpts>\n ste_vec?: SteVecIndexOpts\n } = {}\n\n constructor(columnName: string) {\n this.columnName = columnName\n this.castAsValue = 'string'\n }\n\n /**\n * Set or override the plaintext data type for this column.\n *\n * By default all columns are treated as `'string'`. Use this method to specify\n * a different type so the encryption layer knows how to encode the plaintext\n * before encrypting.\n *\n * @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'bigint'`, or `'json'`.\n * @returns This `ProtectColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const dateOfBirth = encryptedColumn(\"date_of_birth\").dataType(\"date\")\n * ```\n */\n dataType(castAs: CastAs) {\n this.castAsValue = castAs\n return this\n }\n\n /**\n * Enable Order-Revealing Encryption (ORE) indexing on this column.\n *\n * ORE allows sorting, comparison, and range queries on encrypted data.\n * Use with `encryptQuery` and `queryType: 'orderAndRange'`.\n *\n * @returns This `ProtectColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").orderAndRange(),\n * })\n * ```\n */\n orderAndRange() {\n this.indexesValue.ore = {}\n return this\n }\n\n /**\n * Enable an exact-match (unique) index on this column.\n *\n * Allows equality queries on encrypted data. Use with `encryptQuery`\n * and `queryType: 'equality'`.\n *\n * @param tokenFilters - Optional array of token filters (e.g. `[{ kind: 'downcase' }]`).\n * When omitted, no token filters are applied.\n * @returns This `ProtectColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * })\n * ```\n */\n equality(tokenFilters?: TokenFilter[]) {\n this.indexesValue.unique = {\n token_filters: tokenFilters ?? [],\n }\n return this\n }\n\n /**\n * Enable a full-text / fuzzy search (match) index on this column.\n *\n * Uses n-gram tokenization by default for substring and fuzzy matching.\n * Use with `encryptQuery` and `queryType: 'freeTextSearch'`.\n *\n * @param opts - Optional match index configuration. Defaults to 3-character ngram\n * tokenization with a downcase filter, `k=6`, `m=2048`, and `include_original=true`.\n * @returns This `ProtectColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").freeTextSearch(),\n * })\n *\n * // With custom options\n * const posts = encryptedTable(\"posts\", {\n * body: encryptedColumn(\"body\").freeTextSearch({\n * tokenizer: { kind: \"ngram\", token_length: 4 },\n * k: 8,\n * m: 4096,\n * }),\n * })\n * ```\n */\n freeTextSearch(opts?: MatchIndexOpts) {\n // Provide defaults\n this.indexesValue.match = {\n tokenizer: opts?.tokenizer ?? { kind: 'ngram', token_length: 3 },\n token_filters: opts?.token_filters ?? [\n {\n kind: 'downcase',\n },\n ],\n k: opts?.k ?? 6,\n m: opts?.m ?? 2048,\n include_original: opts?.include_original ?? true,\n }\n return this\n }\n\n /**\n * Configure this column for searchable encrypted JSON (STE-Vec).\n *\n * Enables encrypted JSONPath selector queries (e.g. `'$.user.email'`) and\n * containment queries (e.g. `{ role: 'admin' }`). Automatically sets the\n * data type to `'json'`.\n *\n * When used with `encryptQuery`, the query operation is auto-inferred from\n * the plaintext type: strings become selector queries, objects/arrays become\n * containment queries.\n *\n * @returns This `ProtectColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const documents = encryptedTable(\"documents\", {\n * metadata: encryptedColumn(\"metadata\").searchableJson(),\n * })\n * ```\n */\n searchableJson() {\n this.castAsValue = 'json'\n this.indexesValue.ste_vec = { prefix: 'enabled' }\n return this\n }\n\n build() {\n return {\n cast_as: this.castAsValue,\n indexes: this.indexesValue,\n }\n }\n\n getName() {\n return this.columnName\n }\n}\n\ninterface TableDefinition {\n tableName: string\n columns: Record<string, ColumnSchema>\n}\n\nexport class ProtectTable<T extends ProtectTableColumn> {\n constructor(\n public readonly tableName: string,\n private readonly columnBuilders: T,\n ) {}\n\n /**\n * Compile this table schema into a `TableDefinition` used internally by the encryption client.\n *\n * Iterates over all column builders, calls `.build()` on each, and assembles\n * the final `{ tableName, columns }` structure. For `searchableJson()` columns,\n * the STE-Vec prefix is automatically set to `\"<tableName>/<columnName>\"`.\n *\n * @returns A `TableDefinition` containing the table name and built column configs.\n *\n * @example\n * ```typescript\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * })\n *\n * const definition = users.build()\n * // { tableName: \"users\", columns: { email: { cast_as: \"string\", indexes: { unique: ... } } } }\n * ```\n */\n build(): TableDefinition {\n const builtColumns: Record<string, ColumnSchema> = {}\n\n const processColumn = (\n builder:\n | ProtectColumn\n | Record<\n string,\n | ProtectValue\n | Record<\n string,\n | ProtectValue\n | Record<string, ProtectValue | Record<string, ProtectValue>>\n >\n >,\n colName: string,\n ) => {\n if (builder instanceof ProtectColumn) {\n const builtColumn = builder.build()\n\n // Hanlde building the ste_vec index for JSON columns so users don't have to pass the prefix.\n if (\n builtColumn.cast_as === 'json' &&\n builtColumn.indexes.ste_vec?.prefix === 'enabled'\n ) {\n builtColumns[colName] = {\n ...builtColumn,\n indexes: {\n ...builtColumn.indexes,\n ste_vec: {\n prefix: `${this.tableName}/${colName}`,\n },\n },\n }\n } else {\n builtColumns[colName] = builtColumn\n }\n } else {\n for (const [key, value] of Object.entries(builder)) {\n if (value instanceof ProtectValue) {\n builtColumns[value.getName()] = value.build()\n } else {\n processColumn(value, key)\n }\n }\n }\n }\n\n for (const [colName, builder] of Object.entries(this.columnBuilders)) {\n processColumn(builder, colName)\n }\n\n return {\n tableName: this.tableName,\n columns: builtColumns,\n }\n }\n}\n\n// ------------------------\n// Schema type inference helpers\n// ------------------------\n\n/**\n * Infer the plaintext (decrypted) type from a ProtectTable schema.\n *\n * @example\n * ```typescript\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * name: encryptedColumn(\"name\"),\n * })\n *\n * type UserPlaintext = InferPlaintext<typeof users>\n * // => { email: string; name: string }\n * ```\n */\nexport type InferPlaintext<T extends ProtectTable<any>> =\n T extends ProtectTable<infer C>\n ? {\n [K in keyof C as C[K] extends ProtectColumn | ProtectValue\n ? K\n : never]: string\n }\n : never\n\n/**\n * Infer the encrypted type from a ProtectTable schema.\n *\n * @example\n * ```typescript\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * })\n *\n * type UserEncrypted = InferEncrypted<typeof users>\n * // => { email: Encrypted }\n * ```\n */\nexport type InferEncrypted<T extends ProtectTable<any>> =\n T extends ProtectTable<infer C>\n ? {\n [K in keyof C as C[K] extends ProtectColumn | ProtectValue\n ? K\n : never]: Encrypted\n }\n : never\n\n// ------------------------\n// User facing functions\n// ------------------------\n\n/**\n * Define an encrypted table schema.\n *\n * Creates a `ProtectTable` that maps a database table name to a set of encrypted\n * column definitions. Pass the resulting object to `Encryption({ schemas: [...] })`\n * when initializing the client.\n *\n * The returned object is also a proxy that exposes each column builder directly,\n * so you can reference columns as `users.email` when calling `encrypt`, `decrypt`,\n * and `encryptQuery`.\n *\n * @param tableName - The name of the database table this schema represents.\n * @param columns - An object whose keys are logical column names and values are\n * `ProtectColumn` instances created with {@link encryptedColumn}.\n * @returns A `ProtectTable<T> & T` that can be used as both a schema definition\n * and a column accessor.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality().freeTextSearch(),\n * address: encryptedColumn(\"address\"),\n * })\n *\n * // Use as schema\n * const client = await Encryption({ schemas: [users] })\n *\n * // Use as column accessor\n * await client.encrypt(\"hello@example.com\", { column: users.email, table: users })\n * ```\n */\nexport function encryptedTable<T extends ProtectTableColumn>(\n tableName: string,\n columns: T,\n): ProtectTable<T> & T {\n const tableBuilder = new ProtectTable(tableName, columns) as ProtectTable<T> &\n T\n\n for (const [colName, colBuilder] of Object.entries(columns)) {\n ;(tableBuilder as ProtectTableColumn)[colName] = colBuilder\n }\n\n return tableBuilder\n}\n\n/**\n * Define an encrypted column within a table schema.\n *\n * Creates a `ProtectColumn` builder for the given column name. Chain index\n * methods (`.equality()`, `.freeTextSearch()`, `.orderAndRange()`,\n * `.searchableJson()`) and/or `.dataType()` to configure searchable encryption\n * and the plaintext data type.\n *\n * @param columnName - The name of the database column to encrypt.\n * @returns A new `ProtectColumn` builder.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality().freeTextSearch().orderAndRange(),\n * })\n * ```\n */\nexport function encryptedColumn(columnName: string) {\n return new ProtectColumn(columnName)\n}\n\n/**\n * Define an encrypted value for use in nested or structured schemas.\n *\n * `encryptedValue` is similar to {@link encryptedColumn} but creates a `ProtectValue`\n * intended for nested fields within a table schema. It supports `.dataType()`\n * for specifying the plaintext type.\n *\n * @param valueName - The name of the value field.\n * @returns A new `ProtectValue` builder.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedValue } from \"@cipherstash/stack/schema\"\n *\n * const orders = encryptedTable(\"orders\", {\n * details: {\n * amount: encryptedValue(\"amount\").dataType(\"number\"),\n * currency: encryptedValue(\"currency\"),\n * },\n * })\n * ```\n */\nexport function encryptedValue(valueName: string) {\n return new ProtectValue(valueName)\n}\n\n// ------------------------\n// Internal functions\n// ------------------------\n\n/** @internal */\nexport function buildEncryptConfig(\n ...protectTables: Array<ProtectTable<ProtectTableColumn>>\n): EncryptConfig {\n const config: EncryptConfig = {\n v: 2,\n tables: {},\n }\n\n for (const tb of protectTables) {\n const tableDef = tb.build()\n config.tables[tableDef.tableName] = tableDef.columns\n }\n\n return config\n}\n","import { type ProtectColumn, encryptedColumn, encryptedTable } from '@/schema'\nimport type { PgTable } from 'drizzle-orm/pg-core'\nimport { getEncryptedColumnConfig } from './index.js'\n\n/**\n * Extracts an encryption schema from a Drizzle table definition.\n * This function identifies columns created with `encryptedType` and\n * builds a corresponding `ProtectTable` with `encryptedColumn` definitions.\n *\n * @param table - The Drizzle table definition\n * @returns A ProtectTable that can be used with encryption client initialization\n *\n * @example\n * ```ts\n * const drizzleUsersTable = pgTable('users', {\n * email: encryptedType('email', { freeTextSearch: true, equality: true }),\n * age: encryptedType('age', { dataType: 'number', orderAndRange: true }),\n * })\n *\n * const encryptionSchema = extractEncryptionSchema(drizzleUsersTable)\n * const client = await createEncryptionClient({ schemas: [encryptionSchema.build()] })\n * ```\n */\n// We use any for the PgTable generic because we need to access Drizzle's internal properties\n// biome-ignore lint/suspicious/noExplicitAny: Drizzle table types don't expose Symbol properties\nexport function extractEncryptionSchema<T extends PgTable<any>>(\n table: T,\n): ReturnType<typeof encryptedTable<Record<string, ProtectColumn>>> {\n // Drizzle tables store the name in a Symbol property\n // biome-ignore lint/suspicious/noExplicitAny: Drizzle tables don't expose Symbol properties in types\n const tableName = (table as any)[Symbol.for('drizzle:Name')] as\n | string\n | undefined\n if (!tableName) {\n throw new Error(\n 'Unable to extract table name from Drizzle table. Ensure you are using a table created with pgTable().',\n )\n }\n\n const columns: Record<string, ProtectColumn> = {}\n\n // Iterate through table columns\n for (const [columnName, column] of Object.entries(table)) {\n // Skip if it's not a column (could be methods or other properties)\n if (typeof column !== 'object' || column === null) {\n continue\n }\n\n // Check if this column has encrypted configuration\n const config = getEncryptedColumnConfig(columnName, column)\n\n if (config) {\n // Extract the actual column name from the column object (not the schema key)\n // Drizzle columns have a 'name' property that contains the actual database column name\n const actualColumnName = column.name || config.name\n\n // This is an encrypted column - build encryptedColumn using the actual column name\n const csCol = encryptedColumn(actualColumnName)\n\n // Apply data type\n if (config.dataType && config.dataType !== 'string') {\n csCol.dataType(config.dataType)\n }\n\n // Apply indexes based on configuration\n if (config.orderAndRange) {\n csCol.orderAndRange()\n }\n\n if (config.equality) {\n if (Array.isArray(config.equality)) {\n // Custom token filters\n csCol.equality(config.equality)\n } else {\n // Default equality (boolean true)\n csCol.equality()\n }\n }\n\n if (config.freeTextSearch) {\n if (typeof config.freeTextSearch === 'object') {\n // Custom match options\n csCol.freeTextSearch(config.freeTextSearch)\n } else {\n // Default freeTextSearch (boolean true)\n csCol.freeTextSearch()\n }\n }\n\n if (config.searchableJson) {\n if (config.dataType !== 'json') {\n throw new Error(\n `Column \"${columnName}\" has searchableJson enabled but dataType is \"${config.dataType ?? 'string'}\". searchableJson requires dataType: 'json'.`,\n )\n }\n csCol.searchableJson()\n }\n\n columns[actualColumnName] = csCol\n }\n }\n\n if (Object.keys(columns).length === 0) {\n throw new Error(\n `No encrypted columns found in table \"${tableName}\". Use encryptedType() to define encrypted columns.`,\n )\n }\n\n return encryptedTable(tableName, columns)\n}\n","import type {\n ProtectColumn,\n ProtectTable,\n ProtectTableColumn,\n ProtectValue,\n} from '@/schema'\nimport type { LoggingConfig } from '@/utils/logger'\nimport type {\n Encrypted as CipherStashEncrypted,\n JsPlaintext,\n QueryOpName,\n newClient,\n} from '@cipherstash/protect-ffi'\n\n// ---------------------------------------------------------------------------\n// Branded type utilities\n// ---------------------------------------------------------------------------\n\n/** Brand symbol for nominal typing */\ndeclare const __brand: unique symbol\n\n/** Creates a branded type that is structurally incompatible with the base type */\ntype Brand<T, B extends string> = T & { readonly [__brand]: B }\n\n// ---------------------------------------------------------------------------\n// Core types\n// ---------------------------------------------------------------------------\n\nexport type Client = Awaited<ReturnType<typeof newClient>> | undefined\n\n/** A branded type representing encrypted data. Cannot be accidentally used as plaintext. */\nexport type EncryptedValue = Brand<CipherStashEncrypted, 'encrypted'> | null\n\n/** Structural type representing encrypted data. See also `EncryptedValue` for branded nominal typing. */\nexport type Encrypted = CipherStashEncrypted | null\n\nexport type EncryptPayload = JsPlaintext | null\n\n// ---------------------------------------------------------------------------\n// Client configuration\n// ---------------------------------------------------------------------------\n\nexport type KeysetIdentifier = { name: string } | { id: string }\n\nexport type ClientConfig = {\n /**\n * The CipherStash workspace CRN (Cloud Resource Name).\n * Format: `crn:<region>.aws:<workspace-id>`.\n * Can also be set via the `CS_WORKSPACE_CRN` environment variable.\n * If omitted, the SDK reads from the environment or TOML config files.\n */\n workspaceCrn?: string\n\n /**\n * The API access key used for authenticating with the CipherStash API.\n * Can also be set via the `CS_CLIENT_ACCESS_KEY` environment variable.\n * Obtain this from the CipherStash dashboard after creating a workspace.\n */\n accessKey?: string\n\n /**\n * The client identifier used to authenticate with CipherStash services.\n * Can also be set via the `CS_CLIENT_ID` environment variable.\n * Generated during workspace onboarding in the CipherStash dashboard.\n */\n clientId?: string\n\n /**\n * The client key material used in combination with ZeroKMS for encryption operations.\n * Can also be set via the `CS_CLIENT_KEY` environment variable.\n * Generated during workspace onboarding in the CipherStash dashboard.\n */\n clientKey?: string\n\n /**\n * An optional keyset identifier for multi-tenant encryption.\n * Each keyset provides cryptographic isolation, giving each tenant its own keyspace.\n * Specify by name (`{ name: \"tenant-a\" }`) or UUID (`{ id: \"...\" }`).\n * Keysets are created and managed in the CipherStash dashboard.\n */\n keyset?: KeysetIdentifier\n}\n\ntype AtLeastOneCsTable<T> = [T, ...T[]]\n\nexport type EncryptionClientConfig = {\n schemas: AtLeastOneCsTable<ProtectTable<ProtectTableColumn>>\n config?: ClientConfig\n logging?: LoggingConfig\n}\n\n// ---------------------------------------------------------------------------\n// Encrypt / decrypt operation options and results\n// ---------------------------------------------------------------------------\n\nexport type EncryptOptions = {\n column: ProtectColumn | ProtectValue\n table: ProtectTable<ProtectTableColumn>\n}\n\n/** Format for encrypted query/search term return values */\nexport type EncryptedReturnType =\n | 'eql'\n | 'composite-literal'\n | 'escaped-composite-literal'\n\nexport type SearchTerm = {\n value: JsPlaintext\n column: ProtectColumn\n table: ProtectTable<ProtectTableColumn>\n returnType?: EncryptedReturnType\n}\n\n/** Encrypted search term result: EQL object or composite literal string */\nexport type EncryptedSearchTerm = Encrypted | string\n\n/** Result of encryptQuery (single or batch): EQL, composite literal string, or null */\nexport type EncryptedQueryResult = Encrypted | string | null\n\n// ---------------------------------------------------------------------------\n// Model field types (encrypted vs decrypted views)\n// ---------------------------------------------------------------------------\n\nexport type EncryptedFields<T> = {\n [K in keyof T as T[K] extends Encrypted ? K : never]: T[K]\n}\n\nexport type OtherFields<T> = {\n [K in keyof T as T[K] extends Encrypted ? never : K]: T[K]\n}\n\nexport type DecryptedFields<T> = {\n [K in keyof T as T[K] extends Encrypted ? K : never]: string\n}\n\n/** Model with encrypted fields replaced by plaintext (decrypted) values */\nexport type Decrypted<T> = OtherFields<T> & DecryptedFields<T>\n\n/**\n * Maps a plaintext model type to its encrypted form using the table schema.\n *\n * Fields whose keys match columns defined in `S` become `Encrypted`;\n * all other fields retain their original types from `T`.\n *\n * When `S` is the widened `ProtectTableColumn` (e.g. when a user passes an\n * explicit `<User>` type argument without specifying `S`), the type degrades\n * gracefully to `T` — preserving backward compatibility.\n *\n * @typeParam T - The plaintext model type (e.g. `{ id: string; email: string }`)\n * @typeParam S - The table schema column definition, inferred from the `table` argument\n *\n * @example\n * ```typescript\n * type User = { id: string; email: string }\n * // With a schema that defines `email`:\n * type Encrypted = EncryptedFromSchema<User, { email: ProtectColumn }>\n * // => { id: string; email: Encrypted }\n * ```\n */\nexport type EncryptedFromSchema<\n T,\n S extends ProtectTableColumn,\n> = {\n [K in keyof T]: [K] extends [keyof S]\n ? [S[K & keyof S]] extends [ProtectColumn | ProtectValue]\n ? Encrypted\n : T[K]\n : T[K]\n}\n\n// ---------------------------------------------------------------------------\n// Bulk operations\n// ---------------------------------------------------------------------------\n\nexport type BulkEncryptPayload = Array<{\n id?: string\n plaintext: JsPlaintext | null\n}>\n\nexport type BulkEncryptedData = Array<{ id?: string; data: Encrypted }>\nexport type BulkDecryptPayload = Array<{ id?: string; data: Encrypted }>\nexport type BulkDecryptedData = Array<DecryptionResult<JsPlaintext | null>>\n\ntype DecryptionSuccess<T> = { error?: never; data: T; id?: string }\ntype DecryptionError<T> = { error: T; id?: string; data?: never }\n\n/**\n * Result type for individual items in bulk decrypt operations.\n * Uses `error`/`data` fields (not `failure`/`data`) since bulk operations\n * can have per-item failures.\n */\nexport type DecryptionResult<T> = DecryptionSuccess<T> | DecryptionError<T>\n\n// ---------------------------------------------------------------------------\n// Query types (for searchable encryption / encryptQuery)\n// ---------------------------------------------------------------------------\n\n/**\n * User-facing query type names for encrypting query values.\n *\n * - `'equality'`: Exact match. [Exact Queries](https://cipherstash.com/docs/platform/searchable-encryption/supported-queries/exact)\n * - `'freeTextSearch'`: Text search. [Match Queries](https://cipherstash.com/docs/platform/searchable-encryption/supported-queries/match)\n * - `'orderAndRange'`: Comparison and range. [Range Queries](https://cipherstash.com/docs/platform/searchable-encryption/supported-queries/range)\n * - `'steVecSelector'`: JSONPath selector (e.g. `'$.user.email'`)\n * - `'steVecTerm'`: Containment (e.g. `{ role: 'admin' }`)\n * - `'searchableJson'`: Auto-infers selector or term from plaintext type (recommended)\n */\nexport type QueryTypeName =\n | 'orderAndRange'\n | 'freeTextSearch'\n | 'equality'\n | 'steVecSelector'\n | 'steVecTerm'\n | 'searchableJson'\n\n/** @internal */\nexport type FfiIndexTypeName = 'ore' | 'match' | 'unique' | 'ste_vec'\n\nexport const queryTypes = {\n orderAndRange: 'orderAndRange',\n freeTextSearch: 'freeTextSearch',\n equality: 'equality',\n steVecSelector: 'steVecSelector',\n steVecTerm: 'steVecTerm',\n searchableJson: 'searchableJson',\n} as const satisfies Record<string, QueryTypeName>\n\n/** @internal */\nexport const queryTypeToFfi: Record<QueryTypeName, FfiIndexTypeName> = {\n orderAndRange: 'ore',\n freeTextSearch: 'match',\n equality: 'unique',\n steVecSelector: 'ste_vec',\n steVecTerm: 'ste_vec',\n searchableJson: 'ste_vec',\n}\n\n/** @internal */\nexport const queryTypeToQueryOp: Partial<Record<QueryTypeName, QueryOpName>> = {\n steVecSelector: 'ste_vec_selector',\n steVecTerm: 'ste_vec_term',\n}\n\n/** @internal */\nexport type QueryTermBase = {\n column: ProtectColumn\n table: ProtectTable<ProtectTableColumn>\n queryType?: QueryTypeName\n returnType?: EncryptedReturnType\n}\n\nexport type EncryptQueryOptions = QueryTermBase\n\nexport type ScalarQueryTerm = QueryTermBase & {\n value: JsPlaintext | null\n}\n","import type { EncryptionClient } from '@/encryption/ffi'\nimport type { ProtectColumn, ProtectTable, ProtectTableColumn } from '@/schema'\nimport { type QueryTypeName, queryTypes } from '@/types'\nimport {\n type SQL,\n type SQLWrapper,\n and,\n arrayContained,\n arrayContains,\n arrayOverlaps,\n asc,\n between,\n desc,\n eq,\n exists,\n gt,\n gte,\n ilike,\n inArray,\n isNotNull,\n isNull,\n like,\n lt,\n lte,\n ne,\n not,\n notBetween,\n notExists,\n notIlike,\n notInArray,\n or,\n} from 'drizzle-orm'\nimport { bindIfParam, sql } from 'drizzle-orm'\nimport type { PgTable } from 'drizzle-orm/pg-core'\nimport type { EncryptedColumnConfig } from './index.js'\nimport { getEncryptedColumnConfig } from './index.js'\nimport { extractEncryptionSchema } from './schema-extraction.js'\n\n// ============================================================================\n// Type Definitions and Type Guards\n// ============================================================================\n\n/**\n * Branded type for Drizzle table with encrypted columns\n */\n// biome-ignore lint/suspicious/noExplicitAny: Drizzle table types don't expose Symbol properties\ntype EncryptedDrizzleTable = PgTable<any> & {\n readonly __isEncryptedTable?: true\n}\n\n/**\n * Type guard to check if a value is a Drizzle SQLWrapper\n */\nfunction isSQLWrapper(value: unknown): value is SQLWrapper {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'sql' in value &&\n typeof (value as { sql: unknown }).sql !== 'undefined'\n )\n}\n\n/**\n * Type guard to check if a value is a Drizzle table\n */\nfunction isPgTable(value: unknown): value is EncryptedDrizzleTable {\n return (\n typeof value === 'object' &&\n value !== null &&\n Symbol.for('drizzle:Name') in value\n )\n}\n\n/**\n * Custom error types for better debugging\n */\nexport class EncryptionOperatorError extends Error {\n constructor(\n message: string,\n public readonly context?: {\n tableName?: string\n columnName?: string\n operator?: string\n },\n ) {\n super(message)\n this.name = 'EncryptionOperatorError'\n }\n}\n\nexport class EncryptionConfigError extends EncryptionOperatorError {\n constructor(message: string, context?: EncryptionOperatorError['context']) {\n super(message, context)\n this.name = 'EncryptionConfigError'\n }\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Helper to extract table name from a Drizzle table\n */\nfunction getDrizzleTableName(drizzleTable: unknown): string | undefined {\n if (!isPgTable(drizzleTable)) {\n return undefined\n }\n // Access Symbol property using Record type to avoid indexing errors\n const tableWithSymbol = drizzleTable as unknown as Record<\n symbol,\n string | undefined\n >\n return tableWithSymbol[Symbol.for('drizzle:Name')]\n}\n\n/**\n * Helper to get the drizzle table from a drizzle column\n */\nfunction getDrizzleTableFromColumn(drizzleColumn: SQLWrapper): unknown {\n const column = drizzleColumn as unknown as Record<string, unknown>\n return column.table as unknown\n}\n\n/**\n * Helper to extract encrypted table from a drizzle column by deriving it from the column's parent table\n */\nfunction getEncryptedTableFromColumn(\n drizzleColumn: SQLWrapper,\n tableCache: Map<string, ProtectTable<ProtectTableColumn>>,\n): ProtectTable<ProtectTableColumn> | undefined {\n const drizzleTable = getDrizzleTableFromColumn(drizzleColumn)\n if (!drizzleTable) {\n return undefined\n }\n\n const tableName = getDrizzleTableName(drizzleTable)\n if (!tableName) {\n return undefined\n }\n\n // Check cache first\n let encryptedTable = tableCache.get(tableName)\n if (encryptedTable) {\n return encryptedTable\n }\n\n // Extract encryption schema from drizzle table and cache it\n try {\n // biome-ignore lint/suspicious/noExplicitAny: PgTable type doesn't expose all needed properties\n encryptedTable = extractEncryptionSchema(drizzleTable as PgTable<any>)\n tableCache.set(tableName, encryptedTable)\n return encryptedTable\n } catch {\n // Table doesn't have encrypted columns or extraction failed\n return undefined\n }\n}\n\n/**\n * Helper to get the encrypted column definition for a Drizzle column from the encrypted table\n */\nfunction getEncryptedColumn(\n drizzleColumn: SQLWrapper,\n encryptedTable: ProtectTable<ProtectTableColumn>,\n): ProtectColumn | undefined {\n const column = drizzleColumn as unknown as Record<string, unknown>\n const columnName = column.name as string | undefined\n if (!columnName) {\n return undefined\n }\n\n const tableRecord = encryptedTable as unknown as Record<string, unknown>\n return tableRecord[columnName] as ProtectColumn | undefined\n}\n\n/**\n * Column metadata extracted from a Drizzle column\n */\ninterface ColumnInfo {\n readonly encryptedColumn: ProtectColumn | undefined\n readonly config: (EncryptedColumnConfig & { name: string }) | undefined\n readonly encryptedTable: ProtectTable<ProtectTableColumn> | undefined\n readonly columnName: string\n readonly tableName: string | undefined\n}\n\n/**\n * Helper to get the encrypted column and column config for a Drizzle column\n * If encryptedTable is not provided, it will be derived from the column\n */\nfunction getColumnInfo(\n drizzleColumn: SQLWrapper,\n encryptedTable: ProtectTable<ProtectTableColumn> | undefined,\n tableCache: Map<string, ProtectTable<ProtectTableColumn>>,\n): ColumnInfo {\n const column = drizzleColumn as unknown as Record<string, unknown>\n const columnName = (column.name as string | undefined) || 'unknown'\n\n // If encryptedTable not provided, try to derive it from the column\n let resolvedTable = encryptedTable\n if (!resolvedTable) {\n resolvedTable = getEncryptedTableFromColumn(drizzleColumn, tableCache)\n }\n\n const drizzleTable = getDrizzleTableFromColumn(drizzleColumn)\n const tableName = getDrizzleTableName(drizzleTable)\n\n if (!resolvedTable) {\n // Column is not from an encrypted table\n const config = getEncryptedColumnConfig(columnName, drizzleColumn)\n return {\n encryptedColumn: undefined,\n config,\n encryptedTable: undefined,\n columnName,\n tableName,\n }\n }\n\n const encryptedColumn = getEncryptedColumn(drizzleColumn, resolvedTable)\n const config = getEncryptedColumnConfig(columnName, drizzleColumn)\n\n return {\n encryptedColumn,\n config,\n encryptedTable: resolvedTable,\n columnName,\n tableName,\n }\n}\n\n/**\n * Helper to convert a value to plaintext format\n */\nfunction toPlaintext(value: unknown): string | number {\n if (typeof value === 'boolean') {\n return value ? 1 : 0\n }\n if (typeof value === 'string' || typeof value === 'number') {\n return value\n }\n if (value instanceof Date) {\n return value.toISOString()\n }\n return String(value)\n}\n\n/**\n * Value to encrypt with its associated column\n */\ninterface ValueToEncrypt {\n readonly value: string | number\n readonly column: SQLWrapper\n readonly columnInfo: ColumnInfo\n readonly queryType?: QueryTypeName\n readonly originalIndex: number\n}\n\n/**\n * Helper to encrypt multiple values for use in a query\n * Returns an array of encrypted search terms or original values if not encrypted\n */\nasync function encryptValues(\n encryptionClient: EncryptionClient,\n values: Array<{\n value: unknown\n column: SQLWrapper\n queryType?: QueryTypeName\n }>,\n encryptedTable: ProtectTable<ProtectTableColumn> | undefined,\n tableCache: Map<string, ProtectTable<ProtectTableColumn>>,\n): Promise<unknown[]> {\n if (values.length === 0) {\n return []\n }\n\n // Single pass: collect values to encrypt with their metadata\n const valuesToEncrypt: ValueToEncrypt[] = []\n const results: unknown[] = new Array(values.length)\n\n for (let i = 0; i < values.length; i++) {\n const { value, column, queryType } = values[i]\n const columnInfo = getColumnInfo(column, encryptedTable, tableCache)\n\n if (\n !columnInfo.encryptedColumn ||\n !columnInfo.config ||\n !columnInfo.encryptedTable\n ) {\n // Column is not encrypted, return value as-is\n results[i] = value\n continue\n }\n\n const plaintextValue = toPlaintext(value)\n valuesToEncrypt.push({\n value: plaintextValue,\n column,\n columnInfo,\n queryType,\n originalIndex: i,\n })\n }\n\n if (valuesToEncrypt.length === 0) {\n return results\n }\n\n // Group values by column to batch encrypt with same column/table\n const columnGroups = new Map<\n string,\n {\n column: ProtectColumn\n table: ProtectTable<ProtectTableColumn>\n columnName: string\n values: Array<{\n value: string | number\n index: number\n queryType?: QueryTypeName\n }>\n resultIndices: number[]\n }\n >()\n\n let valueIndex = 0\n for (const {\n value,\n columnInfo,\n queryType,\n originalIndex,\n } of valuesToEncrypt) {\n // Safe access with validation - we know these exist from earlier checks\n if (\n !columnInfo.config ||\n !columnInfo.encryptedColumn ||\n !columnInfo.encryptedTable\n ) {\n continue\n }\n\n const columnName = columnInfo.config.name\n const groupKey = `${columnInfo.tableName ?? 'unknown'}/${columnName}`\n let group = columnGroups.get(groupKey)\n if (!group) {\n group = {\n column: columnInfo.encryptedColumn,\n table: columnInfo.encryptedTable,\n columnName,\n values: [],\n resultIndices: [],\n }\n columnGroups.set(groupKey, group)\n }\n group.values.push({ value, index: valueIndex++, queryType })\n group.resultIndices.push(originalIndex)\n }\n\n // Encrypt all values for each column in batches\n for (const [, group] of columnGroups) {\n const { columnName } = group\n try {\n const terms = group.values.map((v) => ({\n value: v.value,\n column: group.column,\n table: group.table,\n queryType: v.queryType,\n }))\n\n const encryptedTerms = await encryptionClient.encryptQuery(terms)\n\n if (encryptedTerms.failure) {\n throw new EncryptionOperatorError(\n `Failed to encrypt query terms for column \"${columnName}\": ${encryptedTerms.failure.message}`,\n { columnName },\n )\n }\n\n // Map results back to original indices\n for (let i = 0; i < group.values.length; i++) {\n const resultIndex = group.resultIndices[i] ?? -1\n if (resultIndex >= 0 && resultIndex < results.length) {\n results[resultIndex] = encryptedTerms.data[i]\n }\n }\n } catch (error) {\n if (error instanceof EncryptionOperatorError) {\n throw error\n }\n const errorMessage =\n error instanceof Error ? error.message : String(error)\n throw new EncryptionOperatorError(\n `Unexpected error encrypting values for column \"${columnName}\": ${errorMessage}`,\n { columnName },\n )\n }\n }\n\n return results\n}\n\n/**\n * Helper to encrypt a single value for use in a query\n * Returns the encrypted search term or the original value if not encrypted\n */\nasync function encryptValue(\n encryptionClient: EncryptionClient,\n value: unknown,\n drizzleColumn: SQLWrapper,\n encryptedTable: ProtectTable<ProtectTableColumn> | undefined,\n tableCache: Map<string, ProtectTable<ProtectTableColumn>>,\n queryType?: QueryTypeName,\n): Promise<unknown> {\n const results = await encryptValues(\n encryptionClient,\n [{ value, column: drizzleColumn, queryType }],\n encryptedTable,\n tableCache,\n )\n return results[0]\n}\n\n// ============================================================================\n// Lazy Operator Pattern\n// ============================================================================\n\n/**\n * Simplified lazy operator that defers encryption until awaited or batched\n */\ninterface LazyOperator {\n readonly __isLazyOperator: true\n readonly operator: string\n readonly queryType?: QueryTypeName\n readonly left: SQLWrapper\n readonly right: unknown\n readonly min?: unknown\n readonly max?: unknown\n readonly needsEncryption: boolean\n readonly columnInfo: ColumnInfo\n execute(\n encrypted: unknown,\n encryptedMin?: unknown,\n encryptedMax?: unknown,\n ): SQL\n}\n\n/**\n * Type guard for lazy operators\n */\nfunction isLazyOperator(value: unknown): value is LazyOperator {\n return (\n typeof value === 'object' &&\n value !== null &&\n '__isLazyOperator' in value &&\n (value as LazyOperator).__isLazyOperator === true\n )\n}\n\n/**\n * Creates a lazy operator that defers execution\n */\nfunction createLazyOperator(\n operator: string,\n left: SQLWrapper,\n right: unknown,\n execute: (\n encrypted: unknown,\n encryptedMin?: unknown,\n encryptedMax?: unknown,\n ) => SQL,\n needsEncryption: boolean,\n columnInfo: ColumnInfo,\n encryptionClient: EncryptionClient,\n defaultTable: ProtectTable<ProtectTableColumn> | undefined,\n tableCache: Map<string, ProtectTable<ProtectTableColumn>>,\n min?: unknown,\n max?: unknown,\n queryType?: QueryTypeName,\n): LazyOperator & Promise<SQL> {\n let resolvedSQL: SQL | undefined\n let encryptionPromise: Promise<SQL> | undefined\n\n const lazyOp: LazyOperator = {\n __isLazyOperator: true,\n operator,\n queryType,\n left,\n right,\n min,\n max,\n needsEncryption,\n columnInfo,\n execute,\n }\n\n // Create a promise that will be resolved when encryption completes\n const promise = new Promise<SQL>((resolve, reject) => {\n // Auto-execute when awaited directly\n queueMicrotask(async () => {\n if (resolvedSQL !== undefined) {\n resolve(resolvedSQL)\n return\n }\n\n try {\n if (!encryptionPromise) {\n encryptionPromise = executeLazyOperatorDirect(\n lazyOp,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n const sql = await encryptionPromise\n resolvedSQL = sql\n resolve(sql)\n } catch (error) {\n reject(error)\n }\n })\n })\n\n // Attach lazy operator properties to the promise\n return Object.assign(promise, lazyOp)\n}\n\n/**\n * Executes a lazy operator with pre-encrypted values (used in batched mode)\n */\nasync function executeLazyOperator(\n lazyOp: LazyOperator,\n encryptedValues?: { value: unknown; encrypted: unknown }[],\n): Promise<SQL> {\n if (!lazyOp.needsEncryption) {\n return lazyOp.execute(lazyOp.right)\n }\n\n if (lazyOp.min !== undefined && lazyOp.max !== undefined) {\n // Between operator - use provided encrypted values\n let encryptedMin: unknown\n let encryptedMax: unknown\n\n if (encryptedValues && encryptedValues.length >= 2) {\n encryptedMin = encryptedValues[0]?.encrypted\n encryptedMax = encryptedValues[1]?.encrypted\n } else {\n throw new EncryptionOperatorError(\n 'Between operator requires both min and max encrypted values',\n {\n columnName: lazyOp.columnInfo.columnName,\n tableName: lazyOp.columnInfo.tableName,\n operator: lazyOp.operator,\n },\n )\n }\n\n if (encryptedMin === undefined || encryptedMax === undefined) {\n throw new EncryptionOperatorError(\n 'Between operator requires both min and max values to be encrypted',\n {\n columnName: lazyOp.columnInfo.columnName,\n tableName: lazyOp.columnInfo.tableName,\n operator: lazyOp.operator,\n },\n )\n }\n\n return lazyOp.execute(undefined, encryptedMin, encryptedMax)\n }\n\n // Single value operator\n let encrypted: unknown\n\n if (encryptedValues && encryptedValues.length > 0) {\n encrypted = encryptedValues[0]?.encrypted\n } else {\n throw new EncryptionOperatorError(\n 'Operator requires encrypted value but none provided',\n {\n columnName: lazyOp.columnInfo.columnName,\n tableName: lazyOp.columnInfo.tableName,\n operator: lazyOp.operator,\n },\n )\n }\n\n if (encrypted === undefined) {\n throw new EncryptionOperatorError(\n 'Encryption failed or value was not encrypted',\n {\n columnName: lazyOp.columnInfo.columnName,\n tableName: lazyOp.columnInfo.tableName,\n operator: lazyOp.operator,\n },\n )\n }\n\n return lazyOp.execute(encrypted)\n}\n\n/**\n * Executes a lazy operator directly by encrypting values on demand\n * Used when operator is awaited directly (not batched)\n */\nasync function executeLazyOperatorDirect(\n lazyOp: LazyOperator,\n encryptionClient: EncryptionClient,\n defaultTable: ProtectTable<ProtectTableColumn> | undefined,\n tableCache: Map<string, ProtectTable<ProtectTableColumn>>,\n): Promise<SQL> {\n if (!lazyOp.needsEncryption) {\n return lazyOp.execute(lazyOp.right)\n }\n\n if (lazyOp.min !== undefined && lazyOp.max !== undefined) {\n // Between operator - encrypt min and max\n const [encryptedMin, encryptedMax] = await encryptValues(\n encryptionClient,\n [\n { value: lazyOp.min, column: lazyOp.left, queryType: lazyOp.queryType },\n { value: lazyOp.max, column: lazyOp.left, queryType: lazyOp.queryType },\n ],\n defaultTable,\n tableCache,\n )\n return lazyOp.execute(undefined, encryptedMin, encryptedMax)\n }\n\n // Single value operator\n const encrypted = await encryptValue(\n encryptionClient,\n lazyOp.right,\n lazyOp.left,\n defaultTable,\n tableCache,\n lazyOp.queryType,\n )\n\n return lazyOp.execute(encrypted)\n}\n\n// ============================================================================\n// Operator Factory Functions\n// ============================================================================\n\n/**\n * Creates a comparison operator (eq, ne, gt, gte, lt, lte)\n */\nfunction createComparisonOperator(\n operator: 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte',\n left: SQLWrapper,\n right: unknown,\n columnInfo: ColumnInfo,\n encryptionClient: EncryptionClient,\n defaultTable: ProtectTable<ProtectTableColumn> | undefined,\n tableCache: Map<string, ProtectTable<ProtectTableColumn>>,\n): Promise<SQL> | SQL {\n const { config } = columnInfo\n\n // Operators requiring orderAndRange index\n const requiresOrderAndRange = ['gt', 'gte', 'lt', 'lte'].includes(operator)\n\n if (requiresOrderAndRange) {\n if (!config?.orderAndRange) {\n // Return regular Drizzle operator for non-encrypted columns\n switch (operator) {\n case 'gt':\n return gt(left, right)\n case 'gte':\n return gte(left, right)\n case 'lt':\n return lt(left, right)\n case 'lte':\n return lte(left, right)\n }\n }\n\n // This will be replaced with encrypted value in executeLazyOperator\n const executeFn = (encrypted: unknown) => {\n if (encrypted === undefined) {\n throw new EncryptionOperatorError(\n `Encryption failed for ${operator} operator`,\n {\n columnName: columnInfo.columnName,\n tableName: columnInfo.tableName,\n operator,\n },\n )\n }\n return sql`eql_v2.${sql.raw(operator)}(${left}, ${bindIfParam(encrypted, left)})`\n }\n\n return createLazyOperator(\n operator,\n left,\n right,\n executeFn,\n true,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n undefined, // min\n undefined, // max\n queryTypes.orderAndRange,\n ) as Promise<SQL>\n }\n\n // Equality operators (eq, ne)\n const requiresEquality = ['eq', 'ne'].includes(operator)\n\n if (requiresEquality && config?.equality) {\n const executeFn = (encrypted: unknown) => {\n if (encrypted === undefined) {\n throw new EncryptionOperatorError(\n `Encryption failed for ${operator} operator`,\n {\n columnName: columnInfo.columnName,\n tableName: columnInfo.tableName,\n operator,\n },\n )\n }\n return operator === 'eq' ? eq(left, encrypted) : ne(left, encrypted)\n }\n\n return createLazyOperator(\n operator,\n left,\n right,\n executeFn,\n true,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n undefined, // min\n undefined, // max\n queryTypes.equality,\n ) as Promise<SQL>\n }\n\n // Fallback to regular Drizzle operators\n return operator === 'eq' ? eq(left, right) : ne(left, right)\n}\n\n/**\n * Creates a range operator (between, notBetween)\n */\nfunction createRangeOperator(\n operator: 'between' | 'notBetween',\n left: SQLWrapper,\n min: unknown,\n max: unknown,\n columnInfo: ColumnInfo,\n encryptionClient: EncryptionClient,\n defaultTable: ProtectTable<ProtectTableColumn> | undefined,\n tableCache: Map<string, ProtectTable<ProtectTableColumn>>,\n): Promise<SQL> | SQL {\n const { config } = columnInfo\n\n if (!config?.orderAndRange) {\n return operator === 'between'\n ? between(left, min, max)\n : notBetween(left, min, max)\n }\n\n const executeFn = (\n _encrypted: unknown,\n encryptedMin?: unknown,\n encryptedMax?: unknown,\n ) => {\n if (encryptedMin === undefined || encryptedMax === undefined) {\n throw new EncryptionOperatorError(\n `${operator} operator requires both min and max values`,\n {\n columnName: columnInfo.columnName,\n tableName: columnInfo.tableName,\n operator,\n },\n )\n }\n\n const rangeCondition = sql`eql_v2.gte(${left}, ${bindIfParam(encryptedMin, left)}) AND eql_v2.lte(${left}, ${bindIfParam(encryptedMax, left)})`\n\n return operator === 'between'\n ? rangeCondition\n : sql`NOT (${rangeCondition})`\n }\n\n return createLazyOperator(\n operator,\n left,\n undefined,\n executeFn,\n true,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n min,\n max,\n queryTypes.orderAndRange,\n ) as Promise<SQL>\n}\n\n/**\n * Creates a text search operator (like, ilike, notIlike)\n */\nfunction createTextSearchOperator(\n operator: 'like' | 'ilike' | 'notIlike',\n left: SQLWrapper,\n right: unknown,\n columnInfo: ColumnInfo,\n encryptionClient: EncryptionClient,\n defaultTable: ProtectTable<ProtectTableColumn> | undefined,\n tableCache: Map<string, ProtectTable<ProtectTableColumn>>,\n): Promise<SQL> | SQL {\n const { config } = columnInfo\n\n if (!config?.freeTextSearch) {\n // Cast to satisfy TypeScript\n const rightValue = right as string | SQLWrapper\n switch (operator) {\n case 'like':\n return like(left as Parameters<typeof like>[0], rightValue)\n case 'ilike':\n return ilike(left as Parameters<typeof ilike>[0], rightValue)\n case 'notIlike':\n return notIlike(left as Parameters<typeof notIlike>[0], rightValue)\n }\n }\n\n const executeFn = (encrypted: unknown) => {\n if (encrypted === undefined) {\n throw new EncryptionOperatorError(\n `Encryption failed for ${operator} operator`,\n {\n columnName: columnInfo.columnName,\n tableName: columnInfo.tableName,\n operator,\n },\n )\n }\n\n const sqlFn = sql`eql_v2.${sql.raw(operator === 'notIlike' ? 'ilike' : operator)}(${left}, ${bindIfParam(encrypted, left)})`\n return operator === 'notIlike' ? sql`NOT (${sqlFn})` : sqlFn\n }\n\n return createLazyOperator(\n operator,\n left,\n right,\n executeFn,\n true,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n undefined, // min\n undefined, // max\n queryTypes.freeTextSearch,\n ) as Promise<SQL>\n}\n\n/**\n * Creates a JSONB operator that encrypts a JSON path selector and wraps it\n * in the appropriate `eql_v2` function call.\n *\n * Supports `jsonbPathQueryFirst`, `jsonbGet`, and `jsonbPathExists`.\n * The column must have `searchableJson` enabled in its {@link EncryptedColumnConfig}.\n */\nfunction createJsonbOperator(\n operator: 'jsonbPathQueryFirst' | 'jsonbGet' | 'jsonbPathExists',\n left: SQLWrapper,\n right: unknown,\n columnInfo: ColumnInfo,\n encryptionClient: EncryptionClient,\n defaultTable: ProtectTable<ProtectTableColumn> | undefined,\n tableCache: Map<string, ProtectTable<ProtectTableColumn>>,\n): Promise<SQL> {\n const { config } = columnInfo\n const encryptedSelector = (value: unknown) =>\n sql`${bindIfParam(value, left)}::eql_v2_encrypted`\n\n if (!config?.searchableJson) {\n throw new EncryptionOperatorError(\n `The ${operator} operator requires searchableJson to be enabled on the column configuration.`,\n {\n columnName: columnInfo.columnName,\n tableName: columnInfo.tableName,\n operator,\n },\n )\n }\n\n const executeFn = (encrypted: unknown) => {\n if (encrypted === undefined) {\n throw new EncryptionOperatorError(\n `Encryption failed for ${operator} operator`,\n {\n columnName: columnInfo.columnName,\n tableName: columnInfo.tableName,\n operator,\n },\n )\n }\n switch (operator) {\n case 'jsonbPathQueryFirst':\n return sql`eql_v2.jsonb_path_query_first(${left}, ${encryptedSelector(encrypted)})`\n case 'jsonbGet':\n return sql`${left} -> ${encryptedSelector(encrypted)}`\n case 'jsonbPathExists':\n return sql`eql_v2.jsonb_path_exists(${left}, ${encryptedSelector(encrypted)})`\n }\n }\n\n return createLazyOperator(\n operator,\n left,\n right,\n executeFn,\n true,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n undefined,\n undefined,\n queryTypes.steVecSelector,\n ) as Promise<SQL>\n}\n\n// ============================================================================\n// Public API: createEncryptionOperators\n// ============================================================================\n\n/**\n * Creates a set of encryption-aware operators that automatically encrypt values\n * for encrypted columns before using them with Drizzle operators.\n *\n * For equality and text search operators (eq, ne, like, ilike, inArray, etc.):\n * Values are encrypted and then passed to regular Drizzle operators, which use\n * PostgreSQL's built-in operators for eql_v2_encrypted types.\n *\n * For order and range operators (gt, gte, lt, lte, between, notBetween):\n * Values are encrypted and then use eql_v2.* functions (eql_v2.gt(), eql_v2.gte(), etc.)\n * which are required for ORE (Order-Revealing Encryption) comparisons.\n *\n * @param encryptionClient - The EncryptionClient instance\n * @returns An object with all Drizzle operators wrapped for encrypted columns\n *\n * @example\n * ```ts\n * // Initialize operators\n * const ops = createEncryptionOperators(encryptionClient)\n *\n * // Equality search - automatically encrypts and uses PostgreSQL operators\n * const results = await db\n * .select()\n * .from(usersTable)\n * .where(await ops.eq(usersTable.email, 'user@example.com'))\n *\n * // Range query - automatically encrypts and uses eql_v2.gte()\n * const olderUsers = await db\n * .select()\n * .from(usersTable)\n * .where(await ops.gte(usersTable.age, 25))\n * ```\n */\nexport function createEncryptionOperators(encryptionClient: EncryptionClient): {\n // Comparison operators\n /**\n * Equality operator - encrypts value for encrypted columns.\n * Requires either `equality` or `orderAndRange` to be set on {@link EncryptedColumnConfig}.\n *\n * @example\n * Select users with a specific email address.\n * ```ts\n * const condition = await ops.eq(usersTable.email, 'user@example.com')\n * const results = await db.select().from(usersTable).where(condition)\n * ```\n */\n eq: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL\n\n /**\n * Not equal operator - encrypts value for encrypted columns.\n * Requires either `equality` or `orderAndRange` to be set on {@link EncryptedColumnConfig}.\n *\n * @example\n * Select users whose email address is not a specific value.\n * ```ts\n * const condition = await ops.ne(usersTable.email, 'user@example.com')\n * const results = await db.select().from(usersTable).where(condition)\n * ```\n */\n ne: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL\n\n /**\n * Greater than operator for encrypted columns with ORE index.\n * Requires `orderAndRange` to be set on {@link EncryptedColumnConfig}.\n *\n * @example\n * Select users older than a specific age.\n * ```ts\n * const condition = await ops.gt(usersTable.age, 30)\n * const results = await db.select().from(usersTable).where(condition)\n * ```\n */\n gt: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL\n\n /**\n * Greater than or equal operator for encrypted columns with ORE index.\n * Requires `orderAndRange` to be set on {@link EncryptedColumnConfig}.\n *\n * @example\n * Select users older than or equal to a specific age.\n * ```ts\n * const condition = await ops.gte(usersTable.age, 30)\n * const results = await db.select().from(usersTable).where(condition)\n * ```\n */\n gte: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL\n\n /**\n * Less than operator for encrypted columns with ORE index.\n * Requires `orderAndRange` to be set on {@link EncryptedColumnConfig}.\n *\n * @example\n * Select users younger than a specific age.\n * ```ts\n * const condition = await ops.lt(usersTable.age, 30)\n * const results = await db.select().from(usersTable).where(condition)\n * ```\n */\n lt: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL\n\n /**\n * Less than or equal operator for encrypted columns with ORE index.\n * Requires `orderAndRange` to be set on {@link EncryptedColumnConfig}.\n *\n * @example\n * Select users younger than or equal to a specific age.\n * ```ts\n * const condition = await ops.lte(usersTable.age, 30)\n * const results = await db.select().from(usersTable).where(condition)\n * ```\n */\n lte: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL\n\n /**\n * Between operator for encrypted columns with ORE index.\n * Requires `orderAndRange` to be set on {@link EncryptedColumnConfig}.\n *\n * @example\n * Select users within a specific age range.\n * ```ts\n * const condition = await ops.between(usersTable.age, 20, 30)\n * const results = await db.select().from(usersTable).where(condition)\n * ```\n */\n between: (left: SQLWrapper, min: unknown, max: unknown) => Promise<SQL> | SQL\n\n /**\n * Not between operator for encrypted columns with ORE index.\n * Requires `orderAndRange` to be set on {@link EncryptedColumnConfig}.\n *\n * @example\n * Select users outside a specific age range.\n * ```ts\n * const condition = await ops.notBetween(usersTable.age, 20, 30)\n * const results = await db.select().from(usersTable).where(condition)\n * ```\n */\n notBetween: (\n left: SQLWrapper,\n min: unknown,\n max: unknown,\n ) => Promise<SQL> | SQL\n\n /**\n * Like operator for encrypted columns with free text search.\n * Requires `freeTextSearch` to be set on {@link EncryptedColumnConfig}.\n *\n * > [!IMPORTANT]\n * > Case sensitivity on encrypted columns depends on the {@link EncryptedColumnConfig}.\n * > Ensure that the column is configured for case-insensitive search if needed.\n *\n * @example\n * Select users with email addresses matching a pattern.\n * ```ts\n * const condition = await ops.like(usersTable.email, '%@example.com')\n * const results = await db.select().from(usersTable).where(condition)\n * ```\n */\n like: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL\n\n /**\n * ILike operator for encrypted columns with free text search.\n * Requires `freeTextSearch` to be set on {@link EncryptedColumnConfig}.\n *\n * > [!IMPORTANT]\n * > Case sensitivity on encrypted columns depends on the {@link EncryptedColumnConfig}.\n * > Ensure that the column is configured for case-insensitive search if needed.\n *\n * @example\n * Select users with email addresses matching a pattern (case-insensitive).\n * ```ts\n * const condition = await ops.ilike(usersTable.email, '%@example.com')\n * const results = await db.select().from(usersTable).where(condition)\n * ```\n */\n ilike: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL\n notIlike: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL\n\n /**\n * JSONB path query first operator for encrypted columns with searchable JSON.\n * Requires `searchableJson` to be set on {@link EncryptedColumnConfig}.\n *\n * Encrypts the JSON path selector and calls `eql_v2.jsonb_path_query_first()`,\n * casting the parameter to `eql_v2_encrypted`.\n *\n * @throws {EncryptionOperatorError} If the column does not have `searchableJson` enabled.\n */\n jsonbPathQueryFirst: (left: SQLWrapper, right: unknown) => Promise<SQL>\n\n /**\n * JSONB get operator for encrypted columns with searchable JSON.\n * Requires `searchableJson` to be set on {@link EncryptedColumnConfig}.\n *\n * Encrypts the JSON path selector and uses the `->` operator,\n * casting the parameter to `eql_v2_encrypted`.\n *\n * @throws {EncryptionOperatorError} If the column does not have `searchableJson` enabled.\n */\n jsonbGet: (left: SQLWrapper, right: unknown) => Promise<SQL>\n\n /**\n * JSONB path exists operator for encrypted columns with searchable JSON.\n * Requires `searchableJson` to be set on {@link EncryptedColumnConfig}.\n *\n * Encrypts the JSON path selector and calls `eql_v2.jsonb_path_exists()`,\n * casting the parameter to `eql_v2_encrypted`.\n *\n * @throws {EncryptionOperatorError} If the column does not have `searchableJson` enabled.\n */\n jsonbPathExists: (left: SQLWrapper, right: unknown) => Promise<SQL>\n // Array operators\n inArray: (left: SQLWrapper, right: unknown[] | SQLWrapper) => Promise<SQL>\n notInArray: (left: SQLWrapper, right: unknown[] | SQLWrapper) => Promise<SQL>\n // Sorting operators\n asc: (column: SQLWrapper) => SQL\n desc: (column: SQLWrapper) => SQL\n and: (\n ...conditions: (SQL | SQLWrapper | Promise<SQL> | undefined)[]\n ) => Promise<SQL>\n or: (\n ...conditions: (SQL | SQLWrapper | Promise<SQL> | undefined)[]\n ) => Promise<SQL>\n // Operators that don't need encryption (pass through to Drizzle)\n exists: typeof exists\n notExists: typeof notExists\n isNull: typeof isNull\n isNotNull: typeof isNotNull\n not: typeof not\n // Array operators that work with arrays directly (not encrypted values)\n arrayContains: typeof arrayContains\n arrayContained: typeof arrayContained\n arrayOverlaps: typeof arrayOverlaps\n} {\n // Create a cache for encrypted tables keyed by table name\n const tableCache = new Map<string, ProtectTable<ProtectTableColumn>>()\n const defaultTable: ProtectTable<ProtectTableColumn> | undefined = undefined\n\n /**\n * Equality operator - encrypts value and uses regular Drizzle operator\n */\n const encryptedEq = (\n left: SQLWrapper,\n right: unknown,\n ): Promise<SQL> | SQL => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createComparisonOperator(\n 'eq',\n left,\n right,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * Not equal operator - encrypts value and uses regular Drizzle operator\n */\n const encryptedNe = (\n left: SQLWrapper,\n right: unknown,\n ): Promise<SQL> | SQL => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createComparisonOperator(\n 'ne',\n left,\n right,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * Greater than operator - uses eql_v2.gt() for encrypted columns with ORE index\n */\n const encryptedGt = (\n left: SQLWrapper,\n right: unknown,\n ): Promise<SQL> | SQL => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createComparisonOperator(\n 'gt',\n left,\n right,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * Greater than or equal operator - uses eql_v2.gte() for encrypted columns with ORE index\n */\n const encryptedGte = (\n left: SQLWrapper,\n right: unknown,\n ): Promise<SQL> | SQL => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createComparisonOperator(\n 'gte',\n left,\n right,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * Less than operator - uses eql_v2.lt() for encrypted columns with ORE index\n */\n const encryptedLt = (\n left: SQLWrapper,\n right: unknown,\n ): Promise<SQL> | SQL => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createComparisonOperator(\n 'lt',\n left,\n right,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * Less than or equal operator - uses eql_v2.lte() for encrypted columns with ORE index\n */\n const encryptedLte = (\n left: SQLWrapper,\n right: unknown,\n ): Promise<SQL> | SQL => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createComparisonOperator(\n 'lte',\n left,\n right,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * Between operator - uses eql_v2.gte() and eql_v2.lte() for encrypted columns with ORE index\n */\n const encryptedBetween = (\n left: SQLWrapper,\n min: unknown,\n max: unknown,\n ): Promise<SQL> | SQL => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createRangeOperator(\n 'between',\n left,\n min,\n max,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * Not between operator - uses eql_v2.gte() and eql_v2.lte() for encrypted columns with ORE index\n */\n const encryptedNotBetween = (\n left: SQLWrapper,\n min: unknown,\n max: unknown,\n ): Promise<SQL> | SQL => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createRangeOperator(\n 'notBetween',\n left,\n min,\n max,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * Like operator - encrypts value and uses eql_v2.like() for encrypted columns with match index\n */\n const encryptedLike = (\n left: SQLWrapper,\n right: unknown,\n ): Promise<SQL> | SQL => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createTextSearchOperator(\n 'like',\n left,\n right,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * Case-insensitive like operator - encrypts value and uses eql_v2.ilike() for encrypted columns with match index\n */\n const encryptedIlike = (\n left: SQLWrapper,\n right: unknown,\n ): Promise<SQL> | SQL => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createTextSearchOperator(\n 'ilike',\n left,\n right,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * Not like operator (case insensitive) - encrypts value and uses eql_v2.ilike() for encrypted columns with match index\n */\n const encryptedNotIlike = (\n left: SQLWrapper,\n right: unknown,\n ): Promise<SQL> | SQL => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createTextSearchOperator(\n 'notIlike',\n left,\n right,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * JSONB path query first operator - encrypts the selector and calls\n * `eql_v2.jsonb_path_query_first()` for encrypted columns with searchable JSON.\n */\n const encryptedJsonbPathQueryFirst = (\n left: SQLWrapper,\n right: unknown,\n ): Promise<SQL> => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createJsonbOperator(\n 'jsonbPathQueryFirst',\n left,\n right,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * JSONB get operator - encrypts the selector and uses the `->` operator\n * for encrypted columns with searchable JSON.\n */\n const encryptedJsonbGet = (\n left: SQLWrapper,\n right: unknown,\n ): Promise<SQL> => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createJsonbOperator(\n 'jsonbGet',\n left,\n right,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * JSONB path exists operator - encrypts the selector and calls\n * `eql_v2.jsonb_path_exists()` for encrypted columns with searchable JSON.\n */\n const encryptedJsonbPathExists = (\n left: SQLWrapper,\n right: unknown,\n ): Promise<SQL> => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createJsonbOperator(\n 'jsonbPathExists',\n left,\n right,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * In array operator - encrypts all values in the array\n */\n const encryptedInArray = async (\n left: SQLWrapper,\n right: unknown[] | SQLWrapper,\n ): Promise<SQL> => {\n // If right is a SQLWrapper (subquery), pass through to Drizzle\n if (isSQLWrapper(right)) {\n return inArray(left, right as unknown as Parameters<typeof inArray>[1])\n }\n\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n\n if (!columnInfo.config?.equality || !Array.isArray(right)) {\n return inArray(left, right as unknown[])\n }\n\n // Encrypt all values in the array in a single batch\n const encryptedValues = await encryptValues(\n encryptionClient,\n right.map((value) => ({\n value,\n column: left,\n queryType: queryTypes.equality,\n })),\n defaultTable,\n tableCache,\n )\n\n // Use regular eq for each encrypted value - PostgreSQL operators handle it\n const conditions = encryptedValues\n .filter((encrypted) => encrypted !== undefined)\n .map((encrypted) => eq(left, encrypted))\n\n if (conditions.length === 0) {\n return sql`false`\n }\n\n const combined = or(...conditions)\n return combined ?? sql`false`\n }\n\n /**\n * Not in array operator\n */\n const encryptedNotInArray = async (\n left: SQLWrapper,\n right: unknown[] | SQLWrapper,\n ): Promise<SQL> => {\n // If right is a SQLWrapper (subquery), pass through to Drizzle\n if (isSQLWrapper(right)) {\n return notInArray(\n left,\n right as unknown as Parameters<typeof notInArray>[1],\n )\n }\n\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n\n if (!columnInfo.config?.equality || !Array.isArray(right)) {\n return notInArray(left, right as unknown[])\n }\n\n // Encrypt all values in the array in a single batch\n const encryptedValues = await encryptValues(\n encryptionClient,\n right.map((value) => ({\n value,\n column: left,\n queryType: queryTypes.equality,\n })),\n defaultTable,\n tableCache,\n )\n\n // Use regular ne for each encrypted value - PostgreSQL operators handle it\n const conditions = encryptedValues\n .filter((encrypted) => encrypted !== undefined)\n .map((encrypted) => ne(left, encrypted))\n\n if (conditions.length === 0) {\n return sql`true`\n }\n\n const combined = and(...conditions)\n return combined ?? sql`true`\n }\n\n /**\n * Ascending order helper - uses eql_v2.order_by() for encrypted columns with ORE index\n */\n const encryptedAsc = (column: SQLWrapper): SQL => {\n const columnInfo = getColumnInfo(column, defaultTable, tableCache)\n\n if (columnInfo.config?.orderAndRange) {\n return asc(sql`eql_v2.order_by(${column})`)\n }\n\n return asc(column)\n }\n\n /**\n * Descending order helper - uses eql_v2.order_by() for encrypted columns with ORE index\n */\n const encryptedDesc = (column: SQLWrapper): SQL => {\n const columnInfo = getColumnInfo(column, defaultTable, tableCache)\n\n if (columnInfo.config?.orderAndRange) {\n return desc(sql`eql_v2.order_by(${column})`)\n }\n\n return desc(column)\n }\n\n /**\n * Batched AND operator - collects lazy operators, batches encryption, and combines conditions\n */\n const encryptedAnd = async (\n ...conditions: (SQL | SQLWrapper | Promise<SQL> | undefined)[]\n ): Promise<SQL> => {\n // Single pass: separate lazy operators from regular conditions\n const lazyOperators: LazyOperator[] = []\n const regularConditions: (SQL | SQLWrapper | undefined)[] = []\n const regularPromises: Promise<SQL>[] = []\n\n for (const condition of conditions) {\n if (condition === undefined) {\n continue\n }\n\n if (isLazyOperator(condition)) {\n lazyOperators.push(condition)\n } else if (condition instanceof Promise) {\n // Check if promise is also a lazy operator\n if (isLazyOperator(condition)) {\n lazyOperators.push(condition)\n } else {\n regularPromises.push(condition)\n }\n } else {\n regularConditions.push(condition)\n }\n }\n\n // If there are no lazy operators, just use Drizzle's and()\n if (lazyOperators.length === 0) {\n const allConditions: (SQL | SQLWrapper | undefined)[] = [\n ...regularConditions,\n ...(await Promise.all(regularPromises)),\n ]\n return and(...allConditions) ?? sql`true`\n }\n\n // Single pass: collect all values to encrypt with metadata\n const valuesToEncrypt: Array<{\n value: unknown\n column: SQLWrapper\n columnInfo: ColumnInfo\n queryType?: QueryTypeName\n lazyOpIndex: number\n isMin?: boolean\n isMax?: boolean\n }> = []\n\n for (let i = 0; i < lazyOperators.length; i++) {\n const lazyOp = lazyOperators[i]\n if (!lazyOp.needsEncryption) {\n continue\n }\n\n if (lazyOp.min !== undefined && lazyOp.max !== undefined) {\n valuesToEncrypt.push({\n value: lazyOp.min,\n column: lazyOp.left,\n columnInfo: lazyOp.columnInfo,\n queryType: lazyOp.queryType,\n lazyOpIndex: i,\n isMin: true,\n })\n valuesToEncrypt.push({\n value: lazyOp.max,\n column: lazyOp.left,\n columnInfo: lazyOp.columnInfo,\n queryType: lazyOp.queryType,\n lazyOpIndex: i,\n isMax: true,\n })\n } else if (lazyOp.right !== undefined) {\n valuesToEncrypt.push({\n value: lazyOp.right,\n column: lazyOp.left,\n columnInfo: lazyOp.columnInfo,\n queryType: lazyOp.queryType,\n lazyOpIndex: i,\n })\n }\n }\n\n // Batch encrypt all values\n const encryptedResults = await encryptValues(\n encryptionClient,\n valuesToEncrypt.map((v) => ({\n value: v.value,\n column: v.column,\n queryType: v.queryType,\n })),\n defaultTable,\n tableCache,\n )\n\n // Group encrypted values by lazy operator index\n const encryptedByLazyOp = new Map<\n number,\n { value?: unknown; min?: unknown; max?: unknown }\n >()\n\n for (let i = 0; i < valuesToEncrypt.length; i++) {\n const { lazyOpIndex, isMin, isMax } = valuesToEncrypt[i]\n const encrypted = encryptedResults[i]\n\n let group = encryptedByLazyOp.get(lazyOpIndex)\n if (!group) {\n group = {}\n encryptedByLazyOp.set(lazyOpIndex, group)\n }\n\n if (isMin) {\n group.min = encrypted\n } else if (isMax) {\n group.max = encrypted\n } else {\n group.value = encrypted\n }\n }\n\n // Execute all lazy operators with their encrypted values\n const sqlConditions: SQL[] = []\n for (let i = 0; i < lazyOperators.length; i++) {\n const lazyOp = lazyOperators[i]\n const encrypted = encryptedByLazyOp.get(i)\n\n let sqlCondition: SQL\n if (lazyOp.needsEncryption && encrypted) {\n const encryptedValues: Array<{ value: unknown; encrypted: unknown }> =\n []\n if (encrypted.value !== undefined) {\n encryptedValues.push({\n value: lazyOp.right,\n encrypted: encrypted.value,\n })\n }\n if (encrypted.min !== undefined) {\n encryptedValues.push({ value: lazyOp.min, encrypted: encrypted.min })\n }\n if (encrypted.max !== undefined) {\n encryptedValues.push({ value: lazyOp.max, encrypted: encrypted.max })\n }\n sqlCondition = await executeLazyOperator(lazyOp, encryptedValues)\n } else {\n sqlCondition = lazyOp.execute(lazyOp.right)\n }\n\n sqlConditions.push(sqlCondition)\n }\n\n // Await any regular promises\n const regularPromisesResults = await Promise.all(regularPromises)\n\n // Combine all conditions\n const allConditions: (SQL | SQLWrapper | undefined)[] = [\n ...regularConditions,\n ...sqlConditions,\n ...regularPromisesResults,\n ]\n\n return and(...allConditions) ?? sql`true`\n }\n\n /**\n * Batched OR operator - collects lazy operators, batches encryption, and combines conditions\n */\n const encryptedOr = async (\n ...conditions: (SQL | SQLWrapper | Promise<SQL> | undefined)[]\n ): Promise<SQL> => {\n const lazyOperators: LazyOperator[] = []\n const regularConditions: (SQL | SQLWrapper | undefined)[] = []\n const regularPromises: Promise<SQL>[] = []\n\n for (const condition of conditions) {\n if (condition === undefined) {\n continue\n }\n\n if (isLazyOperator(condition)) {\n lazyOperators.push(condition)\n } else if (condition instanceof Promise) {\n if (isLazyOperator(condition)) {\n lazyOperators.push(condition)\n } else {\n regularPromises.push(condition)\n }\n } else {\n regularConditions.push(condition)\n }\n }\n\n if (lazyOperators.length === 0) {\n const allConditions: (SQL | SQLWrapper | undefined)[] = [\n ...regularConditions,\n ...(await Promise.all(regularPromises)),\n ]\n return or(...allConditions) ?? sql`false`\n }\n\n const valuesToEncrypt: Array<{\n value: unknown\n column: SQLWrapper\n columnInfo: ColumnInfo\n queryType?: QueryTypeName\n lazyOpIndex: number\n isMin?: boolean\n isMax?: boolean\n }> = []\n\n for (let i = 0; i < lazyOperators.length; i++) {\n const lazyOp = lazyOperators[i]\n if (!lazyOp.needsEncryption) {\n continue\n }\n\n if (lazyOp.min !== undefined && lazyOp.max !== undefined) {\n valuesToEncrypt.push({\n value: lazyOp.min,\n column: lazyOp.left,\n columnInfo: lazyOp.columnInfo,\n queryType: lazyOp.queryType,\n lazyOpIndex: i,\n isMin: true,\n })\n valuesToEncrypt.push({\n value: lazyOp.max,\n column: lazyOp.left,\n columnInfo: lazyOp.columnInfo,\n queryType: lazyOp.queryType,\n lazyOpIndex: i,\n isMax: true,\n })\n } else if (lazyOp.right !== undefined) {\n valuesToEncrypt.push({\n value: lazyOp.right,\n column: lazyOp.left,\n columnInfo: lazyOp.columnInfo,\n queryType: lazyOp.queryType,\n lazyOpIndex: i,\n })\n }\n }\n\n const encryptedResults = await encryptValues(\n encryptionClient,\n valuesToEncrypt.map((v) => ({\n value: v.value,\n column: v.column,\n queryType: v.queryType,\n })),\n defaultTable,\n tableCache,\n )\n\n const encryptedByLazyOp = new Map<\n number,\n { value?: unknown; min?: unknown; max?: unknown }\n >()\n\n for (let i = 0; i < valuesToEncrypt.length; i++) {\n const { lazyOpIndex, isMin, isMax } = valuesToEncrypt[i]\n const encrypted = encryptedResults[i]\n\n let group = encryptedByLazyOp.get(lazyOpIndex)\n if (!group) {\n group = {}\n encryptedByLazyOp.set(lazyOpIndex, group)\n }\n\n if (isMin) {\n group.min = encrypted\n } else if (isMax) {\n group.max = encrypted\n } else {\n group.value = encrypted\n }\n }\n\n const sqlConditions: SQL[] = []\n for (let i = 0; i < lazyOperators.length; i++) {\n const lazyOp = lazyOperators[i]\n const encrypted = encryptedByLazyOp.get(i)\n\n let sqlCondition: SQL\n if (lazyOp.needsEncryption && encrypted) {\n const encryptedValues: Array<{ value: unknown; encrypted: unknown }> =\n []\n if (encrypted.value !== undefined) {\n encryptedValues.push({\n value: lazyOp.right,\n encrypted: encrypted.value,\n })\n }\n if (encrypted.min !== undefined) {\n encryptedValues.push({ value: lazyOp.min, encrypted: encrypted.min })\n }\n if (encrypted.max !== undefined) {\n encryptedValues.push({ value: lazyOp.max, encrypted: encrypted.max })\n }\n sqlCondition = await executeLazyOperator(lazyOp, encryptedValues)\n } else {\n sqlCondition = lazyOp.execute(lazyOp.right)\n }\n\n sqlConditions.push(sqlCondition)\n }\n\n const regularPromisesResults = await Promise.all(regularPromises)\n\n const allConditions: (SQL | SQLWrapper | undefined)[] = [\n ...regularConditions,\n ...sqlConditions,\n ...regularPromisesResults,\n ]\n\n return or(...allConditions) ?? sql`false`\n }\n\n return {\n // Comparison operators\n eq: encryptedEq,\n ne: encryptedNe,\n gt: encryptedGt,\n gte: encryptedGte,\n lt: encryptedLt,\n lte: encryptedLte,\n\n // Range operators\n between: encryptedBetween,\n notBetween: encryptedNotBetween,\n\n // Text search operators\n like: encryptedLike,\n ilike: encryptedIlike,\n notIlike: encryptedNotIlike,\n\n // Searchable JSON operators\n jsonbPathQueryFirst: encryptedJsonbPathQueryFirst,\n jsonbGet: encryptedJsonbGet,\n jsonbPathExists: encryptedJsonbPathExists,\n\n // Array operators\n inArray: encryptedInArray,\n notInArray: encryptedNotInArray,\n\n // Sorting operators\n asc: encryptedAsc,\n desc: encryptedDesc,\n\n // AND operator - batches encryption operations\n and: encryptedAnd,\n\n // OR operator - batches encryption operations\n or: encryptedOr,\n\n // Operators that don't need encryption (pass through to Drizzle)\n exists,\n notExists,\n isNull,\n isNotNull,\n not,\n // Array operators that work with arrays directly (not encrypted values)\n arrayContains,\n arrayContained,\n arrayOverlaps,\n }\n}\n"],"mappings":"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","names":["import_drizzle_orm","encryptedTable","config","encryptedColumn","sql","allConditions"]}
1
+ {"version":3,"sources":["../../src/drizzle/index.ts","../../src/schema/index.ts","../../src/drizzle/schema-extraction.ts","../../src/types.ts","../../src/drizzle/operators.ts"],"sourcesContent":["import type { CastAs, MatchIndexOpts, TokenFilter } from '@/schema'\nimport { customType } from 'drizzle-orm/pg-core'\n\nexport type { CastAs, MatchIndexOpts, TokenFilter }\n\n/**\n * Configuration for encrypted column indexes and data types\n */\nexport type EncryptedColumnConfig = {\n /**\n * Data type for the column (default: 'string')\n */\n dataType?: CastAs\n /**\n * Enable free text search. Can be a boolean for default options, or an object for custom configuration.\n */\n freeTextSearch?: boolean | MatchIndexOpts\n /**\n * Enable equality index. Can be a boolean for default options, or an array of token filters.\n */\n equality?: boolean | TokenFilter[]\n /**\n * Enable order and range index for sorting and range queries.\n */\n orderAndRange?: boolean\n /**\n * Enable searchable JSON index for JSONB path queries.\n * Requires dataType: 'json'.\n */\n searchableJson?: boolean\n}\n\n/**\n * Map to store configuration for encrypted columns\n * Keyed by column name (the name passed to encryptedType)\n */\nconst columnConfigMap = new Map<\n string,\n EncryptedColumnConfig & { name: string }\n>()\n\n/**\n * Creates an encrypted column type for Drizzle ORM with configurable searchable encryption options.\n *\n * When data is encrypted, the actual stored value is an [EQL v2](/docs/reference/eql) encrypted composite type which includes any searchable encryption indexes defined for the column.\n * Importantly, the original data type is not known until it is decrypted. Therefore, this function allows specifying\n * the original data type via the `dataType` option in the configuration.\n * This ensures that when data is decrypted, it can be correctly interpreted as the intended TypeScript type.\n *\n * @typeParam TData - The TypeScript type of the data stored in the column\n * @param name - The column name in the database\n * @param config - Optional configuration for data type and searchable encryption indexes\n * @returns A Drizzle column type that can be used in pgTable definitions\n *\n * ## Searchable Encryption Options\n *\n * - `dataType`: Specifies the original data type of the column (e.g., 'string', 'number', 'json'). Default is 'string'.\n * - `freeTextSearch`: Enables free text search index. Can be a boolean for default options, or an object for custom configuration.\n * - `equality`: Enables equality index. Can be a boolean for default options, or an array of token filters.\n * - `orderAndRange`: Enables order and range index for sorting and range queries.\n * - `searchableJson`: Enables searchable JSON index for JSONB path queries on encrypted JSON columns.\n *\n * See {@link EncryptedColumnConfig}.\n *\n * @example\n * Defining a drizzle table schema for postgres table with encrypted columns.\n *\n * ```typescript\n * import { pgTable, integer, timestamp } from 'drizzle-orm/pg-core'\n * import { encryptedType } from '@cipherstash/stack/drizzle'\n *\n * const users = pgTable('users', {\n * email: encryptedType('email', {\n * freeTextSearch: true,\n * equality: true,\n * orderAndRange: true,\n * }),\n * age: encryptedType('age', {\n * dataType: 'number',\n * equality: true,\n * orderAndRange: true,\n * }),\n * profile: encryptedType('profile', {\n * dataType: 'json',\n * }),\n * })\n * ```\n */\nexport const encryptedType = <TData>(\n name: string,\n config?: EncryptedColumnConfig,\n) => {\n // Create the Drizzle custom type\n const customColumnType = customType<{ data: TData; driverData: string }>({\n dataType() {\n return 'eql_v2_encrypted'\n },\n toDriver(value: TData): string {\n const jsonStr = JSON.stringify(value)\n const escaped = jsonStr.replace(/\"/g, '\"\"')\n return `(\"${escaped}\")`\n },\n fromDriver(value: string): TData {\n const parseComposite = (str: string) => {\n if (!str || str === '') return null\n\n const trimmed = str.trim()\n\n if (trimmed.startsWith('(') && trimmed.endsWith(')')) {\n let inner = trimmed.slice(1, -1)\n inner = inner.replace(/\"\"/g, '\"')\n\n if (inner.startsWith('\"') && inner.endsWith('\"')) {\n const stripped = inner.slice(1, -1)\n return JSON.parse(stripped)\n }\n\n if (inner.startsWith('{') || inner.startsWith('[')) {\n return JSON.parse(inner)\n }\n\n return inner\n }\n\n return JSON.parse(str)\n }\n\n return parseComposite(value) as TData\n },\n })\n\n // Create the column instance\n const column = customColumnType(name)\n\n // Store configuration keyed by column name\n // This allows us to look it up during schema extraction\n const fullConfig: EncryptedColumnConfig & { name: string } = {\n name,\n ...config,\n }\n\n // Store in Map keyed by column name (will be looked up during extraction)\n columnConfigMap.set(name, fullConfig)\n\n // Also store on property for immediate access (before pgTable processes it)\n // We need to use any here because Drizzle columns don't have a type for custom properties\n // biome-ignore lint/suspicious/noExplicitAny: Drizzle columns don't expose custom property types\n ;(column as any)._encryptionConfig = fullConfig\n\n return column\n}\n\n/**\n * Get configuration for an encrypted column by checking if it's an encrypted type\n * and looking up the config by column name\n * @internal\n */\nexport function getEncryptedColumnConfig(\n columnName: string,\n column: unknown,\n): (EncryptedColumnConfig & { name: string }) | undefined {\n // Check if this is an encrypted column\n if (column && typeof column === 'object') {\n // We need to use any here to access Drizzle column properties\n // biome-ignore lint/suspicious/noExplicitAny: Drizzle column types don't expose all properties\n const columnAny = column as any\n\n // Check if it's an encrypted column by checking sqlName or dataType\n // After pgTable processes it, sqlName will be 'eql_v2_encrypted'\n const isEncrypted =\n columnAny.sqlName === 'eql_v2_encrypted' ||\n columnAny.dataType === 'eql_v2_encrypted' ||\n (columnAny.dataType &&\n typeof columnAny.dataType === 'function' &&\n columnAny.dataType() === 'eql_v2_encrypted')\n\n if (isEncrypted) {\n // Try to get config from property (if still there)\n if (columnAny._encryptionConfig) {\n return columnAny._encryptionConfig\n }\n\n // Look up config by column name (the name passed to encryptedType)\n // The column.name should match what was passed to encryptedType\n const lookupName = columnAny.name || columnName\n return columnConfigMap.get(lookupName)\n }\n }\n return undefined\n}\n\n/**\n * Extract a CipherStash encryption schema from a Drizzle table definition.\n *\n * Inspects columns created with {@link encryptedType} and builds the equivalent\n * `encryptedTable` / `encryptedColumn` schema automatically.\n */\nexport { extractEncryptionSchema } from './schema-extraction.js'\n\n/**\n * Create Drizzle query operators (`eq`, `lt`, `gt`, etc.) that work with\n * encrypted columns. The returned operators encrypt query values before\n * passing them to Drizzle, enabling searchable encryption in standard\n * Drizzle queries.\n */\nexport {\n createEncryptionOperators,\n EncryptionOperatorError,\n EncryptionConfigError,\n} from './operators.js'\n","import type { Encrypted } from '@/types'\nimport { z } from 'zod'\n\n// ------------------------\n// Zod schemas\n// ------------------------\n\n/**\n * Allowed cast types for CipherStash schema fields.\n *\n * **Possible values:**\n * - `\"bigint\"`\n * - `\"boolean\"`\n * - `\"date\"`\n * - `\"number\"`\n * - `\"string\"`\n * - `\"json\"`\n *\n * @remarks\n * This is a Zod enum used at runtime to validate schema definitions.\n * Use {@link CastAs} when typing your own code.\n *\n * @internal\n */\nexport const castAsEnum = z\n .enum(['bigint', 'boolean', 'date', 'number', 'string', 'json'])\n .default('string')\n\nconst tokenFilterSchema = z.object({\n kind: z.literal('downcase'),\n})\n\nconst tokenizerSchema = z\n .union([\n z.object({\n kind: z.literal('standard'),\n }),\n z.object({\n kind: z.literal('ngram'),\n token_length: z.number(),\n }),\n ])\n .default({ kind: 'ngram', token_length: 3 })\n .optional()\n\nconst oreIndexOptsSchema = z.object({})\n\nconst uniqueIndexOptsSchema = z.object({\n token_filters: z.array(tokenFilterSchema).default([]).optional(),\n})\n\nconst matchIndexOptsSchema = z.object({\n tokenizer: tokenizerSchema,\n token_filters: z.array(tokenFilterSchema).default([]).optional(),\n k: z.number().default(6).optional(),\n m: z.number().default(2048).optional(),\n include_original: z.boolean().default(false).optional(),\n})\n\nconst steVecIndexOptsSchema = z.object({\n prefix: z.string(),\n})\n\nconst indexesSchema = z\n .object({\n ore: oreIndexOptsSchema.optional(),\n unique: uniqueIndexOptsSchema.optional(),\n match: matchIndexOptsSchema.optional(),\n ste_vec: steVecIndexOptsSchema.optional(),\n })\n .default({})\n\nconst columnSchema = z\n .object({\n cast_as: castAsEnum,\n indexes: indexesSchema,\n })\n .default({})\n\nconst tableSchema = z.record(columnSchema).default({})\n\nconst tablesSchema = z.record(tableSchema).default({})\n\n/** @internal */\nexport const encryptConfigSchema = z.object({\n v: z.number(),\n tables: tablesSchema,\n})\n\n// ------------------------\n// Type definitions\n// ------------------------\n\n/**\n * Type-safe alias for {@link castAsEnum} used to specify the *unencrypted* data type of a column or value.\n * This is important because once encrypted, all data is stored as binary blobs.\n *\n * @see {@link castAsEnum} for possible values.\n */\nexport type CastAs = z.infer<typeof castAsEnum>\nexport type TokenFilter = z.infer<typeof tokenFilterSchema>\nexport type MatchIndexOpts = z.infer<typeof matchIndexOptsSchema>\nexport type SteVecIndexOpts = z.infer<typeof steVecIndexOptsSchema>\nexport type UniqueIndexOpts = z.infer<typeof uniqueIndexOptsSchema>\nexport type OreIndexOpts = z.infer<typeof oreIndexOptsSchema>\nexport type ColumnSchema = z.infer<typeof columnSchema>\n\n/**\n * Shape of table columns: either top-level {@link EncryptedColumn} or nested\n * objects whose leaves are {@link EncryptedField}. Used with {@link encryptedTable}.\n */\nexport type EncryptedTableColumn = {\n [key: string]:\n | EncryptedColumn\n | {\n [key: string]:\n | EncryptedField\n | {\n [key: string]:\n | EncryptedField\n | {\n [key: string]: EncryptedField\n }\n }\n }\n}\nexport type EncryptConfig = z.infer<typeof encryptConfigSchema>\n\n// ------------------------\n// Interface definitions\n// ------------------------\n\n/**\n * Builder for a nested encrypted field (encrypted but not searchable).\n * Create with {@link encryptedField}. Use inside nested objects in {@link encryptedTable};\n * supports `.dataType()` for plaintext type. No index methods (equality, orderAndRange, etc.).\n */\nexport class EncryptedField {\n private valueName: string\n private castAsValue: CastAs\n\n constructor(valueName: string) {\n this.valueName = valueName\n this.castAsValue = 'string'\n }\n\n /**\n * Set or override the plaintext data type for this field.\n *\n * By default all values are treated as `'string'`. Use this method to specify\n * a different type so the encryption layer knows how to encode the plaintext\n * before encrypting.\n *\n * @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'bigint'`, or `'json'`.\n * @returns This `EncryptedField` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedField } from \"@cipherstash/stack/schema\"\n *\n * const age = encryptedField(\"age\").dataType(\"number\")\n * ```\n */\n dataType(castAs: CastAs) {\n this.castAsValue = castAs\n return this\n }\n\n build() {\n return {\n cast_as: this.castAsValue,\n indexes: {},\n }\n }\n\n getName() {\n return this.valueName\n }\n}\n\nexport class EncryptedColumn {\n private columnName: string\n private castAsValue: CastAs\n private indexesValue: {\n ore?: OreIndexOpts\n unique?: UniqueIndexOpts\n match?: Required<MatchIndexOpts>\n ste_vec?: SteVecIndexOpts\n } = {}\n\n constructor(columnName: string) {\n this.columnName = columnName\n this.castAsValue = 'string'\n }\n\n /**\n * Set or override the plaintext data type for this column.\n *\n * By default all columns are treated as `'string'`. Use this method to specify\n * a different type so the encryption layer knows how to encode the plaintext\n * before encrypting.\n *\n * @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'bigint'`, or `'json'`.\n * @returns This `EncryptedColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const dateOfBirth = encryptedColumn(\"date_of_birth\").dataType(\"date\")\n * ```\n */\n dataType(castAs: CastAs) {\n this.castAsValue = castAs\n return this\n }\n\n /**\n * Enable Order-Revealing Encryption (ORE) indexing on this column.\n *\n * ORE allows sorting, comparison, and range queries on encrypted data.\n * Use with `encryptQuery` and `queryType: 'orderAndRange'`.\n *\n * @returns This `EncryptedColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").orderAndRange(),\n * })\n * ```\n */\n orderAndRange() {\n this.indexesValue.ore = {}\n return this\n }\n\n /**\n * Enable an exact-match (unique) index on this column.\n *\n * Allows equality queries on encrypted data. Use with `encryptQuery`\n * and `queryType: 'equality'`.\n *\n * @param tokenFilters - Optional array of token filters (e.g. `[{ kind: 'downcase' }]`).\n * When omitted, no token filters are applied.\n * @returns This `EncryptedColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * })\n * ```\n */\n equality(tokenFilters?: TokenFilter[]) {\n this.indexesValue.unique = {\n token_filters: tokenFilters ?? [],\n }\n return this\n }\n\n /**\n * Enable a full-text / fuzzy search (match) index on this column.\n *\n * Uses n-gram tokenization by default for substring and fuzzy matching.\n * Use with `encryptQuery` and `queryType: 'freeTextSearch'`.\n *\n * @param opts - Optional match index configuration. Defaults to 3-character ngram\n * tokenization with a downcase filter, `k=6`, `m=2048`, and `include_original=true`.\n * @returns This `EncryptedColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").freeTextSearch(),\n * })\n *\n * // With custom options\n * const posts = encryptedTable(\"posts\", {\n * body: encryptedColumn(\"body\").freeTextSearch({\n * tokenizer: { kind: \"ngram\", token_length: 4 },\n * k: 8,\n * m: 4096,\n * }),\n * })\n * ```\n */\n freeTextSearch(opts?: MatchIndexOpts) {\n // Provide defaults\n this.indexesValue.match = {\n tokenizer: opts?.tokenizer ?? { kind: 'ngram', token_length: 3 },\n token_filters: opts?.token_filters ?? [\n {\n kind: 'downcase',\n },\n ],\n k: opts?.k ?? 6,\n m: opts?.m ?? 2048,\n include_original: opts?.include_original ?? true,\n }\n return this\n }\n\n /**\n * Configure this column for searchable encrypted JSON (STE-Vec).\n *\n * Enables encrypted JSONPath selector queries (e.g. `'$.user.email'`) and\n * containment queries (e.g. `{ role: 'admin' }`). Automatically sets the\n * data type to `'json'`.\n *\n * When used with `encryptQuery`, the query operation is auto-inferred from\n * the plaintext type: strings become selector queries, objects/arrays become\n * containment queries.\n *\n * @returns This `EncryptedColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const documents = encryptedTable(\"documents\", {\n * metadata: encryptedColumn(\"metadata\").searchableJson(),\n * })\n * ```\n */\n searchableJson() {\n this.castAsValue = 'json'\n this.indexesValue.ste_vec = { prefix: 'enabled' }\n return this\n }\n\n build() {\n return {\n cast_as: this.castAsValue,\n indexes: this.indexesValue,\n }\n }\n\n getName() {\n return this.columnName\n }\n}\n\ninterface TableDefinition {\n tableName: string\n columns: Record<string, ColumnSchema>\n}\n\nexport class EncryptedTable<T extends EncryptedTableColumn> {\n /** @internal Type-level brand so TypeScript can infer `T` from `EncryptedTable<T>`. */\n declare readonly _columnType: T\n\n constructor(\n public readonly tableName: string,\n private readonly columnBuilders: T,\n ) {}\n\n /**\n * Compile this table schema into a `TableDefinition` used internally by the encryption client.\n *\n * Iterates over all column builders, calls `.build()` on each, and assembles\n * the final `{ tableName, columns }` structure. For `searchableJson()` columns,\n * the STE-Vec prefix is automatically set to `\"<tableName>/<columnName>\"`.\n *\n * @returns A `TableDefinition` containing the table name and built column configs.\n *\n * @example\n * ```typescript\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * })\n *\n * const definition = users.build()\n * // { tableName: \"users\", columns: { email: { cast_as: \"string\", indexes: { unique: ... } } } }\n * ```\n */\n build(): TableDefinition {\n const builtColumns: Record<string, ColumnSchema> = {}\n\n const processColumn = (\n builder:\n | EncryptedColumn\n | Record<\n string,\n | EncryptedField\n | Record<\n string,\n | EncryptedField\n | Record<\n string,\n EncryptedField | Record<string, EncryptedField>\n >\n >\n >,\n colName: string,\n ) => {\n if (builder instanceof EncryptedColumn) {\n const builtColumn = builder.build()\n\n // Hanlde building the ste_vec index for JSON columns so users don't have to pass the prefix.\n if (\n builtColumn.cast_as === 'json' &&\n builtColumn.indexes.ste_vec?.prefix === 'enabled'\n ) {\n builtColumns[colName] = {\n ...builtColumn,\n indexes: {\n ...builtColumn.indexes,\n ste_vec: {\n prefix: `${this.tableName}/${colName}`,\n },\n },\n }\n } else {\n builtColumns[colName] = builtColumn\n }\n } else {\n for (const [key, value] of Object.entries(builder)) {\n if (value instanceof EncryptedField) {\n builtColumns[value.getName()] = value.build()\n } else {\n processColumn(value, key)\n }\n }\n }\n }\n\n for (const [colName, builder] of Object.entries(this.columnBuilders)) {\n processColumn(builder, colName)\n }\n\n return {\n tableName: this.tableName,\n columns: builtColumns,\n }\n }\n}\n\n// ------------------------\n// Schema type inference helpers\n// ------------------------\n\n/**\n * Infer the plaintext (decrypted) type from a EncryptedTable schema.\n *\n * @example\n * ```typescript\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * name: encryptedColumn(\"name\"),\n * })\n *\n * type UserPlaintext = InferPlaintext<typeof users>\n * // => { email: string; name: string }\n * ```\n */\nexport type InferPlaintext<T extends EncryptedTable<any>> =\n T extends EncryptedTable<infer C>\n ? {\n [K in keyof C as C[K] extends EncryptedColumn | EncryptedField\n ? K\n : never]: string\n }\n : never\n\n/**\n * Infer the encrypted type from a EncryptedTable schema.\n *\n * @example\n * ```typescript\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * })\n *\n * type UserEncrypted = InferEncrypted<typeof users>\n * // => { email: Encrypted }\n * ```\n */\nexport type InferEncrypted<T extends EncryptedTable<any>> =\n T extends EncryptedTable<infer C>\n ? {\n [K in keyof C as C[K] extends EncryptedColumn | EncryptedField\n ? K\n : never]: Encrypted\n }\n : never\n\n// ------------------------\n// User facing functions\n// ------------------------\n\n/**\n * Define an encrypted table schema.\n *\n * Creates a `EncryptedTable` that maps a database table name to a set of encrypted\n * column definitions. Pass the resulting object to `Encryption({ schemas: [...] })`\n * when initializing the client.\n *\n * The returned object is also a proxy that exposes each column builder directly,\n * so you can reference columns as `users.email` when calling `encrypt`, `decrypt`,\n * and `encryptQuery`.\n *\n * @param tableName - The name of the database table this schema represents.\n * @param columns - An object whose keys are logical column names and values are\n * {@link EncryptedColumn} from {@link encryptedColumn}, or nested objects whose\n * leaves are {@link EncryptedField} from {@link encryptedField}.\n * @returns A `EncryptedTable<T> & T` that can be used as both a schema definition\n * and a column accessor.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality().freeTextSearch(),\n * address: encryptedColumn(\"address\"),\n * })\n *\n * // Use as schema\n * const client = await Encryption({ schemas: [users] })\n *\n * // Use as column accessor\n * await client.encrypt(\"hello@example.com\", { column: users.email, table: users })\n * ```\n */\nexport function encryptedTable<T extends EncryptedTableColumn>(\n tableName: string,\n columns: T,\n): EncryptedTable<T> & T {\n const tableBuilder = new EncryptedTable(\n tableName,\n columns,\n ) as EncryptedTable<T> & T\n\n for (const [colName, colBuilder] of Object.entries(columns)) {\n ;(tableBuilder as EncryptedTableColumn)[colName] = colBuilder\n }\n\n return tableBuilder\n}\n\n/**\n * Define an encrypted column within a table schema.\n *\n * Creates a `EncryptedColumn` builder for the given column name. Chain index\n * methods (`.equality()`, `.freeTextSearch()`, `.orderAndRange()`,\n * `.searchableJson()`) and/or `.dataType()` to configure searchable encryption\n * and the plaintext data type.\n *\n * @param columnName - The name of the database column to encrypt.\n * @returns A new `EncryptedColumn` builder.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality().freeTextSearch().orderAndRange(),\n * })\n * ```\n */\nexport function encryptedColumn(columnName: string) {\n return new EncryptedColumn(columnName)\n}\n\n/**\n * Define an encrypted field for use in nested or structured schemas.\n *\n * `encryptedField` is similar to {@link encryptedColumn} but creates an {@link EncryptedField}\n * for nested fields that are encrypted but not searchable (no indexes). Use `.dataType()`\n * to specify the plaintext type.\n *\n * @param valueName - The name of the value field.\n * @returns A new `EncryptedField` builder.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedField } from \"@cipherstash/stack/schema\"\n *\n * const orders = encryptedTable(\"orders\", {\n * details: {\n * amount: encryptedField(\"amount\").dataType(\"number\"),\n * currency: encryptedField(\"currency\"),\n * },\n * })\n * ```\n */\nexport function encryptedField(valueName: string) {\n return new EncryptedField(valueName)\n}\n\n// ------------------------\n// Internal functions\n// ------------------------\n\n/** @internal */\nexport function buildEncryptConfig(\n ...protectTables: Array<EncryptedTable<EncryptedTableColumn>>\n): EncryptConfig {\n const config: EncryptConfig = {\n v: 2,\n tables: {},\n }\n\n for (const tb of protectTables) {\n const tableDef = tb.build()\n config.tables[tableDef.tableName] = tableDef.columns\n }\n\n return config\n}\n","import { type EncryptedColumn, encryptedColumn, encryptedTable } from '@/schema'\nimport type { PgTable } from 'drizzle-orm/pg-core'\nimport { getEncryptedColumnConfig } from './index.js'\n\n/**\n * Extracts an encryption schema from a Drizzle table definition.\n * This function identifies columns created with `encryptedType` and\n * builds a corresponding `EncryptedTable` with `encryptedColumn` definitions.\n *\n * @param table - The Drizzle table definition\n * @returns A EncryptedTable that can be used with encryption client initialization\n *\n * @example\n * ```ts\n * const drizzleUsersTable = pgTable('users', {\n * email: encryptedType('email', { freeTextSearch: true, equality: true }),\n * age: encryptedType('age', { dataType: 'number', orderAndRange: true }),\n * })\n *\n * const encryptionSchema = extractEncryptionSchema(drizzleUsersTable)\n * const client = await createEncryptionClient({ schemas: [encryptionSchema.build()] })\n * ```\n */\n// We use any for the PgTable generic because we need to access Drizzle's internal properties\n// biome-ignore lint/suspicious/noExplicitAny: Drizzle table types don't expose Symbol properties\nexport function extractEncryptionSchema<T extends PgTable<any>>(\n table: T,\n): ReturnType<typeof encryptedTable<Record<string, EncryptedColumn>>> {\n // Drizzle tables store the name in a Symbol property\n // biome-ignore lint/suspicious/noExplicitAny: Drizzle tables don't expose Symbol properties in types\n const tableName = (table as any)[Symbol.for('drizzle:Name')] as\n | string\n | undefined\n if (!tableName) {\n throw new Error(\n 'Unable to extract table name from Drizzle table. Ensure you are using a table created with pgTable().',\n )\n }\n\n const columns: Record<string, EncryptedColumn> = {}\n\n // Iterate through table columns\n for (const [columnName, column] of Object.entries(table)) {\n // Skip if it's not a column (could be methods or other properties)\n if (typeof column !== 'object' || column === null) {\n continue\n }\n\n // Check if this column has encrypted configuration\n const config = getEncryptedColumnConfig(columnName, column)\n\n if (config) {\n // Extract the actual column name from the column object (not the schema key)\n // Drizzle columns have a 'name' property that contains the actual database column name\n const actualColumnName = column.name || config.name\n\n // This is an encrypted column - build encryptedColumn using the actual column name\n const csCol = encryptedColumn(actualColumnName)\n\n // Apply data type\n if (config.dataType && config.dataType !== 'string') {\n csCol.dataType(config.dataType)\n }\n\n // Apply indexes based on configuration\n if (config.orderAndRange) {\n csCol.orderAndRange()\n }\n\n if (config.equality) {\n if (Array.isArray(config.equality)) {\n // Custom token filters\n csCol.equality(config.equality)\n } else {\n // Default equality (boolean true)\n csCol.equality()\n }\n }\n\n if (config.freeTextSearch) {\n if (typeof config.freeTextSearch === 'object') {\n // Custom match options\n csCol.freeTextSearch(config.freeTextSearch)\n } else {\n // Default freeTextSearch (boolean true)\n csCol.freeTextSearch()\n }\n }\n\n if (config.searchableJson) {\n if (config.dataType !== 'json') {\n throw new Error(\n `Column \"${columnName}\" has searchableJson enabled but dataType is \"${config.dataType ?? 'string'}\". searchableJson requires dataType: 'json'.`,\n )\n }\n csCol.searchableJson()\n }\n\n columns[actualColumnName] = csCol\n }\n }\n\n if (Object.keys(columns).length === 0) {\n throw new Error(\n `No encrypted columns found in table \"${tableName}\". Use encryptedType() to define encrypted columns.`,\n )\n }\n\n return encryptedTable(tableName, columns)\n}\n","import type {\n EncryptedColumn,\n EncryptedTable,\n EncryptedTableColumn,\n EncryptedField,\n} from '@/schema'\nimport type { LoggingConfig } from '@/utils/logger'\nimport type {\n Encrypted as CipherStashEncrypted,\n JsPlaintext,\n QueryOpName,\n newClient,\n} from '@cipherstash/protect-ffi'\n\n// ---------------------------------------------------------------------------\n// Branded type utilities\n// ---------------------------------------------------------------------------\n\n/** Brand symbol for nominal typing */\ndeclare const __brand: unique symbol\n\n/** Creates a branded type that is structurally incompatible with the base type */\ntype Brand<T, B extends string> = T & { readonly [__brand]: B }\n\n// ---------------------------------------------------------------------------\n// Core types\n// ---------------------------------------------------------------------------\n\nexport type Client = Awaited<ReturnType<typeof newClient>> | undefined\n\n/** A branded type representing encrypted data. Cannot be accidentally used as plaintext. */\nexport type EncryptedValue = Brand<CipherStashEncrypted, 'encrypted'> | null\n\n/** Structural type representing encrypted data. See also `EncryptedValue` for branded nominal typing. */\nexport type Encrypted = CipherStashEncrypted | null\n\nexport type EncryptPayload = JsPlaintext | null\n\n// ---------------------------------------------------------------------------\n// Client configuration\n// ---------------------------------------------------------------------------\n\nexport type KeysetIdentifier = { name: string } | { id: string }\n\nexport type ClientConfig = {\n /**\n * The CipherStash workspace CRN (Cloud Resource Name).\n * Format: `crn:<region>.aws:<workspace-id>`.\n * Can also be set via the `CS_WORKSPACE_CRN` environment variable.\n * If omitted, the SDK reads from the environment or TOML config files.\n */\n workspaceCrn?: string\n\n /**\n * The API access key used for authenticating with the CipherStash API.\n * Can also be set via the `CS_CLIENT_ACCESS_KEY` environment variable.\n * Obtain this from the CipherStash dashboard after creating a workspace.\n */\n accessKey?: string\n\n /**\n * The client identifier used to authenticate with CipherStash services.\n * Can also be set via the `CS_CLIENT_ID` environment variable.\n * Generated during workspace onboarding in the CipherStash dashboard.\n */\n clientId?: string\n\n /**\n * The client key material used in combination with ZeroKMS for encryption operations.\n * Can also be set via the `CS_CLIENT_KEY` environment variable.\n * Generated during workspace onboarding in the CipherStash dashboard.\n */\n clientKey?: string\n\n /**\n * An optional keyset identifier for multi-tenant encryption.\n * Each keyset provides cryptographic isolation, giving each tenant its own keyspace.\n * Specify by name (`{ name: \"tenant-a\" }`) or UUID (`{ id: \"...\" }`).\n * Keysets are created and managed in the CipherStash dashboard.\n */\n keyset?: KeysetIdentifier\n}\n\ntype AtLeastOneCsTable<T> = [T, ...T[]]\n\nexport type EncryptionClientConfig = {\n schemas: AtLeastOneCsTable<EncryptedTable<EncryptedTableColumn>>\n config?: ClientConfig\n logging?: LoggingConfig\n}\n\n// ---------------------------------------------------------------------------\n// Encrypt / decrypt operation options and results\n// ---------------------------------------------------------------------------\n\n/**\n * Options for single-value encrypt operations.\n * Use a column from your table schema (from {@link encryptedColumn}) or a nested\n * field (from {@link encryptedField}) as the target for encryption.\n */\nexport type EncryptOptions = {\n /** The column or nested field to encrypt into. From {@link EncryptedColumn} or {@link EncryptedField}. */\n column: EncryptedColumn | EncryptedField\n table: EncryptedTable<EncryptedTableColumn>\n}\n\n/** Format for encrypted query/search term return values */\nexport type EncryptedReturnType =\n | 'eql'\n | 'composite-literal'\n | 'escaped-composite-literal'\n\nexport type SearchTerm = {\n value: JsPlaintext\n column: EncryptedColumn\n table: EncryptedTable<EncryptedTableColumn>\n returnType?: EncryptedReturnType\n}\n\n/** Encrypted search term result: EQL object or composite literal string */\nexport type EncryptedSearchTerm = Encrypted | string\n\n/** Result of encryptQuery (single or batch): EQL, composite literal string, or null */\nexport type EncryptedQueryResult = Encrypted | string | null\n\n// ---------------------------------------------------------------------------\n// Model field types (encrypted vs decrypted views)\n// ---------------------------------------------------------------------------\n\nexport type EncryptedFields<T> = {\n [K in keyof T as T[K] extends Encrypted ? K : never]: T[K]\n}\n\nexport type OtherFields<T> = {\n [K in keyof T as T[K] extends Encrypted ? never : K]: T[K]\n}\n\nexport type DecryptedFields<T> = {\n [K in keyof T as T[K] extends Encrypted ? K : never]: string\n}\n\n/** Model with encrypted fields replaced by plaintext (decrypted) values */\nexport type Decrypted<T> = OtherFields<T> & DecryptedFields<T>\n\n/**\n * Maps a plaintext model type to its encrypted form using the table schema.\n *\n * Fields whose keys match columns defined in `S` become `Encrypted`;\n * all other fields retain their original types from `T`.\n *\n * When `S` is the widened `EncryptedTableColumn` (e.g. when a user passes an\n * explicit `<User>` type argument without specifying `S`), the type degrades\n * gracefully to `T` — preserving backward compatibility.\n *\n * @typeParam T - The plaintext model type (e.g. `{ id: string; email: string }`)\n * @typeParam S - The table schema column definition, inferred from the `table` argument\n *\n * @example\n * ```typescript\n * type User = { id: string; email: string }\n * // With a schema that defines `email`:\n * type Encrypted = EncryptedFromSchema<User, { email: EncryptedColumn }>\n * // => { id: string; email: Encrypted }\n * ```\n */\nexport type EncryptedFromSchema<T, S extends EncryptedTableColumn> = {\n [K in keyof T]: [K] extends [keyof S]\n ? [S[K & keyof S]] extends [EncryptedColumn | EncryptedField]\n ? Encrypted\n : T[K]\n : T[K]\n}\n\n// ---------------------------------------------------------------------------\n// Bulk operations\n// ---------------------------------------------------------------------------\n\nexport type BulkEncryptPayload = Array<{\n id?: string\n plaintext: JsPlaintext | null\n}>\n\nexport type BulkEncryptedData = Array<{ id?: string; data: Encrypted }>\nexport type BulkDecryptPayload = Array<{ id?: string; data: Encrypted }>\nexport type BulkDecryptedData = Array<DecryptionResult<JsPlaintext | null>>\n\ntype DecryptionSuccess<T> = { error?: never; data: T; id?: string }\ntype DecryptionError<T> = { error: T; id?: string; data?: never }\n\n/**\n * Result type for individual items in bulk decrypt operations.\n * Uses `error`/`data` fields (not `failure`/`data`) since bulk operations\n * can have per-item failures.\n */\nexport type DecryptionResult<T> = DecryptionSuccess<T> | DecryptionError<T>\n\n// ---------------------------------------------------------------------------\n// Query types (for searchable encryption / encryptQuery)\n// ---------------------------------------------------------------------------\n\n/**\n * User-facing query type names for encrypting query values.\n *\n * - `'equality'`: Exact match. [Exact Queries](https://cipherstash.com/docs/platform/searchable-encryption/supported-queries/exact)\n * - `'freeTextSearch'`: Text search. [Match Queries](https://cipherstash.com/docs/platform/searchable-encryption/supported-queries/match)\n * - `'orderAndRange'`: Comparison and range. [Range Queries](https://cipherstash.com/docs/platform/searchable-encryption/supported-queries/range)\n * - `'steVecSelector'`: JSONPath selector (e.g. `'$.user.email'`)\n * - `'steVecTerm'`: Containment (e.g. `{ role: 'admin' }`)\n * - `'searchableJson'`: Auto-infers selector or term from plaintext type (recommended)\n */\nexport type QueryTypeName =\n | 'orderAndRange'\n | 'freeTextSearch'\n | 'equality'\n | 'steVecSelector'\n | 'steVecTerm'\n | 'searchableJson'\n\n/** @internal */\nexport type FfiIndexTypeName = 'ore' | 'match' | 'unique' | 'ste_vec'\n\nexport const queryTypes = {\n orderAndRange: 'orderAndRange',\n freeTextSearch: 'freeTextSearch',\n equality: 'equality',\n steVecSelector: 'steVecSelector',\n steVecTerm: 'steVecTerm',\n searchableJson: 'searchableJson',\n} as const satisfies Record<string, QueryTypeName>\n\n/** @internal */\nexport const queryTypeToFfi: Record<QueryTypeName, FfiIndexTypeName> = {\n orderAndRange: 'ore',\n freeTextSearch: 'match',\n equality: 'unique',\n steVecSelector: 'ste_vec',\n steVecTerm: 'ste_vec',\n searchableJson: 'ste_vec',\n}\n\n/** @internal */\nexport const queryTypeToQueryOp: Partial<Record<QueryTypeName, QueryOpName>> = {\n steVecSelector: 'ste_vec_selector',\n steVecTerm: 'ste_vec_term',\n}\n\n/** @internal */\nexport type QueryTermBase = {\n column: EncryptedColumn\n table: EncryptedTable<EncryptedTableColumn>\n queryType?: QueryTypeName\n returnType?: EncryptedReturnType\n}\n\nexport type EncryptQueryOptions = QueryTermBase\n\nexport type ScalarQueryTerm = QueryTermBase & {\n value: JsPlaintext | null\n}\n","import type { EncryptionClient } from '@/encryption/index.js'\nimport type {\n EncryptedColumn,\n EncryptedTable,\n EncryptedTableColumn,\n} from '@/schema'\nimport { type QueryTypeName, queryTypes } from '@/types'\nimport {\n type SQL,\n type SQLWrapper,\n and,\n arrayContained,\n arrayContains,\n arrayOverlaps,\n asc,\n between,\n desc,\n eq,\n exists,\n gt,\n gte,\n ilike,\n inArray,\n isNotNull,\n isNull,\n like,\n lt,\n lte,\n ne,\n not,\n notBetween,\n notExists,\n notIlike,\n notInArray,\n or,\n} from 'drizzle-orm'\nimport { bindIfParam, sql } from 'drizzle-orm'\nimport type { PgTable } from 'drizzle-orm/pg-core'\nimport type { EncryptedColumnConfig } from './index.js'\nimport { getEncryptedColumnConfig } from './index.js'\nimport { extractEncryptionSchema } from './schema-extraction.js'\n\n// ============================================================================\n// Type Definitions and Type Guards\n// ============================================================================\n\n/**\n * Branded type for Drizzle table with encrypted columns\n */\n// biome-ignore lint/suspicious/noExplicitAny: Drizzle table types don't expose Symbol properties\ntype EncryptedDrizzleTable = PgTable<any> & {\n readonly __isEncryptedTable?: true\n}\n\n/**\n * Type guard to check if a value is a Drizzle SQLWrapper\n */\nfunction isSQLWrapper(value: unknown): value is SQLWrapper {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'sql' in value &&\n typeof (value as { sql: unknown }).sql !== 'undefined'\n )\n}\n\n/**\n * Type guard to check if a value is a Drizzle table\n */\nfunction isPgTable(value: unknown): value is EncryptedDrizzleTable {\n return (\n typeof value === 'object' &&\n value !== null &&\n Symbol.for('drizzle:Name') in value\n )\n}\n\n/**\n * Custom error types for better debugging\n */\nexport class EncryptionOperatorError extends Error {\n constructor(\n message: string,\n public readonly context?: {\n tableName?: string\n columnName?: string\n operator?: string\n },\n ) {\n super(message)\n this.name = 'EncryptionOperatorError'\n }\n}\n\nexport class EncryptionConfigError extends EncryptionOperatorError {\n constructor(message: string, context?: EncryptionOperatorError['context']) {\n super(message, context)\n this.name = 'EncryptionConfigError'\n }\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Helper to extract table name from a Drizzle table\n */\nfunction getDrizzleTableName(drizzleTable: unknown): string | undefined {\n if (!isPgTable(drizzleTable)) {\n return undefined\n }\n // Access Symbol property using Record type to avoid indexing errors\n const tableWithSymbol = drizzleTable as unknown as Record<\n symbol,\n string | undefined\n >\n return tableWithSymbol[Symbol.for('drizzle:Name')]\n}\n\n/**\n * Helper to get the drizzle table from a drizzle column\n */\nfunction getDrizzleTableFromColumn(drizzleColumn: SQLWrapper): unknown {\n const column = drizzleColumn as unknown as Record<string, unknown>\n return column.table as unknown\n}\n\n/**\n * Helper to extract encrypted table from a drizzle column by deriving it from the column's parent table\n */\nfunction getEncryptedTableFromColumn(\n drizzleColumn: SQLWrapper,\n tableCache: Map<string, EncryptedTable<EncryptedTableColumn>>,\n): EncryptedTable<EncryptedTableColumn> | undefined {\n const drizzleTable = getDrizzleTableFromColumn(drizzleColumn)\n if (!drizzleTable) {\n return undefined\n }\n\n const tableName = getDrizzleTableName(drizzleTable)\n if (!tableName) {\n return undefined\n }\n\n // Check cache first\n let encryptedTable = tableCache.get(tableName)\n if (encryptedTable) {\n return encryptedTable\n }\n\n // Extract encryption schema from drizzle table and cache it\n try {\n // biome-ignore lint/suspicious/noExplicitAny: PgTable type doesn't expose all needed properties\n encryptedTable = extractEncryptionSchema(drizzleTable as PgTable<any>)\n tableCache.set(tableName, encryptedTable)\n return encryptedTable\n } catch {\n // Table doesn't have encrypted columns or extraction failed\n return undefined\n }\n}\n\n/**\n * Helper to get the encrypted column definition for a Drizzle column from the encrypted table\n */\nfunction getEncryptedColumn(\n drizzleColumn: SQLWrapper,\n encryptedTable: EncryptedTable<EncryptedTableColumn>,\n): EncryptedColumn | undefined {\n const column = drizzleColumn as unknown as Record<string, unknown>\n const columnName = column.name as string | undefined\n if (!columnName) {\n return undefined\n }\n\n const tableRecord = encryptedTable as unknown as Record<string, unknown>\n return tableRecord[columnName] as EncryptedColumn | undefined\n}\n\n/**\n * Column metadata extracted from a Drizzle column\n */\ninterface ColumnInfo {\n readonly encryptedColumn: EncryptedColumn | undefined\n readonly config: (EncryptedColumnConfig & { name: string }) | undefined\n readonly encryptedTable: EncryptedTable<EncryptedTableColumn> | undefined\n readonly columnName: string\n readonly tableName: string | undefined\n}\n\n/**\n * Helper to get the encrypted column and column config for a Drizzle column\n * If encryptedTable is not provided, it will be derived from the column\n */\nfunction getColumnInfo(\n drizzleColumn: SQLWrapper,\n encryptedTable: EncryptedTable<EncryptedTableColumn> | undefined,\n tableCache: Map<string, EncryptedTable<EncryptedTableColumn>>,\n): ColumnInfo {\n const column = drizzleColumn as unknown as Record<string, unknown>\n const columnName = (column.name as string | undefined) || 'unknown'\n\n // If encryptedTable not provided, try to derive it from the column\n let resolvedTable = encryptedTable\n if (!resolvedTable) {\n resolvedTable = getEncryptedTableFromColumn(drizzleColumn, tableCache)\n }\n\n const drizzleTable = getDrizzleTableFromColumn(drizzleColumn)\n const tableName = getDrizzleTableName(drizzleTable)\n\n if (!resolvedTable) {\n // Column is not from an encrypted table\n const config = getEncryptedColumnConfig(columnName, drizzleColumn)\n return {\n encryptedColumn: undefined,\n config,\n encryptedTable: undefined,\n columnName,\n tableName,\n }\n }\n\n const encryptedColumn = getEncryptedColumn(drizzleColumn, resolvedTable)\n const config = getEncryptedColumnConfig(columnName, drizzleColumn)\n\n return {\n encryptedColumn,\n config,\n encryptedTable: resolvedTable,\n columnName,\n tableName,\n }\n}\n\n/**\n * Helper to convert a value to plaintext format\n */\nfunction toPlaintext(value: unknown): string | number {\n if (typeof value === 'boolean') {\n return value ? 1 : 0\n }\n if (typeof value === 'string' || typeof value === 'number') {\n return value\n }\n if (value instanceof Date) {\n return value.toISOString()\n }\n return String(value)\n}\n\n/**\n * Value to encrypt with its associated column\n */\ninterface ValueToEncrypt {\n readonly value: string | number\n readonly column: SQLWrapper\n readonly columnInfo: ColumnInfo\n readonly queryType?: QueryTypeName\n readonly originalIndex: number\n}\n\n/**\n * Helper to encrypt multiple values for use in a query\n * Returns an array of encrypted search terms or original values if not encrypted\n */\nasync function encryptValues(\n encryptionClient: EncryptionClient,\n values: Array<{\n value: unknown\n column: SQLWrapper\n queryType?: QueryTypeName\n }>,\n encryptedTable: EncryptedTable<EncryptedTableColumn> | undefined,\n tableCache: Map<string, EncryptedTable<EncryptedTableColumn>>,\n): Promise<unknown[]> {\n if (values.length === 0) {\n return []\n }\n\n // Single pass: collect values to encrypt with their metadata\n const valuesToEncrypt: ValueToEncrypt[] = []\n const results: unknown[] = new Array(values.length)\n\n for (let i = 0; i < values.length; i++) {\n const { value, column, queryType } = values[i]\n const columnInfo = getColumnInfo(column, encryptedTable, tableCache)\n\n if (\n !columnInfo.encryptedColumn ||\n !columnInfo.config ||\n !columnInfo.encryptedTable\n ) {\n // Column is not encrypted, return value as-is\n results[i] = value\n continue\n }\n\n const plaintextValue = toPlaintext(value)\n valuesToEncrypt.push({\n value: plaintextValue,\n column,\n columnInfo,\n queryType,\n originalIndex: i,\n })\n }\n\n if (valuesToEncrypt.length === 0) {\n return results\n }\n\n // Group values by column to batch encrypt with same column/table\n const columnGroups = new Map<\n string,\n {\n column: EncryptedColumn\n table: EncryptedTable<EncryptedTableColumn>\n columnName: string\n values: Array<{\n value: string | number\n index: number\n queryType?: QueryTypeName\n }>\n resultIndices: number[]\n }\n >()\n\n let valueIndex = 0\n for (const {\n value,\n columnInfo,\n queryType,\n originalIndex,\n } of valuesToEncrypt) {\n // Safe access with validation - we know these exist from earlier checks\n if (\n !columnInfo.config ||\n !columnInfo.encryptedColumn ||\n !columnInfo.encryptedTable\n ) {\n continue\n }\n\n const columnName = columnInfo.config.name\n const groupKey = `${columnInfo.tableName ?? 'unknown'}/${columnName}`\n let group = columnGroups.get(groupKey)\n if (!group) {\n group = {\n column: columnInfo.encryptedColumn,\n table: columnInfo.encryptedTable,\n columnName,\n values: [],\n resultIndices: [],\n }\n columnGroups.set(groupKey, group)\n }\n group.values.push({ value, index: valueIndex++, queryType })\n group.resultIndices.push(originalIndex)\n }\n\n // Encrypt all values for each column in batches\n for (const [, group] of columnGroups) {\n const { columnName } = group\n try {\n const terms = group.values.map((v) => ({\n value: v.value,\n column: group.column,\n table: group.table,\n queryType: v.queryType,\n }))\n\n const encryptedTerms = await encryptionClient.encryptQuery(terms)\n\n if (encryptedTerms.failure) {\n throw new EncryptionOperatorError(\n `Failed to encrypt query terms for column \"${columnName}\": ${encryptedTerms.failure.message}`,\n { columnName },\n )\n }\n\n // Map results back to original indices\n for (let i = 0; i < group.values.length; i++) {\n const resultIndex = group.resultIndices[i] ?? -1\n if (resultIndex >= 0 && resultIndex < results.length) {\n results[resultIndex] = encryptedTerms.data[i]\n }\n }\n } catch (error) {\n if (error instanceof EncryptionOperatorError) {\n throw error\n }\n const errorMessage =\n error instanceof Error ? error.message : String(error)\n throw new EncryptionOperatorError(\n `Unexpected error encrypting values for column \"${columnName}\": ${errorMessage}`,\n { columnName },\n )\n }\n }\n\n return results\n}\n\n/**\n * Helper to encrypt a single value for use in a query\n * Returns the encrypted search term or the original value if not encrypted\n */\nasync function encryptValue(\n encryptionClient: EncryptionClient,\n value: unknown,\n drizzleColumn: SQLWrapper,\n encryptedTable: EncryptedTable<EncryptedTableColumn> | undefined,\n tableCache: Map<string, EncryptedTable<EncryptedTableColumn>>,\n queryType?: QueryTypeName,\n): Promise<unknown> {\n const results = await encryptValues(\n encryptionClient,\n [{ value, column: drizzleColumn, queryType }],\n encryptedTable,\n tableCache,\n )\n return results[0]\n}\n\n// ============================================================================\n// Lazy Operator Pattern\n// ============================================================================\n\n/**\n * Simplified lazy operator that defers encryption until awaited or batched\n */\ninterface LazyOperator {\n readonly __isLazyOperator: true\n readonly operator: string\n readonly queryType?: QueryTypeName\n readonly left: SQLWrapper\n readonly right: unknown\n readonly min?: unknown\n readonly max?: unknown\n readonly needsEncryption: boolean\n readonly columnInfo: ColumnInfo\n execute(\n encrypted: unknown,\n encryptedMin?: unknown,\n encryptedMax?: unknown,\n ): SQL\n}\n\n/**\n * Type guard for lazy operators\n */\nfunction isLazyOperator(value: unknown): value is LazyOperator {\n return (\n typeof value === 'object' &&\n value !== null &&\n '__isLazyOperator' in value &&\n (value as LazyOperator).__isLazyOperator === true\n )\n}\n\n/**\n * Creates a lazy operator that defers execution\n */\nfunction createLazyOperator(\n operator: string,\n left: SQLWrapper,\n right: unknown,\n execute: (\n encrypted: unknown,\n encryptedMin?: unknown,\n encryptedMax?: unknown,\n ) => SQL,\n needsEncryption: boolean,\n columnInfo: ColumnInfo,\n encryptionClient: EncryptionClient,\n defaultTable: EncryptedTable<EncryptedTableColumn> | undefined,\n tableCache: Map<string, EncryptedTable<EncryptedTableColumn>>,\n min?: unknown,\n max?: unknown,\n queryType?: QueryTypeName,\n): LazyOperator & Promise<SQL> {\n let resolvedSQL: SQL | undefined\n let encryptionPromise: Promise<SQL> | undefined\n\n const lazyOp: LazyOperator = {\n __isLazyOperator: true,\n operator,\n queryType,\n left,\n right,\n min,\n max,\n needsEncryption,\n columnInfo,\n execute,\n }\n\n // Create a promise that will be resolved when encryption completes\n const promise = new Promise<SQL>((resolve, reject) => {\n // Auto-execute when awaited directly\n queueMicrotask(async () => {\n if (resolvedSQL !== undefined) {\n resolve(resolvedSQL)\n return\n }\n\n try {\n if (!encryptionPromise) {\n encryptionPromise = executeLazyOperatorDirect(\n lazyOp,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n const sql = await encryptionPromise\n resolvedSQL = sql\n resolve(sql)\n } catch (error) {\n reject(error)\n }\n })\n })\n\n // Attach lazy operator properties to the promise\n return Object.assign(promise, lazyOp)\n}\n\n/**\n * Executes a lazy operator with pre-encrypted values (used in batched mode)\n */\nasync function executeLazyOperator(\n lazyOp: LazyOperator,\n encryptedValues?: { value: unknown; encrypted: unknown }[],\n): Promise<SQL> {\n if (!lazyOp.needsEncryption) {\n return lazyOp.execute(lazyOp.right)\n }\n\n if (lazyOp.min !== undefined && lazyOp.max !== undefined) {\n // Between operator - use provided encrypted values\n let encryptedMin: unknown\n let encryptedMax: unknown\n\n if (encryptedValues && encryptedValues.length >= 2) {\n encryptedMin = encryptedValues[0]?.encrypted\n encryptedMax = encryptedValues[1]?.encrypted\n } else {\n throw new EncryptionOperatorError(\n 'Between operator requires both min and max encrypted values',\n {\n columnName: lazyOp.columnInfo.columnName,\n tableName: lazyOp.columnInfo.tableName,\n operator: lazyOp.operator,\n },\n )\n }\n\n if (encryptedMin === undefined || encryptedMax === undefined) {\n throw new EncryptionOperatorError(\n 'Between operator requires both min and max values to be encrypted',\n {\n columnName: lazyOp.columnInfo.columnName,\n tableName: lazyOp.columnInfo.tableName,\n operator: lazyOp.operator,\n },\n )\n }\n\n return lazyOp.execute(undefined, encryptedMin, encryptedMax)\n }\n\n // Single value operator\n let encrypted: unknown\n\n if (encryptedValues && encryptedValues.length > 0) {\n encrypted = encryptedValues[0]?.encrypted\n } else {\n throw new EncryptionOperatorError(\n 'Operator requires encrypted value but none provided',\n {\n columnName: lazyOp.columnInfo.columnName,\n tableName: lazyOp.columnInfo.tableName,\n operator: lazyOp.operator,\n },\n )\n }\n\n if (encrypted === undefined) {\n throw new EncryptionOperatorError(\n 'Encryption failed or value was not encrypted',\n {\n columnName: lazyOp.columnInfo.columnName,\n tableName: lazyOp.columnInfo.tableName,\n operator: lazyOp.operator,\n },\n )\n }\n\n return lazyOp.execute(encrypted)\n}\n\n/**\n * Executes a lazy operator directly by encrypting values on demand\n * Used when operator is awaited directly (not batched)\n */\nasync function executeLazyOperatorDirect(\n lazyOp: LazyOperator,\n encryptionClient: EncryptionClient,\n defaultTable: EncryptedTable<EncryptedTableColumn> | undefined,\n tableCache: Map<string, EncryptedTable<EncryptedTableColumn>>,\n): Promise<SQL> {\n if (!lazyOp.needsEncryption) {\n return lazyOp.execute(lazyOp.right)\n }\n\n if (lazyOp.min !== undefined && lazyOp.max !== undefined) {\n // Between operator - encrypt min and max\n const [encryptedMin, encryptedMax] = await encryptValues(\n encryptionClient,\n [\n { value: lazyOp.min, column: lazyOp.left, queryType: lazyOp.queryType },\n { value: lazyOp.max, column: lazyOp.left, queryType: lazyOp.queryType },\n ],\n defaultTable,\n tableCache,\n )\n return lazyOp.execute(undefined, encryptedMin, encryptedMax)\n }\n\n // Single value operator\n const encrypted = await encryptValue(\n encryptionClient,\n lazyOp.right,\n lazyOp.left,\n defaultTable,\n tableCache,\n lazyOp.queryType,\n )\n\n return lazyOp.execute(encrypted)\n}\n\n// ============================================================================\n// Operator Factory Functions\n// ============================================================================\n\n/**\n * Creates a comparison operator (eq, ne, gt, gte, lt, lte)\n */\nfunction createComparisonOperator(\n operator: 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte',\n left: SQLWrapper,\n right: unknown,\n columnInfo: ColumnInfo,\n encryptionClient: EncryptionClient,\n defaultTable: EncryptedTable<EncryptedTableColumn> | undefined,\n tableCache: Map<string, EncryptedTable<EncryptedTableColumn>>,\n): Promise<SQL> | SQL {\n const { config } = columnInfo\n\n // Operators requiring orderAndRange index\n const requiresOrderAndRange = ['gt', 'gte', 'lt', 'lte'].includes(operator)\n\n if (requiresOrderAndRange) {\n if (!config?.orderAndRange) {\n // Return regular Drizzle operator for non-encrypted columns\n switch (operator) {\n case 'gt':\n return gt(left, right)\n case 'gte':\n return gte(left, right)\n case 'lt':\n return lt(left, right)\n case 'lte':\n return lte(left, right)\n }\n }\n\n // This will be replaced with encrypted value in executeLazyOperator\n const executeFn = (encrypted: unknown) => {\n if (encrypted === undefined) {\n throw new EncryptionOperatorError(\n `Encryption failed for ${operator} operator`,\n {\n columnName: columnInfo.columnName,\n tableName: columnInfo.tableName,\n operator,\n },\n )\n }\n return sql`eql_v2.${sql.raw(operator)}(${left}, ${bindIfParam(encrypted, left)})`\n }\n\n return createLazyOperator(\n operator,\n left,\n right,\n executeFn,\n true,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n undefined, // min\n undefined, // max\n queryTypes.orderAndRange,\n ) as Promise<SQL>\n }\n\n // Equality operators (eq, ne)\n const requiresEquality = ['eq', 'ne'].includes(operator)\n\n if (requiresEquality && config?.equality) {\n const executeFn = (encrypted: unknown) => {\n if (encrypted === undefined) {\n throw new EncryptionOperatorError(\n `Encryption failed for ${operator} operator`,\n {\n columnName: columnInfo.columnName,\n tableName: columnInfo.tableName,\n operator,\n },\n )\n }\n return operator === 'eq' ? eq(left, encrypted) : ne(left, encrypted)\n }\n\n return createLazyOperator(\n operator,\n left,\n right,\n executeFn,\n true,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n undefined, // min\n undefined, // max\n queryTypes.equality,\n ) as Promise<SQL>\n }\n\n // Fallback to regular Drizzle operators\n return operator === 'eq' ? eq(left, right) : ne(left, right)\n}\n\n/**\n * Creates a range operator (between, notBetween)\n */\nfunction createRangeOperator(\n operator: 'between' | 'notBetween',\n left: SQLWrapper,\n min: unknown,\n max: unknown,\n columnInfo: ColumnInfo,\n encryptionClient: EncryptionClient,\n defaultTable: EncryptedTable<EncryptedTableColumn> | undefined,\n tableCache: Map<string, EncryptedTable<EncryptedTableColumn>>,\n): Promise<SQL> | SQL {\n const { config } = columnInfo\n\n if (!config?.orderAndRange) {\n return operator === 'between'\n ? between(left, min, max)\n : notBetween(left, min, max)\n }\n\n const executeFn = (\n _encrypted: unknown,\n encryptedMin?: unknown,\n encryptedMax?: unknown,\n ) => {\n if (encryptedMin === undefined || encryptedMax === undefined) {\n throw new EncryptionOperatorError(\n `${operator} operator requires both min and max values`,\n {\n columnName: columnInfo.columnName,\n tableName: columnInfo.tableName,\n operator,\n },\n )\n }\n\n const rangeCondition = sql`eql_v2.gte(${left}, ${bindIfParam(encryptedMin, left)}) AND eql_v2.lte(${left}, ${bindIfParam(encryptedMax, left)})`\n\n return operator === 'between'\n ? rangeCondition\n : sql`NOT (${rangeCondition})`\n }\n\n return createLazyOperator(\n operator,\n left,\n undefined,\n executeFn,\n true,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n min,\n max,\n queryTypes.orderAndRange,\n ) as Promise<SQL>\n}\n\n/**\n * Creates a text search operator (like, ilike, notIlike)\n */\nfunction createTextSearchOperator(\n operator: 'like' | 'ilike' | 'notIlike',\n left: SQLWrapper,\n right: unknown,\n columnInfo: ColumnInfo,\n encryptionClient: EncryptionClient,\n defaultTable: EncryptedTable<EncryptedTableColumn> | undefined,\n tableCache: Map<string, EncryptedTable<EncryptedTableColumn>>,\n): Promise<SQL> | SQL {\n const { config } = columnInfo\n\n if (!config?.freeTextSearch) {\n // Cast to satisfy TypeScript\n const rightValue = right as string | SQLWrapper\n switch (operator) {\n case 'like':\n return like(left as Parameters<typeof like>[0], rightValue)\n case 'ilike':\n return ilike(left as Parameters<typeof ilike>[0], rightValue)\n case 'notIlike':\n return notIlike(left as Parameters<typeof notIlike>[0], rightValue)\n }\n }\n\n const executeFn = (encrypted: unknown) => {\n if (encrypted === undefined) {\n throw new EncryptionOperatorError(\n `Encryption failed for ${operator} operator`,\n {\n columnName: columnInfo.columnName,\n tableName: columnInfo.tableName,\n operator,\n },\n )\n }\n\n const sqlFn = sql`eql_v2.${sql.raw(operator === 'notIlike' ? 'ilike' : operator)}(${left}, ${bindIfParam(encrypted, left)})`\n return operator === 'notIlike' ? sql`NOT (${sqlFn})` : sqlFn\n }\n\n return createLazyOperator(\n operator,\n left,\n right,\n executeFn,\n true,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n undefined, // min\n undefined, // max\n queryTypes.freeTextSearch,\n ) as Promise<SQL>\n}\n\n/**\n * Creates a JSONB operator that encrypts a JSON path selector and wraps it\n * in the appropriate `eql_v2` function call.\n *\n * Supports `jsonbPathQueryFirst`, `jsonbGet`, and `jsonbPathExists`.\n * The column must have `searchableJson` enabled in its {@link EncryptedColumnConfig}.\n */\nfunction createJsonbOperator(\n operator: 'jsonbPathQueryFirst' | 'jsonbGet' | 'jsonbPathExists',\n left: SQLWrapper,\n right: unknown,\n columnInfo: ColumnInfo,\n encryptionClient: EncryptionClient,\n defaultTable: EncryptedTable<EncryptedTableColumn> | undefined,\n tableCache: Map<string, EncryptedTable<EncryptedTableColumn>>,\n): Promise<SQL> {\n const { config } = columnInfo\n const encryptedSelector = (value: unknown) =>\n sql`${bindIfParam(value, left)}::eql_v2_encrypted`\n\n if (!config?.searchableJson) {\n throw new EncryptionOperatorError(\n `The ${operator} operator requires searchableJson to be enabled on the column configuration.`,\n {\n columnName: columnInfo.columnName,\n tableName: columnInfo.tableName,\n operator,\n },\n )\n }\n\n const executeFn = (encrypted: unknown) => {\n if (encrypted === undefined) {\n throw new EncryptionOperatorError(\n `Encryption failed for ${operator} operator`,\n {\n columnName: columnInfo.columnName,\n tableName: columnInfo.tableName,\n operator,\n },\n )\n }\n switch (operator) {\n case 'jsonbPathQueryFirst':\n return sql`eql_v2.jsonb_path_query_first(${left}, ${encryptedSelector(encrypted)})`\n case 'jsonbGet':\n return sql`${left} -> ${encryptedSelector(encrypted)}`\n case 'jsonbPathExists':\n return sql`eql_v2.jsonb_path_exists(${left}, ${encryptedSelector(encrypted)})`\n }\n }\n\n return createLazyOperator(\n operator,\n left,\n right,\n executeFn,\n true,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n undefined,\n undefined,\n queryTypes.steVecSelector,\n ) as Promise<SQL>\n}\n\n// ============================================================================\n// Public API: createEncryptionOperators\n// ============================================================================\n\n/**\n * Creates a set of encryption-aware operators that automatically encrypt values\n * for encrypted columns before using them with Drizzle operators.\n *\n * For equality and text search operators (eq, ne, like, ilike, inArray, etc.):\n * Values are encrypted and then passed to regular Drizzle operators, which use\n * PostgreSQL's built-in operators for eql_v2_encrypted types.\n *\n * For order and range operators (gt, gte, lt, lte, between, notBetween):\n * Values are encrypted and then use eql_v2.* functions (eql_v2.gt(), eql_v2.gte(), etc.)\n * which are required for ORE (Order-Revealing Encryption) comparisons.\n *\n * @param encryptionClient - The EncryptionClient instance\n * @returns An object with all Drizzle operators wrapped for encrypted columns\n *\n * @example\n * ```ts\n * // Initialize operators\n * const ops = createEncryptionOperators(encryptionClient)\n *\n * // Equality search - automatically encrypts and uses PostgreSQL operators\n * const results = await db\n * .select()\n * .from(usersTable)\n * .where(await ops.eq(usersTable.email, 'user@example.com'))\n *\n * // Range query - automatically encrypts and uses eql_v2.gte()\n * const olderUsers = await db\n * .select()\n * .from(usersTable)\n * .where(await ops.gte(usersTable.age, 25))\n * ```\n */\nexport function createEncryptionOperators(encryptionClient: EncryptionClient): {\n // Comparison operators\n /**\n * Equality operator - encrypts value for encrypted columns.\n * Requires either `equality` or `orderAndRange` to be set on {@link EncryptedColumnConfig}.\n *\n * @example\n * Select users with a specific email address.\n * ```ts\n * const condition = await ops.eq(usersTable.email, 'user@example.com')\n * const results = await db.select().from(usersTable).where(condition)\n * ```\n */\n eq: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL\n\n /**\n * Not equal operator - encrypts value for encrypted columns.\n * Requires either `equality` or `orderAndRange` to be set on {@link EncryptedColumnConfig}.\n *\n * @example\n * Select users whose email address is not a specific value.\n * ```ts\n * const condition = await ops.ne(usersTable.email, 'user@example.com')\n * const results = await db.select().from(usersTable).where(condition)\n * ```\n */\n ne: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL\n\n /**\n * Greater than operator for encrypted columns with ORE index.\n * Requires `orderAndRange` to be set on {@link EncryptedColumnConfig}.\n *\n * @example\n * Select users older than a specific age.\n * ```ts\n * const condition = await ops.gt(usersTable.age, 30)\n * const results = await db.select().from(usersTable).where(condition)\n * ```\n */\n gt: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL\n\n /**\n * Greater than or equal operator for encrypted columns with ORE index.\n * Requires `orderAndRange` to be set on {@link EncryptedColumnConfig}.\n *\n * @example\n * Select users older than or equal to a specific age.\n * ```ts\n * const condition = await ops.gte(usersTable.age, 30)\n * const results = await db.select().from(usersTable).where(condition)\n * ```\n */\n gte: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL\n\n /**\n * Less than operator for encrypted columns with ORE index.\n * Requires `orderAndRange` to be set on {@link EncryptedColumnConfig}.\n *\n * @example\n * Select users younger than a specific age.\n * ```ts\n * const condition = await ops.lt(usersTable.age, 30)\n * const results = await db.select().from(usersTable).where(condition)\n * ```\n */\n lt: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL\n\n /**\n * Less than or equal operator for encrypted columns with ORE index.\n * Requires `orderAndRange` to be set on {@link EncryptedColumnConfig}.\n *\n * @example\n * Select users younger than or equal to a specific age.\n * ```ts\n * const condition = await ops.lte(usersTable.age, 30)\n * const results = await db.select().from(usersTable).where(condition)\n * ```\n */\n lte: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL\n\n /**\n * Between operator for encrypted columns with ORE index.\n * Requires `orderAndRange` to be set on {@link EncryptedColumnConfig}.\n *\n * @example\n * Select users within a specific age range.\n * ```ts\n * const condition = await ops.between(usersTable.age, 20, 30)\n * const results = await db.select().from(usersTable).where(condition)\n * ```\n */\n between: (left: SQLWrapper, min: unknown, max: unknown) => Promise<SQL> | SQL\n\n /**\n * Not between operator for encrypted columns with ORE index.\n * Requires `orderAndRange` to be set on {@link EncryptedColumnConfig}.\n *\n * @example\n * Select users outside a specific age range.\n * ```ts\n * const condition = await ops.notBetween(usersTable.age, 20, 30)\n * const results = await db.select().from(usersTable).where(condition)\n * ```\n */\n notBetween: (\n left: SQLWrapper,\n min: unknown,\n max: unknown,\n ) => Promise<SQL> | SQL\n\n /**\n * Like operator for encrypted columns with free text search.\n * Requires `freeTextSearch` to be set on {@link EncryptedColumnConfig}.\n *\n * > [!IMPORTANT]\n * > Case sensitivity on encrypted columns depends on the {@link EncryptedColumnConfig}.\n * > Ensure that the column is configured for case-insensitive search if needed.\n *\n * @example\n * Select users with email addresses matching a pattern.\n * ```ts\n * const condition = await ops.like(usersTable.email, '%@example.com')\n * const results = await db.select().from(usersTable).where(condition)\n * ```\n */\n like: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL\n\n /**\n * ILike operator for encrypted columns with free text search.\n * Requires `freeTextSearch` to be set on {@link EncryptedColumnConfig}.\n *\n * > [!IMPORTANT]\n * > Case sensitivity on encrypted columns depends on the {@link EncryptedColumnConfig}.\n * > Ensure that the column is configured for case-insensitive search if needed.\n *\n * @example\n * Select users with email addresses matching a pattern (case-insensitive).\n * ```ts\n * const condition = await ops.ilike(usersTable.email, '%@example.com')\n * const results = await db.select().from(usersTable).where(condition)\n * ```\n */\n ilike: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL\n notIlike: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL\n\n /**\n * JSONB path query first operator for encrypted columns with searchable JSON.\n * Requires `searchableJson` to be set on {@link EncryptedColumnConfig}.\n *\n * Encrypts the JSON path selector and calls `eql_v2.jsonb_path_query_first()`,\n * casting the parameter to `eql_v2_encrypted`.\n *\n * @throws {EncryptionOperatorError} If the column does not have `searchableJson` enabled.\n */\n jsonbPathQueryFirst: (left: SQLWrapper, right: unknown) => Promise<SQL>\n\n /**\n * JSONB get operator for encrypted columns with searchable JSON.\n * Requires `searchableJson` to be set on {@link EncryptedColumnConfig}.\n *\n * Encrypts the JSON path selector and uses the `->` operator,\n * casting the parameter to `eql_v2_encrypted`.\n *\n * @throws {EncryptionOperatorError} If the column does not have `searchableJson` enabled.\n */\n jsonbGet: (left: SQLWrapper, right: unknown) => Promise<SQL>\n\n /**\n * JSONB path exists operator for encrypted columns with searchable JSON.\n * Requires `searchableJson` to be set on {@link EncryptedColumnConfig}.\n *\n * Encrypts the JSON path selector and calls `eql_v2.jsonb_path_exists()`,\n * casting the parameter to `eql_v2_encrypted`.\n *\n * @throws {EncryptionOperatorError} If the column does not have `searchableJson` enabled.\n */\n jsonbPathExists: (left: SQLWrapper, right: unknown) => Promise<SQL>\n // Array operators\n inArray: (left: SQLWrapper, right: unknown[] | SQLWrapper) => Promise<SQL>\n notInArray: (left: SQLWrapper, right: unknown[] | SQLWrapper) => Promise<SQL>\n // Sorting operators\n asc: (column: SQLWrapper) => SQL\n desc: (column: SQLWrapper) => SQL\n and: (\n ...conditions: (SQL | SQLWrapper | Promise<SQL> | undefined)[]\n ) => Promise<SQL>\n or: (\n ...conditions: (SQL | SQLWrapper | Promise<SQL> | undefined)[]\n ) => Promise<SQL>\n // Operators that don't need encryption (pass through to Drizzle)\n exists: typeof exists\n notExists: typeof notExists\n isNull: typeof isNull\n isNotNull: typeof isNotNull\n not: typeof not\n // Array operators that work with arrays directly (not encrypted values)\n arrayContains: typeof arrayContains\n arrayContained: typeof arrayContained\n arrayOverlaps: typeof arrayOverlaps\n} {\n // Create a cache for encrypted tables keyed by table name\n const tableCache = new Map<string, EncryptedTable<EncryptedTableColumn>>()\n const defaultTable: EncryptedTable<EncryptedTableColumn> | undefined =\n undefined\n\n /**\n * Equality operator - encrypts value and uses regular Drizzle operator\n */\n const encryptedEq = (\n left: SQLWrapper,\n right: unknown,\n ): Promise<SQL> | SQL => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createComparisonOperator(\n 'eq',\n left,\n right,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * Not equal operator - encrypts value and uses regular Drizzle operator\n */\n const encryptedNe = (\n left: SQLWrapper,\n right: unknown,\n ): Promise<SQL> | SQL => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createComparisonOperator(\n 'ne',\n left,\n right,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * Greater than operator - uses eql_v2.gt() for encrypted columns with ORE index\n */\n const encryptedGt = (\n left: SQLWrapper,\n right: unknown,\n ): Promise<SQL> | SQL => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createComparisonOperator(\n 'gt',\n left,\n right,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * Greater than or equal operator - uses eql_v2.gte() for encrypted columns with ORE index\n */\n const encryptedGte = (\n left: SQLWrapper,\n right: unknown,\n ): Promise<SQL> | SQL => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createComparisonOperator(\n 'gte',\n left,\n right,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * Less than operator - uses eql_v2.lt() for encrypted columns with ORE index\n */\n const encryptedLt = (\n left: SQLWrapper,\n right: unknown,\n ): Promise<SQL> | SQL => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createComparisonOperator(\n 'lt',\n left,\n right,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * Less than or equal operator - uses eql_v2.lte() for encrypted columns with ORE index\n */\n const encryptedLte = (\n left: SQLWrapper,\n right: unknown,\n ): Promise<SQL> | SQL => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createComparisonOperator(\n 'lte',\n left,\n right,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * Between operator - uses eql_v2.gte() and eql_v2.lte() for encrypted columns with ORE index\n */\n const encryptedBetween = (\n left: SQLWrapper,\n min: unknown,\n max: unknown,\n ): Promise<SQL> | SQL => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createRangeOperator(\n 'between',\n left,\n min,\n max,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * Not between operator - uses eql_v2.gte() and eql_v2.lte() for encrypted columns with ORE index\n */\n const encryptedNotBetween = (\n left: SQLWrapper,\n min: unknown,\n max: unknown,\n ): Promise<SQL> | SQL => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createRangeOperator(\n 'notBetween',\n left,\n min,\n max,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * Like operator - encrypts value and uses eql_v2.like() for encrypted columns with match index\n */\n const encryptedLike = (\n left: SQLWrapper,\n right: unknown,\n ): Promise<SQL> | SQL => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createTextSearchOperator(\n 'like',\n left,\n right,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * Case-insensitive like operator - encrypts value and uses eql_v2.ilike() for encrypted columns with match index\n */\n const encryptedIlike = (\n left: SQLWrapper,\n right: unknown,\n ): Promise<SQL> | SQL => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createTextSearchOperator(\n 'ilike',\n left,\n right,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * Not like operator (case insensitive) - encrypts value and uses eql_v2.ilike() for encrypted columns with match index\n */\n const encryptedNotIlike = (\n left: SQLWrapper,\n right: unknown,\n ): Promise<SQL> | SQL => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createTextSearchOperator(\n 'notIlike',\n left,\n right,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * JSONB path query first operator - encrypts the selector and calls\n * `eql_v2.jsonb_path_query_first()` for encrypted columns with searchable JSON.\n */\n const encryptedJsonbPathQueryFirst = (\n left: SQLWrapper,\n right: unknown,\n ): Promise<SQL> => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createJsonbOperator(\n 'jsonbPathQueryFirst',\n left,\n right,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * JSONB get operator - encrypts the selector and uses the `->` operator\n * for encrypted columns with searchable JSON.\n */\n const encryptedJsonbGet = (\n left: SQLWrapper,\n right: unknown,\n ): Promise<SQL> => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createJsonbOperator(\n 'jsonbGet',\n left,\n right,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * JSONB path exists operator - encrypts the selector and calls\n * `eql_v2.jsonb_path_exists()` for encrypted columns with searchable JSON.\n */\n const encryptedJsonbPathExists = (\n left: SQLWrapper,\n right: unknown,\n ): Promise<SQL> => {\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n return createJsonbOperator(\n 'jsonbPathExists',\n left,\n right,\n columnInfo,\n encryptionClient,\n defaultTable,\n tableCache,\n )\n }\n\n /**\n * In array operator - encrypts all values in the array\n */\n const encryptedInArray = async (\n left: SQLWrapper,\n right: unknown[] | SQLWrapper,\n ): Promise<SQL> => {\n // If right is a SQLWrapper (subquery), pass through to Drizzle\n if (isSQLWrapper(right)) {\n return inArray(left, right as unknown as Parameters<typeof inArray>[1])\n }\n\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n\n if (!columnInfo.config?.equality || !Array.isArray(right)) {\n return inArray(left, right as unknown[])\n }\n\n // Encrypt all values in the array in a single batch\n const encryptedValues = await encryptValues(\n encryptionClient,\n right.map((value) => ({\n value,\n column: left,\n queryType: queryTypes.equality,\n })),\n defaultTable,\n tableCache,\n )\n\n // Use regular eq for each encrypted value - PostgreSQL operators handle it\n const conditions = encryptedValues\n .filter((encrypted) => encrypted !== undefined)\n .map((encrypted) => eq(left, encrypted))\n\n if (conditions.length === 0) {\n return sql`false`\n }\n\n const combined = or(...conditions)\n return combined ?? sql`false`\n }\n\n /**\n * Not in array operator\n */\n const encryptedNotInArray = async (\n left: SQLWrapper,\n right: unknown[] | SQLWrapper,\n ): Promise<SQL> => {\n // If right is a SQLWrapper (subquery), pass through to Drizzle\n if (isSQLWrapper(right)) {\n return notInArray(\n left,\n right as unknown as Parameters<typeof notInArray>[1],\n )\n }\n\n const columnInfo = getColumnInfo(left, defaultTable, tableCache)\n\n if (!columnInfo.config?.equality || !Array.isArray(right)) {\n return notInArray(left, right as unknown[])\n }\n\n // Encrypt all values in the array in a single batch\n const encryptedValues = await encryptValues(\n encryptionClient,\n right.map((value) => ({\n value,\n column: left,\n queryType: queryTypes.equality,\n })),\n defaultTable,\n tableCache,\n )\n\n // Use regular ne for each encrypted value - PostgreSQL operators handle it\n const conditions = encryptedValues\n .filter((encrypted) => encrypted !== undefined)\n .map((encrypted) => ne(left, encrypted))\n\n if (conditions.length === 0) {\n return sql`true`\n }\n\n const combined = and(...conditions)\n return combined ?? sql`true`\n }\n\n /**\n * Ascending order helper - uses eql_v2.order_by() for encrypted columns with ORE index\n */\n const encryptedAsc = (column: SQLWrapper): SQL => {\n const columnInfo = getColumnInfo(column, defaultTable, tableCache)\n\n if (columnInfo.config?.orderAndRange) {\n return asc(sql`eql_v2.order_by(${column})`)\n }\n\n return asc(column)\n }\n\n /**\n * Descending order helper - uses eql_v2.order_by() for encrypted columns with ORE index\n */\n const encryptedDesc = (column: SQLWrapper): SQL => {\n const columnInfo = getColumnInfo(column, defaultTable, tableCache)\n\n if (columnInfo.config?.orderAndRange) {\n return desc(sql`eql_v2.order_by(${column})`)\n }\n\n return desc(column)\n }\n\n /**\n * Batched AND operator - collects lazy operators, batches encryption, and combines conditions\n */\n const encryptedAnd = async (\n ...conditions: (SQL | SQLWrapper | Promise<SQL> | undefined)[]\n ): Promise<SQL> => {\n // Single pass: separate lazy operators from regular conditions\n const lazyOperators: LazyOperator[] = []\n const regularConditions: (SQL | SQLWrapper | undefined)[] = []\n const regularPromises: Promise<SQL>[] = []\n\n for (const condition of conditions) {\n if (condition === undefined) {\n continue\n }\n\n if (isLazyOperator(condition)) {\n lazyOperators.push(condition)\n } else if (condition instanceof Promise) {\n // Check if promise is also a lazy operator\n if (isLazyOperator(condition)) {\n lazyOperators.push(condition)\n } else {\n regularPromises.push(condition)\n }\n } else {\n regularConditions.push(condition)\n }\n }\n\n // If there are no lazy operators, just use Drizzle's and()\n if (lazyOperators.length === 0) {\n const allConditions: (SQL | SQLWrapper | undefined)[] = [\n ...regularConditions,\n ...(await Promise.all(regularPromises)),\n ]\n return and(...allConditions) ?? sql`true`\n }\n\n // Single pass: collect all values to encrypt with metadata\n const valuesToEncrypt: Array<{\n value: unknown\n column: SQLWrapper\n columnInfo: ColumnInfo\n queryType?: QueryTypeName\n lazyOpIndex: number\n isMin?: boolean\n isMax?: boolean\n }> = []\n\n for (let i = 0; i < lazyOperators.length; i++) {\n const lazyOp = lazyOperators[i]\n if (!lazyOp.needsEncryption) {\n continue\n }\n\n if (lazyOp.min !== undefined && lazyOp.max !== undefined) {\n valuesToEncrypt.push({\n value: lazyOp.min,\n column: lazyOp.left,\n columnInfo: lazyOp.columnInfo,\n queryType: lazyOp.queryType,\n lazyOpIndex: i,\n isMin: true,\n })\n valuesToEncrypt.push({\n value: lazyOp.max,\n column: lazyOp.left,\n columnInfo: lazyOp.columnInfo,\n queryType: lazyOp.queryType,\n lazyOpIndex: i,\n isMax: true,\n })\n } else if (lazyOp.right !== undefined) {\n valuesToEncrypt.push({\n value: lazyOp.right,\n column: lazyOp.left,\n columnInfo: lazyOp.columnInfo,\n queryType: lazyOp.queryType,\n lazyOpIndex: i,\n })\n }\n }\n\n // Batch encrypt all values\n const encryptedResults = await encryptValues(\n encryptionClient,\n valuesToEncrypt.map((v) => ({\n value: v.value,\n column: v.column,\n queryType: v.queryType,\n })),\n defaultTable,\n tableCache,\n )\n\n // Group encrypted values by lazy operator index\n const encryptedByLazyOp = new Map<\n number,\n { value?: unknown; min?: unknown; max?: unknown }\n >()\n\n for (let i = 0; i < valuesToEncrypt.length; i++) {\n const { lazyOpIndex, isMin, isMax } = valuesToEncrypt[i]\n const encrypted = encryptedResults[i]\n\n let group = encryptedByLazyOp.get(lazyOpIndex)\n if (!group) {\n group = {}\n encryptedByLazyOp.set(lazyOpIndex, group)\n }\n\n if (isMin) {\n group.min = encrypted\n } else if (isMax) {\n group.max = encrypted\n } else {\n group.value = encrypted\n }\n }\n\n // Execute all lazy operators with their encrypted values\n const sqlConditions: SQL[] = []\n for (let i = 0; i < lazyOperators.length; i++) {\n const lazyOp = lazyOperators[i]\n const encrypted = encryptedByLazyOp.get(i)\n\n let sqlCondition: SQL\n if (lazyOp.needsEncryption && encrypted) {\n const encryptedValues: Array<{ value: unknown; encrypted: unknown }> =\n []\n if (encrypted.value !== undefined) {\n encryptedValues.push({\n value: lazyOp.right,\n encrypted: encrypted.value,\n })\n }\n if (encrypted.min !== undefined) {\n encryptedValues.push({ value: lazyOp.min, encrypted: encrypted.min })\n }\n if (encrypted.max !== undefined) {\n encryptedValues.push({ value: lazyOp.max, encrypted: encrypted.max })\n }\n sqlCondition = await executeLazyOperator(lazyOp, encryptedValues)\n } else {\n sqlCondition = lazyOp.execute(lazyOp.right)\n }\n\n sqlConditions.push(sqlCondition)\n }\n\n // Await any regular promises\n const regularPromisesResults = await Promise.all(regularPromises)\n\n // Combine all conditions\n const allConditions: (SQL | SQLWrapper | undefined)[] = [\n ...regularConditions,\n ...sqlConditions,\n ...regularPromisesResults,\n ]\n\n return and(...allConditions) ?? sql`true`\n }\n\n /**\n * Batched OR operator - collects lazy operators, batches encryption, and combines conditions\n */\n const encryptedOr = async (\n ...conditions: (SQL | SQLWrapper | Promise<SQL> | undefined)[]\n ): Promise<SQL> => {\n const lazyOperators: LazyOperator[] = []\n const regularConditions: (SQL | SQLWrapper | undefined)[] = []\n const regularPromises: Promise<SQL>[] = []\n\n for (const condition of conditions) {\n if (condition === undefined) {\n continue\n }\n\n if (isLazyOperator(condition)) {\n lazyOperators.push(condition)\n } else if (condition instanceof Promise) {\n if (isLazyOperator(condition)) {\n lazyOperators.push(condition)\n } else {\n regularPromises.push(condition)\n }\n } else {\n regularConditions.push(condition)\n }\n }\n\n if (lazyOperators.length === 0) {\n const allConditions: (SQL | SQLWrapper | undefined)[] = [\n ...regularConditions,\n ...(await Promise.all(regularPromises)),\n ]\n return or(...allConditions) ?? sql`false`\n }\n\n const valuesToEncrypt: Array<{\n value: unknown\n column: SQLWrapper\n columnInfo: ColumnInfo\n queryType?: QueryTypeName\n lazyOpIndex: number\n isMin?: boolean\n isMax?: boolean\n }> = []\n\n for (let i = 0; i < lazyOperators.length; i++) {\n const lazyOp = lazyOperators[i]\n if (!lazyOp.needsEncryption) {\n continue\n }\n\n if (lazyOp.min !== undefined && lazyOp.max !== undefined) {\n valuesToEncrypt.push({\n value: lazyOp.min,\n column: lazyOp.left,\n columnInfo: lazyOp.columnInfo,\n queryType: lazyOp.queryType,\n lazyOpIndex: i,\n isMin: true,\n })\n valuesToEncrypt.push({\n value: lazyOp.max,\n column: lazyOp.left,\n columnInfo: lazyOp.columnInfo,\n queryType: lazyOp.queryType,\n lazyOpIndex: i,\n isMax: true,\n })\n } else if (lazyOp.right !== undefined) {\n valuesToEncrypt.push({\n value: lazyOp.right,\n column: lazyOp.left,\n columnInfo: lazyOp.columnInfo,\n queryType: lazyOp.queryType,\n lazyOpIndex: i,\n })\n }\n }\n\n const encryptedResults = await encryptValues(\n encryptionClient,\n valuesToEncrypt.map((v) => ({\n value: v.value,\n column: v.column,\n queryType: v.queryType,\n })),\n defaultTable,\n tableCache,\n )\n\n const encryptedByLazyOp = new Map<\n number,\n { value?: unknown; min?: unknown; max?: unknown }\n >()\n\n for (let i = 0; i < valuesToEncrypt.length; i++) {\n const { lazyOpIndex, isMin, isMax } = valuesToEncrypt[i]\n const encrypted = encryptedResults[i]\n\n let group = encryptedByLazyOp.get(lazyOpIndex)\n if (!group) {\n group = {}\n encryptedByLazyOp.set(lazyOpIndex, group)\n }\n\n if (isMin) {\n group.min = encrypted\n } else if (isMax) {\n group.max = encrypted\n } else {\n group.value = encrypted\n }\n }\n\n const sqlConditions: SQL[] = []\n for (let i = 0; i < lazyOperators.length; i++) {\n const lazyOp = lazyOperators[i]\n const encrypted = encryptedByLazyOp.get(i)\n\n let sqlCondition: SQL\n if (lazyOp.needsEncryption && encrypted) {\n const encryptedValues: Array<{ value: unknown; encrypted: unknown }> =\n []\n if (encrypted.value !== undefined) {\n encryptedValues.push({\n value: lazyOp.right,\n encrypted: encrypted.value,\n })\n }\n if (encrypted.min !== undefined) {\n encryptedValues.push({ value: lazyOp.min, encrypted: encrypted.min })\n }\n if (encrypted.max !== undefined) {\n encryptedValues.push({ value: lazyOp.max, encrypted: encrypted.max })\n }\n sqlCondition = await executeLazyOperator(lazyOp, encryptedValues)\n } else {\n sqlCondition = lazyOp.execute(lazyOp.right)\n }\n\n sqlConditions.push(sqlCondition)\n }\n\n const regularPromisesResults = await Promise.all(regularPromises)\n\n const allConditions: (SQL | SQLWrapper | undefined)[] = [\n ...regularConditions,\n ...sqlConditions,\n ...regularPromisesResults,\n ]\n\n return or(...allConditions) ?? sql`false`\n }\n\n return {\n // Comparison operators\n eq: encryptedEq,\n ne: encryptedNe,\n gt: encryptedGt,\n gte: encryptedGte,\n lt: encryptedLt,\n lte: encryptedLte,\n\n // Range operators\n between: encryptedBetween,\n notBetween: encryptedNotBetween,\n\n // Text search operators\n like: encryptedLike,\n ilike: encryptedIlike,\n notIlike: encryptedNotIlike,\n\n // Searchable JSON operators\n jsonbPathQueryFirst: encryptedJsonbPathQueryFirst,\n jsonbGet: encryptedJsonbGet,\n jsonbPathExists: encryptedJsonbPathExists,\n\n // Array operators\n inArray: encryptedInArray,\n notInArray: encryptedNotInArray,\n\n // Sorting operators\n asc: encryptedAsc,\n desc: encryptedDesc,\n\n // AND operator - batches encryption operations\n and: encryptedAnd,\n\n // OR operator - batches encryption operations\n or: encryptedOr,\n\n // Operators that don't need encryption (pass through to Drizzle)\n exists,\n notExists,\n isNull,\n isNotNull,\n not,\n // Array operators that work with arrays directly (not encrypted values)\n arrayContains,\n arrayContained,\n arrayOverlaps,\n }\n}\n"],"mappings":"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","names":["import_drizzle_orm","encryptedTable","config","encryptedColumn","sql","allConditions"]}