Skip to content

Commit 869e90b

Browse files
committed
docs: comprehensive update to EQL function reference
Fix critical documentation issues and add missing function documentation: - Fix return type names: change eql_v2_* to eql_v2.* for index term extraction functions (hmac_256, blake3, bloom_filter, ore_block_u64_8_256) - Add missing function equivalents for Supabase compatibility: ilike(), lt(), lte(), gt(), gte() - Document configuration lifecycle functions: migrate_config(), activate_config(), discard(), reload_config() - Add aggregate functions: min(), max() - Document jsonb overloads for JSONB path and array functions - Add new Utility Functions section with version(), to_encrypted(), to_jsonb(), check_encrypted() - Standardize terminology: change "context" to "prefix" for ste_vec index configuration - Update table of contents to include new sections This update brings the documentation in line with actual implementation and test behavior, addressing 15+ previously undocumented functions.
1 parent 8e8b06a commit 869e90b

File tree

2 files changed

+273
-13
lines changed

2 files changed

+273
-13
lines changed

docs/reference/eql-functions.md

Lines changed: 264 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ This document provides a comprehensive reference for all EQL (Encrypt Query Lang
1313
- [Array Functions](#array-functions)
1414
- [Helper Functions](#helper-functions)
1515
- [Aggregate Functions](#aggregate-functions)
16+
- [Utility Functions](#utility-functions)
1617

1718
---
1819

@@ -125,6 +126,89 @@ eql_v2.config() RETURNS TABLE (
125126
SELECT * FROM eql_v2.config();
126127
```
127128

129+
### `eql_v2.migrate_config()`
130+
131+
Transition pending configuration to encrypting state.
132+
133+
```sql
134+
eql_v2.migrate_config() RETURNS boolean
135+
```
136+
137+
**Description:**
138+
- Validates that all configured columns exist with `eql_v2_encrypted` type
139+
- Marks the pending configuration as 'encrypting'
140+
- Required before activating a new configuration
141+
142+
**Raises exception if:**
143+
- An encryption is already in progress
144+
- No pending configuration exists
145+
- Some pending columns don't have encrypted targets
146+
147+
**Example:**
148+
```sql
149+
-- Add configuration changes
150+
SELECT eql_v2.add_search_config('users', 'email', 'unique', 'text', migrating => true);
151+
152+
-- Validate and migrate
153+
SELECT eql_v2.migrate_config();
154+
155+
-- After re-encrypting data, activate
156+
SELECT eql_v2.activate_config();
157+
```
158+
159+
### `eql_v2.activate_config()`
160+
161+
Activate an encrypting configuration.
162+
163+
```sql
164+
eql_v2.activate_config() RETURNS boolean
165+
```
166+
167+
**Description:**
168+
- Moves 'encrypting' configuration to 'active' state
169+
- Marks previous 'active' configuration as 'inactive'
170+
- Should be called after data has been re-encrypted with new index terms
171+
172+
**Raises exception if:**
173+
- No encrypting configuration exists
174+
175+
**Example:**
176+
```sql
177+
SELECT eql_v2.activate_config();
178+
```
179+
180+
### `eql_v2.discard()`
181+
182+
Discard pending configuration without activating.
183+
184+
```sql
185+
eql_v2.discard() RETURNS boolean
186+
```
187+
188+
**Description:**
189+
- Deletes the pending configuration
190+
- Use when you want to abandon configuration changes
191+
192+
**Raises exception if:**
193+
- No pending configuration exists
194+
195+
**Example:**
196+
```sql
197+
SELECT eql_v2.discard();
198+
```
199+
200+
### `eql_v2.reload_config()`
201+
202+
Reload active configuration (no-op for compatibility).
203+
204+
```sql
205+
eql_v2.reload_config() RETURNS void
206+
```
207+
208+
**Description:**
209+
- Placeholder function for configuration reload
210+
- Currently has no effect (configuration is loaded automatically)
211+
128212
---
129213

130214
## Query Functions
@@ -215,7 +299,7 @@ eql_v2.neq(a eql_v2_encrypted, b eql_v2_encrypted) RETURNS boolean
215299

216300
#### `eql_v2.like()`
217301

218-
Pattern matching.
302+
Pattern matching (case-sensitive).
219303

220304
```sql
221305
eql_v2.like(a eql_v2_encrypted, b eql_v2_encrypted) RETURNS boolean
@@ -226,6 +310,71 @@ eql_v2.like(a eql_v2_encrypted, b eql_v2_encrypted) RETURNS boolean
226310
SELECT * FROM docs WHERE eql_v2.like(encrypted_content, $1::eql_v2_encrypted);
227311
```
228312

313+
#### `eql_v2.ilike()`
314+
315+
Pattern matching (case-insensitive).
316+
317+
```sql
318+
eql_v2.ilike(a eql_v2_encrypted, b eql_v2_encrypted) RETURNS boolean
319+
```
320+
321+
**Example:**
322+
```sql
323+
SELECT * FROM docs WHERE eql_v2.ilike(encrypted_content, $1::eql_v2_encrypted);
324+
```
325+
326+
#### `eql_v2.lt()`
327+
328+
Less than comparison.
329+
330+
```sql
331+
eql_v2.lt(a eql_v2_encrypted, b eql_v2_encrypted) RETURNS boolean
332+
```
333+
334+
**Example:**
335+
```sql
336+
SELECT * FROM events WHERE eql_v2.lt(encrypted_date, $1::eql_v2_encrypted);
337+
```
338+
339+
#### `eql_v2.lte()`
340+
341+
Less than or equal comparison.
342+
343+
```sql
344+
eql_v2.lte(a eql_v2_encrypted, b eql_v2_encrypted) RETURNS boolean
345+
```
346+
347+
**Example:**
348+
```sql
349+
SELECT * FROM events WHERE eql_v2.lte(encrypted_date, $1::eql_v2_encrypted);
350+
```
351+
352+
#### `eql_v2.gt()`
353+
354+
Greater than comparison.
355+
356+
```sql
357+
eql_v2.gt(a eql_v2_encrypted, b eql_v2_encrypted) RETURNS boolean
358+
```
359+
360+
**Example:**
361+
```sql
362+
SELECT * FROM events WHERE eql_v2.gt(encrypted_date, $1::eql_v2_encrypted);
363+
```
364+
365+
#### `eql_v2.gte()`
366+
367+
Greater than or equal comparison.
368+
369+
```sql
370+
eql_v2.gte(a eql_v2_encrypted, b eql_v2_encrypted) RETURNS boolean
371+
```
372+
373+
**Example:**
374+
```sql
375+
SELECT * FROM events WHERE eql_v2.gte(encrypted_date, $1::eql_v2_encrypted);
376+
```
377+
229378
---
230379

231380
## Index Term Extraction Functions
@@ -237,35 +386,35 @@ These functions extract specific index terms from encrypted values. Typically us
237386
Extract HMAC-256 unique index term.
238387

239388
```sql
240-
eql_v2.hmac_256(val eql_v2_encrypted) RETURNS eql_v2_hmac_256
241-
eql_v2.hmac_256(val jsonb) RETURNS eql_v2_hmac_256
389+
eql_v2.hmac_256(val eql_v2_encrypted) RETURNS eql_v2.hmac_256
390+
eql_v2.hmac_256(val jsonb) RETURNS eql_v2.hmac_256
242391
```
243392

244393
### `eql_v2.blake3()`
245394

246395
Extract Blake3 unique index term.
247396

248397
```sql
249-
eql_v2.blake3(val eql_v2_encrypted) RETURNS eql_v2_blake3
250-
eql_v2.blake3(val jsonb) RETURNS eql_v2_blake3
398+
eql_v2.blake3(val eql_v2_encrypted) RETURNS eql_v2.blake3
399+
eql_v2.blake3(val jsonb) RETURNS eql_v2.blake3
251400
```
252401

253402
### `eql_v2.bloom_filter()`
254403

255404
Extract bloom filter match index term.
256405

257406
```sql
258-
eql_v2.bloom_filter(val eql_v2_encrypted) RETURNS eql_v2_bloom_filter
259-
eql_v2.bloom_filter(val jsonb) RETURNS eql_v2_bloom_filter
407+
eql_v2.bloom_filter(val eql_v2_encrypted) RETURNS eql_v2.bloom_filter
408+
eql_v2.bloom_filter(val jsonb) RETURNS eql_v2.bloom_filter
260409
```
261410

262411
### `eql_v2.ore_block_u64_8_256()`
263412

264413
Extract ORE (Order-Revealing Encryption) index term.
265414

266415
```sql
267-
eql_v2.ore_block_u64_8_256(val eql_v2_encrypted) RETURNS eql_v2_ore_block_u64_8_256_term
268-
eql_v2.ore_block_u64_8_256(val jsonb) RETURNS eql_v2_ore_block_u64_8_256_term
416+
eql_v2.ore_block_u64_8_256(val eql_v2_encrypted) RETURNS eql_v2.ore_block_u64_8_256
417+
eql_v2.ore_block_u64_8_256(val jsonb) RETURNS eql_v2.ore_block_u64_8_256
269418
```
270419

271420
### `eql_v2.ste_vec()`
@@ -290,6 +439,7 @@ Returns all encrypted elements matching a selector.
290439
```sql
291440
eql_v2.jsonb_path_query(val eql_v2_encrypted, selector text) RETURNS SETOF eql_v2_encrypted
292441
eql_v2.jsonb_path_query(val eql_v2_encrypted, selector eql_v2_encrypted) RETURNS SETOF eql_v2_encrypted
442+
eql_v2.jsonb_path_query(val jsonb, selector text) RETURNS SETOF eql_v2_encrypted
293443
```
294444

295445
**Example:**
@@ -304,6 +454,7 @@ Returns the first encrypted element matching a selector.
304454
```sql
305455
eql_v2.jsonb_path_query_first(val eql_v2_encrypted, selector text) RETURNS eql_v2_encrypted
306456
eql_v2.jsonb_path_query_first(val eql_v2_encrypted, selector eql_v2_encrypted) RETURNS eql_v2_encrypted
457+
eql_v2.jsonb_path_query_first(val jsonb, selector text) RETURNS eql_v2_encrypted
307458
```
308459

309460
### `eql_v2.jsonb_path_exists()`
@@ -313,6 +464,7 @@ Checks if any element matches a selector.
313464
```sql
314465
eql_v2.jsonb_path_exists(val eql_v2_encrypted, selector text) RETURNS boolean
315466
eql_v2.jsonb_path_exists(val eql_v2_encrypted, selector eql_v2_encrypted) RETURNS boolean
467+
eql_v2.jsonb_path_exists(val jsonb, selector text) RETURNS boolean
316468
```
317469

318470
**Example:**
@@ -333,6 +485,7 @@ Returns the length of an encrypted array.
333485

334486
```sql
335487
eql_v2.jsonb_array_length(val eql_v2_encrypted) RETURNS integer
488+
eql_v2.jsonb_array_length(val jsonb) RETURNS integer
336489
```
337490

338491
**Example:**
@@ -346,6 +499,7 @@ Returns each array element as an encrypted value.
346499

347500
```sql
348501
eql_v2.jsonb_array_elements(val eql_v2_encrypted) RETURNS SETOF eql_v2_encrypted
502+
eql_v2.jsonb_array_elements(val jsonb) RETURNS SETOF eql_v2_encrypted
349503
```
350504

351505
**Example:**
@@ -361,6 +515,7 @@ Returns each array element's ciphertext as text.
361515

362516
```sql
363517
eql_v2.jsonb_array_elements_text(val eql_v2_encrypted) RETURNS SETOF text
518+
eql_v2.jsonb_array_elements_text(val jsonb) RETURNS SETOF text
364519
```
365520

366521
---
@@ -481,6 +636,106 @@ FROM products
481636
GROUP BY eql_v2.jsonb_path_query_first(encrypted_json, 'color_selector');
482637
```
483638

639+
### `eql_v2.min()`
640+
641+
Returns the minimum encrypted value in a set (requires `ore` index for ordering).
642+
643+
```sql
644+
eql_v2.min(eql_v2_encrypted) RETURNS eql_v2_encrypted
645+
```
646+
647+
**Example:**
648+
```sql
649+
SELECT eql_v2.min(encrypted_date) FROM events;
650+
SELECT eql_v2.min(encrypted_price) FROM products WHERE category = 'electronics';
651+
```
652+
653+
### `eql_v2.max()`
654+
655+
Returns the maximum encrypted value in a set (requires `ore` index for ordering).
656+
657+
```sql
658+
eql_v2.max(eql_v2_encrypted) RETURNS eql_v2_encrypted
659+
```
660+
661+
**Example:**
662+
```sql
663+
SELECT eql_v2.max(encrypted_date) FROM events;
664+
SELECT eql_v2.max(encrypted_price) FROM products WHERE category = 'electronics';
665+
```
666+
667+
---
668+
669+
## Utility Functions
670+
671+
### `eql_v2.version()`
672+
673+
Get the installed EQL version.
674+
675+
```sql
676+
eql_v2.version() RETURNS text
677+
```
678+
679+
**Example:**
680+
```sql
681+
SELECT eql_v2.version();
682+
-- Returns: '2.1.8'
683+
```
684+
685+
### `eql_v2.to_encrypted()`
686+
687+
Convert jsonb or text to eql_v2_encrypted type.
688+
689+
```sql
690+
eql_v2.to_encrypted(data jsonb) RETURNS eql_v2_encrypted
691+
eql_v2.to_encrypted(data text) RETURNS eql_v2_encrypted
692+
```
693+
694+
**Example:**
695+
```sql
696+
-- Convert jsonb payload to encrypted type
697+
SELECT eql_v2.to_encrypted('{"v":2,"k":"pt","p":"plaintext"}'::jsonb);
698+
699+
-- Convert text payload to encrypted type
700+
SELECT eql_v2.to_encrypted('{"v":2,"k":"pt","p":"plaintext"}');
701+
```
702+
703+
### `eql_v2.to_jsonb()`
704+
705+
Convert eql_v2_encrypted to jsonb.
706+
707+
```sql
708+
eql_v2.to_jsonb(e eql_v2_encrypted) RETURNS jsonb
709+
```
710+
711+
**Example:**
712+
```sql
713+
SELECT eql_v2.to_jsonb(encrypted_column) FROM users;
714+
```
715+
716+
### `eql_v2.check_encrypted()`
717+
718+
Validate encrypted payload structure (used in constraints).
719+
720+
```sql
721+
eql_v2.check_encrypted(val jsonb) RETURNS boolean
722+
eql_v2.check_encrypted(val eql_v2_encrypted) RETURNS boolean
723+
```
724+
725+
**Description:**
726+
- Validates that encrypted value has required fields (`v`, `k`, `i`)
727+
- Returns true if valid, false otherwise
728+
- Automatically added as constraint when using `eql_v2.add_column()`
729+
730+
**Example:**
731+
```sql
732+
SELECT eql_v2.check_encrypted('{"v":2,"k":"pt","p":"test","i":{"t":"users","c":"email"}}'::jsonb);
733+
-- Returns: true
734+
735+
SELECT eql_v2.check_encrypted('{"invalid":"structure"}'::jsonb);
736+
-- Returns: false
737+
```
738+
484739
---
485740

486741
## See Also

docs/reference/index-config.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,16 @@ Try to ensure that the string you search for is at least as long as the `tokenLe
105105

106106
An ste_vec index on a encrypted JSONB column enables the use of PostgreSQL's `@>` and `<@` [containment operators](https://www.postgresql.org/docs/16/functions-json.html#FUNCTIONS-JSONB-OP-TABLE).
107107

108-
An ste_vec index requires one piece of configuration: the `context` (a string) which is passed as an info string to a MAC (Message Authenticated Code).
109-
This ensures that all of the encrypted values are unique to that context.
110-
We recommend that you use the table and column name as a the context (e.g. `users/name`).
108+
An ste_vec index requires one piece of configuration: the `prefix` (a string) which is passed as an info string to a MAC (Message Authenticated Code).
109+
This ensures that all of the encrypted values are unique to that prefix.
110+
We recommend that you use the table and column name as the prefix (e.g. `users/name`).
111111

112-
Within a dataset, encrypted columns indexed using an `ste_vec` that use different contexts can't be compared.
112+
**Example:**
113+
```json
114+
{"prefix": "users/encrypted_json"}
115+
```
116+
117+
Within a dataset, encrypted columns indexed using an `ste_vec` that use different prefixes can't be compared.
113118
Containment queries that manage to mix index terms from multiple columns will never return a positive result.
114119
This is by design.
115120

0 commit comments

Comments
 (0)