You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: DEVELOPMENT.md
+95-78Lines changed: 95 additions & 78 deletions
Original file line number
Diff line number
Diff line change
@@ -8,6 +8,17 @@
8
8
-[Testing](#testing)
9
9
-[Running tests locally](#running-tests-locally)
10
10
-[Releasing](#releasing)
11
+
-[Building](#building)
12
+
-[Dependencies](#dependencies)
13
+
-[Building a release locally](#building-a-release-locally)
14
+
-[Structure](#structure)
15
+
-[Schema](#schema)
16
+
-[Types](#types)
17
+
-[Encrypted column type](#encrypted-column-type)
18
+
-[Encrypted index term types](#encrypted-index-term-types)
19
+
-[Operators](#operators)
20
+
-[Working without operators](#working-without-operators)
21
+
-[Configuration table](#configuration-table)
11
22
12
23
### How this project is organised
13
24
@@ -25,16 +36,43 @@ These are the important files in the repo:
25
36
.
26
37
├── mise.toml <-- the main config file for mise
27
38
├── tasks/ <-- mise tasks
28
-
├── sql/ <-- The individual SQL components that make up EQL
39
+
├── src/ <-- The individual SQL components that make up EQL
40
+
│ ├── encrypted/ <-- Encrypted column type
41
+
│ ├── operators/ <-- Operators for the encrypted column type
42
+
│ ├── match/ <-- match index term type
43
+
│ ├── unique/ <-- unique index term type
44
+
│ ├── ore/ <-- ore index term type
45
+
│ ├── ore-cllw/ <-- ore-cllw index term type
46
+
│ ├── config/ <-- Configuration management for encrypted columns
47
+
│ ├── schema.sql <-- Defines the PostgreSQL schema for namespacing EQL
48
+
│ ├── crypto.sql <-- Installs pg_crypto extension, required by ORE
49
+
│ ├── common.sql <-- Shared helper functions
50
+
│ └── version.sql <-- Defines function to query current EQL version - automatically generated on build
29
51
├── docs/ <-- Tutorial, reference, and concept documentation
30
52
├── tests/ <-- Unit and integration tests
31
53
│ ├── docker-compose.yml <-- Docker configuration for running PostgreSQL instances
32
-
│ └── *.sql <-- Individual unit and integration tests
54
+
│ └── *.sql <-- Helpers and test data loaded during test runs
33
55
├── release/ <-- Build artifacts produced by the `build` task
34
56
├── examples/ <-- Example uses of EQL in different languages
35
57
└── playground/ <-- Playground enviroment for experimenting with EQL and CipherStash Proxy
36
58
```
37
59
60
+
Tests live alongside the individual SQL files, with a filename ending with `_test.sql`
61
+
62
+
We break SQL into small modules named after what they do.
63
+
64
+
In general, operator functions are thin wrappers around larger functions that do the actual work.
65
+
Put the wrapper functions in `operators.sql` and the larger functions in `functions.sql`.
66
+
67
+
Dependencies between SQL in `src/` are declared in a comment at the top of each file.
68
+
All SQL files should `REQUIRE` the source file of any other object they reference.
69
+
70
+
All files must have at least one declaration, and the default is to reference the schema:
71
+
72
+
```
73
+
-- REQUIRE: src/schema.sql
74
+
```
75
+
38
76
## Set up a local development environment
39
77
40
78
> [!IMPORTANT]
@@ -123,7 +161,7 @@ stateDiagram-v2
123
161
state "🧍 Human makes changes to EQL sources" as changes
124
162
state sources_fork <<fork>>
125
163
state sources_join <<join>>
126
-
state "sql/*.sql" as source_sql
164
+
state "src/*.sql" as source_sql
127
165
state "tasks/**/*" as source_tasks
128
166
state "tests/**/*" as source_tests
129
167
state sources_changed <<choice>>
@@ -235,118 +273,97 @@ To cut a [release](https://github.com/cipherstash/encrypt-query-language/release
235
273
236
274
This will trigger the [Release EQL](https://github.com/cipherstash/encrypt-query-language/actions/workflows/release-eql.yml) workflow, which will build and attach artifacts to [the release](https://github.com/cipherstash/encrypt-query-language/releases/).
237
275
276
+
## Building
238
277
239
-
====
240
-
241
-
242
-
###
243
-
244
-
EQL is installed into the `eql_v1` schema.
245
-
246
-
247
-
## Types
248
-
249
-
### `public.eql_v1_encrypted`
250
-
251
-
Core column type, defined as PostgreSQL composite type.
252
-
In public schema as once used in customer tables it cannot be dropped without dropping data.
253
-
254
-
### Index terms
255
-
256
-
Each type of encrypted indexing has an associated type and functions
257
-
258
-
-`eql_v1.unique_index`
259
-
-`eql_v1.match`
260
-
-`eql_v1.ore_64_8_v1`
261
-
-`eql_v1.ore_64_8_v1_term`
278
+
### Dependencies
262
279
280
+
SQL sources are split into smaller files in `src/`.
281
+
Dependencies are resolved at build time to construct a single SQL file with the correct ordering.
263
282
264
-
##Operators
283
+
### Building a release locally
265
284
266
-
Operators are provided for the `eql_v1_encrypted` column type and `jsonb`.
285
+
To build a release locally, run:
267
286
268
-
```
269
-
eql_v1_encrypted - eql_v1_encrypted
270
-
jsonb - eql_v1_encrypted
271
-
eql_v1_encrypted - jsonb
287
+
```bash
288
+
mise run build
272
289
```
273
290
274
-
The index types and functions are internal implementation details and should not need to be exposed as operators on the `eql_v1_encrypted` type.
291
+
This produces two SQL files in `releases/`:
275
292
293
+
- An installer (`cipherstash-encrypt.sql`), and
294
+
- An uninstaller (`cipherstash-encrypt-uninstall.sql`)
276
295
277
-
-- eql_v1_encrypted = eql_v1_encrypted
278
-
-- eql_v1_encrypted = jsonb
279
-
-- jsonb = eql_v1_encrypted
280
-
-- ore_64_8_v1 = ore_64_8_v1
296
+
## Structure
281
297
282
-
The jsonb comparison is handy as it automates casting.
283
-
Comparing ore_64_8_v1 index values requires that sides are functionalated:
284
-
eql_v1.ore_64_8_v1(...) = eql_v1.ore_64_8_v1(...)
285
-
In the spirit of aggressive simplification, however, I am not going to add operators to compare eql_v1_encrypted with the ore_64_8_v1 type.
286
-
In an operator world, the index types and functions are internal implementation details.
287
-
Customers should never need to think about the internals.
288
-
I can't think of a reason to need it that isn't a version of "holding it wrong". (edited)
298
+
### Schema
289
299
300
+
EQL is installed into the `eql_v1` PostgreSQL schema.
290
301
302
+
### Types
291
303
304
+
#### Encrypted column type
292
305
293
-
## Working without operators
306
+
`public.eql_v1_encrypted` is EQL's encrypted column type, defined as PostgreSQL composite type.
294
307
308
+
This column type is used for storing the encrypted value and any associated indexes for searching.
309
+
The associated indexes are described in the [index term types](#index-term-types) section.
295
310
296
-
### Equality
311
+
`public.eql_v1_encrypted` is in the public schema, because once it's used by a user in one of their tables, encrypted column types cannot be dropped without dropping data.
297
312
298
-
```sql
299
-
eql_v1.eq(a eql_v1_encrypted, b eql_v1_encrypted);
300
-
```
313
+
#### Encrypted index term types
301
314
315
+
Each type of encrypted index (`unique`, `match`, `ore`) has an associated type, functions, and operators.
302
316
317
+
These are transient runtime types, used internally by EQL functions and operators:
303
318
319
+
-`eql_v1.unique_index`
320
+
-`eql_v1.match`
321
+
-`eql_v1.ore_64_8_v1`
322
+
-`eql_v1.ore_64_8_v1_term`
304
323
324
+
The data in the column is converted into these types, when any operations are being performed on that encrypted data.
305
325
306
-
##Organisation
326
+
### Operators
307
327
308
-
Break SQL into small modules, aligned with the core domains and types where possible
328
+
Searchable encryption functionality is driven by operators on two types:
309
329
310
-
- types.sql
311
-
- casts.sql
312
-
- constraints.sql
313
-
- functions.sql
314
-
- operators.sql
330
+
- EQL's `eql_v1_encrypted` column type
331
+
- PostgreSQL's `jsonb` column type
315
332
316
-
Operators are also functions, so some judgement is required.
317
-
The intent is to reduce file size and cognitive load.
333
+
For convenience, operators allow comparisons between `eql_v1_encrypted` and `jsonb` column types.
318
334
319
-
In general, operator functions should be thin wrappers around a larger function that does the work.
320
-
Put the wrapper functions in `operators.sql` and the "heavy lifting" functions in `functions.sql`.
335
+
Operators allow comparisons between:
321
336
322
-
Tests should follow a similar pattern.
337
+
-`eql_v1_encrypted` and `eql_v1_encrypted`
338
+
-`jsonb` and `eql_v1_encrypted`
339
+
-`eql_v1_encrypted` and `jsonb`
323
340
341
+
The index types and functions are internal implementation details and should not be exposed as operators on the `eql_v1_encrypted` type.
342
+
For example, `eql_v1_encrypted` should not have an operator with the `ore_64_8_v1` type.
343
+
Users should never need to think about or interact with EQL internals.
324
344
345
+
#### Working without operators
325
346
326
-
### Dependencies
347
+
There are scenarios where users are unable to install EQL operators in your database.
348
+
Users will experience this in more restrictive environments like Supabase.
327
349
328
-
SQL sources are split into smaller files.
329
-
Dependencies are resolved at build time to construct a single SQL file with the correct ordering.
330
-
331
-
Dependencies between files are declared in a comment at the top of the file.
332
-
All SQL files should `REQUIRE` the source file of any other object they reference.
350
+
EQL can still be used, but requires the use of functions instead of operators.
333
351
334
-
All files must have at least one declaration, and the default is to reference the schema
352
+
For example, to perform an equality query:
335
353
336
-
```
337
-
-- REQUIRE: src/schema.sql
354
+
```sql
355
+
SELECT email FROM users WHEREeql_v1.eq(email, $1);
338
356
```
339
357
358
+
### Configuration table
340
359
360
+
EQL uses a table for tracking configuration state in the database, called `public.eql_v1_configuration`.
341
361
342
-
### Tables
343
-
344
-
### Configuration
345
-
346
-
347
-
`public.eql_v1_configuration`
348
-
362
+
This table should never be dropped, except by a user explicitly uninstalling EQL.
349
363
364
+
<!--
365
+
TODO(toby): probably move to README
366
+
TODO(toby): include examples of how to get data out of the table
350
367
351
368
EQL Design Note
352
369
Experimenting with using a Composite type instead of a Domain type for the encrypted column.
@@ -363,4 +380,4 @@ Already built cast helpers so syntax is something like
0 commit comments