Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/eql-v4-ordered-ope-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@cipherstash/eql': minor
---

**Stack Encrypt produces the OPE-ordered EQL v4 types `IntegerOrd`, `BigintOrd`, `RealOrd`, `DoubleOrd`, `TextOrd` and their `OrdOpe` twins** (`eql-bindings`, `stack-encrypt` feature). Their `op` term orders by ADR-0002's order key, so `<`, `<=`, `>`, `>=` and `ORDER BY eql_v4.ord_term(col)` compare integers by value, floats as PostgreSQL's `float8` does and text by its fold (case and accents folded). `=` on text reads `TextEq`'s equality term. `TextSearch` stays unproducible, with a reason: its query carries a match term that short text cannot make.
6 changes: 6 additions & 0 deletions languages/golang/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ listed under **Breaking**. Releases are tagged `languages/golang/vX.Y.Z`.
`float32` or `float64` field tagged `encrypt_into=` one of them gets `Eq`.
`=` compares as PostgreSQL compares the plain types: an integer has one
term whatever its width, and for floats `-0.0 = 0.0` and `NaN = NaN`.
- **`IntegerOrd`, `BigintOrd`, `RealOrd`, `DoubleOrd`, `TextOrd` and their
`OrdOpe` twins**: a field tagged `encrypt_into=` one of them gets `Lt`,
`Lte`, `Gt` and `Gte`, and a text one `Eq` too. They store an OPE term
that orders by ADR-0002's order key: floats as PostgreSQL's `float8`
sorts them, text by its fold. No `Between` yet: it needs EQL v4's range
query domains.
- **Ordering methods on text.** A string field with `index=ore` or
`index=ope` gets `Lt`, `Lte`, `Gt`, `Gte` and `Between`. Text orders by its
folded form (ADR-0002: case and accents folded, under Unicode 16), so
Expand Down
13 changes: 7 additions & 6 deletions languages/golang/cmd/stashgen/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,14 +158,15 @@ The engine produces these EQL types today, each from one Go field type:

| `encrypt_into` | Go field |
|---|---|
| `TextEq`, `Text`, `TextMatch` | `string` |
| `Integer`, `IntegerEq` | `int32`, or any Go integer type |
| `Bigint`, `BigintEq` | `int64`, or any Go integer type |
| `TextEq`, `Text`, `TextMatch`, `TextOrd`, `TextOrdOpe` | `string` |
| `Integer`, `IntegerEq`, `IntegerOrd`, `IntegerOrdOpe` | `int32`, or any Go integer type |
| `Bigint`, `BigintEq`, `BigintOrd`, `BigintOrdOpe` | `int64`, or any Go integer type |
| `Boolean` | `bool` |
| `Real`, `RealEq` | `float32` |
| `Double`, `DoubleEq` | `float64` |
| `Real`, `RealEq`, `RealOrd`, `RealOrdOpe` | `float32` |
| `Double`, `DoubleEq`, `DoubleOrd`, `DoubleOrdOpe` | `float64` |

The `Eq` types answer `Eq`; `Text`, `Integer`, `Bigint`, `Boolean`, `Real` and `Double` are stored and read only, with no query method.
The `Eq` types answer `Eq`; the `Ord` and `OrdOpe` types answer `Lt`, `Lte`, `Gt` and `Gte`, and on text `Eq` too; `Text`, `Integer`, `Bigint`, `Boolean`, `Real` and `Double` are stored and read only, with no query method.
An ordered type has no `Between` method yet, because a `BETWEEN` operand needs EQL v4's range query domains.

Any built-in Go integer field takes an integer type (ADR-0002) and seals at the type's width: an `int16` field always fits an `Integer`, and an `int64` field is range checked value by value, `Encrypt` refusing a value that does not fit with `encrypt.ErrEncoding`. `encrypt.Int128` and `encrypt.Uint128` are not converted. A float's width must match: a `float64` field is not a `Real`.
A `TextMatch` field refuses text shorter than three characters, such as an empty string or a two-letter code, because it has no 3-grams to index; its query refuses such text too.
Expand Down
26 changes: 24 additions & 2 deletions languages/golang/encrypt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -448,16 +448,21 @@ The EQL types the engine produces, and the Go field types each takes:
|---|---|---|
| `TextEq` | `string` | `=`, `<>` |
| `TextMatch` | `string` | `@@` (substring match, 3-grams, case-insensitive) |
| `TextOrd`, `TextOrdOpe` | `string` | `=`, `<>`, `<`, `<=`, `>`, `>=`, `ORDER BY` |
| `Text` | `string` | none: stored and read only |
| `Integer` | `int32`, or any Go integer type (see below) | none |
| `IntegerEq` | the same | `=`, `<>` |
| `IntegerOrd`, `IntegerOrdOpe` | the same | `=`, `<>`, `<`, `<=`, `>`, `>=`, `ORDER BY` |
| `Bigint` | `int64`, or any Go integer type | none |
| `BigintEq` | the same | `=`, `<>` |
| `BigintOrd`, `BigintOrdOpe` | the same | `=`, `<>`, `<`, `<=`, `>`, `>=`, `ORDER BY` |
| `Boolean` | `bool` | none |
| `Real` | `float32` | none |
| `RealEq` | `float32` | `=`, `<>` |
| `RealOrd`, `RealOrdOpe` | `float32` | `=`, `<>`, `<`, `<=`, `>`, `>=`, `ORDER BY` |
| `Double` | `float64` | none |
| `DoubleEq` | `float64` | `=`, `<>` |
| `DoubleOrd`, `DoubleOrdOpe` | `float64` | `=`, `<>`, `<`, `<=`, `>`, `>=`, `ORDER BY` |

Any built-in Go integer field takes an integer EQL type (ADR-0002): the field
is sealed at the type's width, and opens back into the field's type. A type
Expand All @@ -472,8 +477,25 @@ A `TextMatch` value must be at least three characters long: shorter text has
no 3-grams to index and is refused. The number equality types compare as
PostgreSQL compares the plain types: an integer equals itself whatever its
width, and for floats `-0.0 = 0.0` and `NaN = NaN`; the stored value still
decrypts to exactly what was written. The rest of
the catalog (ordering, dates, decimals, JSON) is listed in
decrypts to exactly what was written.

The `Ord` and `OrdOpe` types store an OPE term, which EQL compares as bytes,
and order by ADR-0002's order key: integers by value, floats as PostgreSQL's
`float8` sorts them (`-0.0` ties `0.0`, every NaN is one value after
`+Infinity`), text by its fold (case and accents folded, under Unicode 16).
A field gets `Lt`, `Lte`, `Gt` and `Gte`, and a text field `Eq` too; sort
with `ORDER BY eql_v4.ord_term(col)`. `ord_term` returns a `bytea` domain, so
a plain functional btree index, `CREATE INDEX ON t (eql_v4.ord_term(col))`,
serves `<`, `>` and `ORDER BY` with no operator class. That is why these
types work on an install without superuser rights, where the ORE operator
class is skipped. On a number column SQL's `=` compares
the order term; stashgen writes no `Eq` method for one yet, since the engine
answers `Eq` through an equality term only. A text order type also stores
`TextEq`'s equality term, and `=` reads that, so `Café` and `cafe` are
neither `<` nor `>` each other and not `=` either. Text holding a code point
Unicode 16 does not assign has no order term and is refused. There is no
`Between` method yet: a `BETWEEN` needs EQL v4's range query domains. The rest of
the catalog (ORE ordering, dates, decimals, JSON) is listed in
`eql.Types` with the reason it is not produced yet, and `stashgen` refuses it
with that reason. The guest builds the value: the generated code
imports `encrypt/eql`, which embeds the build of the engine that holds the
Expand Down
6 changes: 4 additions & 2 deletions languages/golang/encrypt/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@
// also takes any other built-in Go integer type, sealed at the type's width:
// one every value of which fits it (an int16 into Integer) always seals, and
// a wider one (an int64 into Integer) is range checked, a value that does not
// fit refused with [ErrEncoding]. The *Eq types answer Eq; Integer, Bigint,
// Boolean, Real, Double and Text are stored and read only.
// fit refused with [ErrEncoding]. The *Eq types answer Eq; the *Ord and
// *OrdOpe types (IntegerOrd, BigintOrd, RealOrd, DoubleOrd, TextOrd and their
// OrdOpe twins) answer Lt, Lte, Gt and Gte, and Eq too on text; Integer,
// Bigint, Boolean, Real, Double and Text are stored and read only.
//
// 3. Run the generator. It writes user_stash.go beside the struct:
//
Expand Down
Loading
Loading