From 53e5cca3a7dcc0744df398deffad90e655329f97 Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Tue, 13 Oct 2026 12:52:01 +1100 Subject: [PATCH] docs(golang): lead the encrypt quickstart with EQL v4 columns The encrypt README and package doc opened with the index= grammar (Ciphertext plus term byte columns, Fields.Email.Equality), while the stashgen README and the EQL v4 alpha setup guide use encrypt_into= and Fields.Email.Query. A reader starting from go doc wrote tags the guide does not describe, for a storage model it does not cover. Both quickstarts now declare encrypt_into fields, build the query with Query, and store each field as one eql_v4 column, with the install step and the query cast. The index= form stays documented and is named as the alternative; the example program still uses it, and the README now says so rather than calling it the eight steps. --- languages/golang/encrypt/README.md | 32 ++++++++++++++++++++---------- languages/golang/encrypt/doc.go | 26 +++++++++++++++++------- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/languages/golang/encrypt/README.md b/languages/golang/encrypt/README.md index 49daffc6c..26a3546ab 100644 --- a/languages/golang/encrypt/README.md +++ b/languages/golang/encrypt/README.md @@ -31,11 +31,15 @@ The package reference is on [pkg.go.dev]; the generator's reference is type User struct { _ struct{} `stash:"context=users"` ID int64 `stash:"id,passthrough"` - Email string `stash:"email,encrypt,index=equality;match"` - Age uint32 `stash:"age,encrypt,index=equality;ore"` + Email string `stash:"email,encrypt_into=TextEq"` + Name string `stash:"name,encrypt_into=TextMatch"` + Age int32 `stash:"age,encrypt_into=Integer"` } ``` + `encrypt_into=` names the EQL type the field is stored as. The Go field + type must match it; see [EQL columns](#eql-columns). + 3. Run the generator. It writes `user_stash.go` beside the struct. ```sh @@ -56,17 +60,25 @@ The package reference is on [pkg.go.dev]; the generator's reference is encrypted, err := users.Encrypt(ctx, cipher, people) opened, err := users.Decrypt(ctx, cipher, encrypted) - term, err := users.Fields.Email.Equality(ctx, cipher, "bob@example.com") + query, err := users.Fields.Email.Query(ctx, cipher, "bob@example.com") ``` `Encrypt` and `Decrypt` send one ZeroKMS request for each 500 sealed values in the batch, plus one request the first time a keyset is used. -6. Store the encrypted type. Each sealed field is one or more byte columns: - `e.Email.Ciphertext`, `e.Email.Equality`, `e.Email.Match`. `Ciphertext` - and each term type implement `driver.Valuer` and `sql.Scanner`, so a - database library binds and scans each column as bytes; map each one to - its own column. +6. Store the encrypted type. Each `encrypt_into` field is one EQL v4 column: + `eql.TextEq` implements `driver.Valuer` and `sql.Scanner`, so a database + library binds and scans it as the JSON a `public.eql_v4_text_eq` column + holds. Install EQL v4 into PostgreSQL first, with the + `eql-v4-install.sql` attached to the release. A query casts its parameter + to the column's query type: + + ```sql + SELECT id, email, name, age FROM users WHERE email = $1::eql_v4.query_text_eq + ``` + + A field tagged `encrypt` or `index=` stores its ciphertext and each term + as separate byte columns instead; see [What is stored](#what-is-stored). 7. Run the generator again after each change to the struct or to a tag. A change to the fields of the struct stops the build until you do. @@ -80,8 +92,8 @@ The package reference is on [pkg.go.dev]; the generator's reference is `git diff` sees only files git already tracks; the `git status` check also fails on a generated file that was never committed. -The rest of this file is the reference. [`example/`](example/) is the eight -steps as a program. +The rest of this file is the reference. [`example/`](example/) is a program +that stores separate byte columns (`index=`) against real ZeroKMS. ## Connect diff --git a/languages/golang/encrypt/doc.go b/languages/golang/encrypt/doc.go index 7b114f0e3..f29c861bf 100644 --- a/languages/golang/encrypt/doc.go +++ b/languages/golang/encrypt/doc.go @@ -15,10 +15,15 @@ // type User struct { // _ struct{} `stash:"context=users"` // ID int64 `stash:"id,passthrough"` -// Email string `stash:"email,encrypt,index=equality;match"` -// Age uint32 `stash:"age,encrypt,index=equality;ore"` +// Email string `stash:"email,encrypt_into=TextEq"` +// Name string `stash:"name,encrypt_into=TextMatch"` +// Age int32 `stash:"age,encrypt_into=Integer"` // } // +// encrypt_into names the EQL type the field is stored as. The Go field type +// must match it: TextEq, TextMatch and Text take a string, Integer an int32, +// Bigint an int64, Boolean a bool, Real a float32 and Double a float64. +// // 3. Run the generator. It writes user_stash.go beside the struct: // // go generate ./... @@ -35,15 +40,22 @@ // cipher := client.Keyset(encrypt.KeysetName("tenant-42")) // encrypted, err := users.Encrypt(ctx, cipher, people) // []users.EncryptedUser // opened, err := users.Decrypt(ctx, cipher, encrypted) // []users.User -// term, err := users.Fields.Email.Equality(ctx, cipher, "bob@example.com") +// query, err := users.Fields.Email.Query(ctx, cipher, "bob@example.com") // // Encrypt and Decrypt send one ZeroKMS request for each 500 sealed values in // the batch, plus one the first time a keyset is used. // -// 6. Store the encrypted type. Each sealed field is one or more columns of -// bytes ([Ciphertext] and the term types), each implementing driver.Valuer -// and sql.Scanner, so a database library binds and scans each one as bytes; -// map each one to its own column. +// 6. Store the encrypted type. Each encrypt_into field is one EQL v4 column +// (an eql.TextEq goes in a public.eql_v4_text_eq column), implementing +// driver.Valuer and sql.Scanner, so a database library binds and scans it +// like any other value. Install EQL v4 into PostgreSQL first, with the +// eql-v4-install.sql attached to the release. A query casts its parameter to +// the column's query type: +// +// SELECT id, email, name, age FROM users WHERE email = $1::eql_v4.query_text_eq +// +// A field tagged encrypt or index= stores its ciphertext ([Ciphertext]) and +// each term as separate byte columns instead; see Terms below. // // 7. Run the generator again after each change to the struct or to a tag. A // change to the fields of the struct stops the build until you do.