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
{{ message }}
Repository navigation
Commit c6e3af1
Browse filesBrowse the repository at this point in the historyBrowse files
`eql-bindings` (the Rust crate released with this package): an EQL v4 type whose terms a null has, a storage-only type (`Date`, `Integer`, `Text`, ...) or one whose only term is equality's (`DateEq`, `IntegerEq`, `TextEq`, ...), now also implements `EncryptFrom` and `DecryptInto` for an `Option` of its plaintext, and its query twin `EncryptFrom` for one. For a type of fixed width a `None` seals as a typed null as long as a value (vitaminc 0.8), so an optional column does not show which rows are absent. For text it seals as a null that is not padded, since text's ciphertext is as long as the text, so its length may show that the value is absent. Either way it opens as `None`; its `hm` is the one term every null shares, and the query of a `None` finds the stored nulls with `=`. A value seals exactly as before. The by-name dispatch (`encryption::targets`) reads, opens and queries these types through the `Option`; a type with an order or match term still refuses a null. eql-bindings' own `Date`, `Timestamp` and `Decimal` plaintexts declare their fixed width to vitaminc, so their `None` is padded too. The SQL bundle and the TypeScript types do not change.
Copy file name to clipboardExpand all lines: languages/golang/cmd/stashgen/README.md
+23-2Lines changed: 23 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -79,6 +79,7 @@ The first part of a tag is the field's name, which is the column name in a datab
79
79
|`stash:"tenant,context_field"`| the field's value is the context of every other field in the struct, in place of a `context=` tag; stored as it is |
80
80
|`stash:"-"`| leave the field out |
81
81
|`` _ struct{} `stash:"context=documents,opaque"` ``| seal the struct as one value |
82
+
|`stash:"born,encrypt_into=DateEq,null=sql"`| on a field declared over a pointer (`*encrypt.Date`): how it stores `nil`, `null=sealed` or `null=sql`; see "Optional fields" |
82
83
83
84
A struct has one context: either a `_ struct{}` field with `context=`, or one field with `context_field`, not both.
84
85
A `context_field` is a `string` whose value is a label such as `"tenants/acme"`, segments separated by `/`.
@@ -109,6 +110,26 @@ These words are the same as the Rust API's words for the same behaviour, with tw
109
110
`opaque` seals the whole struct as one `bytes` field holding a JSON document (see "What crosses the binding").
110
111
`json` names the JSON index, which the Rust API does not declare yet; this build refuses it.
111
112
113
+
### Optional fields
114
+
115
+
A sealed field declared over a pointer to one scalar (`*encrypt.Date`, `*int32`, `*string`, a pointer to a type defined over a scalar) is optional: `nil` is a value it may hold, and `Decrypt` gives it back as `nil`.
116
+
`null=` says how the field stores `nil`. There are two ways, and they differ in what a reader of the database can see:
117
+
118
+
|`null=`| Stored for `nil`| What a reader of the column sees |
119
+
|---|---|---|
120
+
|`sealed`| a sealed null, as long as a sealed value of the field's type, and beside an equality index the one term every null of the field shares | nothing in the ciphertext; in an equality column, that the absent rows are one group, as rows holding one repeated value are |
121
+
|`sql`| nothing: the field's columns are `NULL`, and its member in the generated type is `nil`| which rows have no value |
122
+
123
+
A sealed null hides that the value is absent only where its length matches a value's and no index beside it shows it, so it is the default for a field whose type has a fixed width (a `bool`, a number, `encrypt.Date`, `time.Time`, `encrypt.Decimal`, `encrypt.Int128` and `encrypt.Uint128`) and whose only index, if it has one, is `equality`: sealed with `encrypt`, `encrypt,index=equality`, or into an EQL type with no index or with equality alone (`Date`, `DateEq`, `Integer`, `IntegerEq`, ...).
124
+
A null has an equality term, so its rows are one equality group and a query finds them: the generated `EqNull` derives the `eq` query of `nil`, which matches every row whose value is absent.
125
+
A `null=sealed` field's entry in the generated `Fields` value also has `EncryptNull`, which seals `nil` for an update of that one column: a sealed null is a value, so set the column to what it returns, not to SQL `NULL`.
126
+
A null has no order or match term, so a field with any other index, and a field of text or bytes, has to write `null=sql`: an order or match column would show which values are absent, and text shows its length, and `stashgen` will not choose a visible `NULL` for you.
127
+
`null=sealed` on such a field stops `stashgen` with the reason.
128
+
129
+
A `null=sql` field's member in the generated type is a pointer (`*eql.DateEq`, `*EncryptedUserScore`), `nil` when the value was; a `null=sealed` field's is the same type as a non-optional field's, and its column is never `NULL`.
130
+
A stored null read into a field that is not a pointer is an error from `Decrypt`, naming the field, never a zero value.
131
+
`-model` does not map a `null=sql` field yet, and `stashgen` stops if it is asked to.
132
+
112
133
An embedded struct of your own adds its tagged fields to the outer struct.
113
134
An embedded struct from another package takes one tag for all of its fields: `stash:",passthrough"` stores them as they are, and `stash:"-"` leaves them out.
114
135
Tags for other libraries, such as `gorm`, `db` and `json`, are copied to the same field of the generated type.
@@ -254,10 +275,10 @@ Generated code sends the engine every sealed field with its value, under the dec
254
275
A passthrough field stays on the host: the engine does nothing to it a program could observe, and the FFI codec cannot carry every Go type a program stores beside a ciphertext (a `driver.Valuer`, a `sql.NullTime`).
255
276
An `opaque` struct crosses as one JSON document and is one column, decoded back into the exact Go types the struct declares; a field may be any type `encoding/json` carries both ways (a scalar or a type defined over one, `[]byte`, slices, maps with string or integer keys, pointers, structs whose fields are all exported, `time.Time`).
256
277
A float in an opaque struct must be finite: `encoding/json` refuses NaN and the infinities, so `Encrypt` fails for the batch with `encrypt.ErrEncoding`. A sealed float field outside an opaque struct carries them.
257
-
A sealed field outside an opaque struct is one scalar, or a type defined over one; a struct, slice or map field seals only inside an opaque struct.
278
+
A sealed field outside an opaque struct is one scalar, a type defined over one, or a pointer to either (see "Optional fields"); a struct, slice or map field seals only inside an opaque struct.
258
279
The scalars are `string`, `[]byte`, `bool`, every integer type (each sealed at its own width, `int` and `uint` as 64-bit), `encrypt.Int128` and `encrypt.Uint128`, `float32`, `float64`, `encrypt.Decimal`, `encrypt.Date` and `time.Time` (a timestamp). The wire type `stashgen` writes for each is the field's own: `int8` is `gensupport.Int8`, `time.Time` is `gensupport.Timestamp`, and so on.
259
280
An order index (`ore`, `ope`) on a decimal, date or timestamp is refused: those order terms are not supported yet (#1236).
260
-
The zero `encrypt.Date` is not a date: a date field must be set, and `Encrypt` refuses a zero one with `encrypt.ErrEncoding`, naming the field. A sealed field cannot be a pointer (`*encrypt.Date`is refused as a composite), so an optional date has no sealed form yet: keep it in an opaque struct, or store a sentinel date.
281
+
The zero `encrypt.Date` is not a date: a date field must be set, and `Encrypt` refuses a zero one with `encrypt.ErrEncoding`, naming the field. An optional date is a `*encrypt.Date`field (see "Optional fields").
261
282
A nil `[]byte` in a sealed field, or a nil slice of a type defined over `[]byte`, comes back from `Decrypt` as an empty, non-nil slice; inside an opaque struct, nil comes back as nil.
262
283
A protobuf message with a `oneof` cannot be generated from a policy: protoc-gen-go puts its members in wrapper types, not in the message struct, and `Generate` refuses it.
returnOutput{}, fmt.Errorf("%w: gensupport: %s: EncryptNull seals nil only for a field that stores it as a sealed null (null=sealed)", encrypt.ErrEncoding, f.name)
71
+
}
72
+
returnf.seal(ctx, c, "EncryptNull", nil)
73
+
}
74
+
75
+
// seal seals one value of the field, or nil, through the field's own plan.
0 commit comments