|
67 | 67 | //! seals and which it opens to (checked by kind, both ways), and nothing |
68 | 68 | //! about the bytes: declaring a type on a field written without one changes |
69 | 69 | //! no leaf. A field with any index declares its type, and a plan whose |
70 | | -//! indexed field has none is refused when it is built: the term then derives |
| 70 | +//! indexed field has none is refused when it is built |
| 71 | +//! ([`Error::UntypedIndex`], naming the field): the term then derives |
71 | 72 | //! from the one declared kind, every value checked against it, never from |
72 | 73 | //! whatever tag each value arrived with (`34` sent once as a float and once |
73 | 74 | //! as an integer would otherwise store two terms under one field). A field |
@@ -207,12 +208,15 @@ enum Verb { |
207 | 208 | /// One field of a record plan: what to call it, what label to seal it |
208 | 209 | /// under, what to produce for it, and, optionally, what type its values are. |
209 | 210 | /// |
210 | | -/// A field with a declared type (a [`ValueKind`]) admits only the indexes |
211 | | -/// that kind is defined for ([`admits`], checked when the plan is built), |
212 | | -/// seals only values of that kind and opens only to one (checked per value), |
213 | | -/// so the engine verifies what a binding hands it rather than trusting the |
214 | | -/// binding's tagging. A field with no declared type is dispatched on each |
215 | | -/// value's own type; see the [module docs](self#what-a-fields-type-decides). |
| 211 | +/// A field may declare the type of its values (a [`ValueKind`]), and must |
| 212 | +/// when it has a term output: [`Plan::new_with`] refuses the plan otherwise |
| 213 | +/// ([`Error::UntypedIndex`]). A typed field admits only the indexes that |
| 214 | +/// kind is defined for ([`admits`], checked when the plan is built), seals |
| 215 | +/// only values of that kind and opens only to one (checked per value), so |
| 216 | +/// the engine verifies what a binding hands it rather than trusting the |
| 217 | +/// binding's tagging. A field that only seals, or only carries its value |
| 218 | +/// through, may leave the type out; see the |
| 219 | +/// [module docs](self#what-a-fields-type-decides-and-what-it-does-not). |
216 | 220 | #[derive(Clone, Debug)] |
217 | 221 | pub struct FieldPlan { |
218 | 222 | name: String, |
@@ -512,7 +516,10 @@ impl Plan { |
512 | 516 | /// fields whose labels sit under different contexts or carry different |
513 | 517 | /// extensions, or does not build as a fields plan: two sealed or indexed |
514 | 518 | /// fields keyed under one identity, for instance, whose terms would be |
515 | | - /// interchangeable. [`Error::Target`] if a target field names a type the |
| 519 | + /// interchangeable. [`Error::UntypedIndex`], naming the field, if a field |
| 520 | + /// with a term output declares no type: this is where that rule is |
| 521 | + /// enforced, for a parsed and a hand-built plan alike. |
| 522 | + /// [`Error::Target`] if a target field names a type the |
516 | 523 | /// resolver does not know or cannot produce, declares a `"type"` other |
517 | 524 | /// than the kind that type is produced from, or sits in an extended plan. |
518 | 525 | pub fn new_with( |
@@ -741,7 +748,8 @@ pub fn plan(value: FfiValue) -> Result<Plan, Error> { |
741 | 748 | /// binding is never trusted to have tagged each value alike (a `34` sent once |
742 | 749 | /// as a `Float64` and once as an `Int64` would store two terms under one |
743 | 750 | /// field). A field with term outputs and no `"type"` is refused when the plan |
744 | | -/// is built. It is optional on a field whose only output is `"c"` or |
| 751 | +/// is built ([`Error::UntypedIndex`], naming the field). It is optional on a |
| 752 | +/// field whose only output is `"c"` or |
745 | 753 | /// `"passthrough"`, and on a target field, whose kind is the EQL type's own. |
746 | 754 | /// Declared, it is checked against the field's outputs here ([`admits`]) and |
747 | 755 | /// decides nothing about the bytes (see the |
@@ -800,10 +808,11 @@ pub fn plan(value: FfiValue) -> Result<Plan, Error> { |
800 | 808 | /// is empty, names an output key twice or names `"passthrough"` beside |
801 | 809 | /// another output, a `"target"` that is not a non-empty string, a `"type"` |
802 | 810 | /// that is not a string naming a [`ValueKind`], a type that does not admit |
803 | | -/// one of the field's index outputs, a field with a term output and no |
804 | | -/// `"type"`, a context that is not a label of at |
| 811 | +/// one of the field's index outputs, a context that is not a label of at |
805 | 812 | /// least two segments (optionally extended), fields under different |
806 | 813 | /// contexts or extensions, or a plan the builder refuses ([`Plan::new`]). |
| 814 | +/// [`Error::UntypedIndex`], naming the field, for a field with a term |
| 815 | +/// output and no `"type"`. |
807 | 816 | /// [`Error::Context`] for a `"context"` that is present but is not a |
808 | 817 | /// context at all, or renders empty. [`Error::Target`] for a target the |
809 | 818 | /// resolver refuses ([`Plan::new_with`]). |
@@ -884,8 +893,8 @@ pub fn plan_with( |
884 | 893 | /// index nothing. |
885 | 894 | /// |
886 | 895 | /// The source is checked and converted here, with no cipher: that is |
887 | | -/// [`check_source`], and it is where [`Error::Source`] and [`Error::Term`] |
888 | | -/// come from. What comes back is the plan's [`Pending`], with every term |
| 896 | +/// [`check_source`], and it is where [`Error::Source`] comes from. What |
| 897 | +/// comes back is the plan's [`Pending`], with every term |
889 | 898 | /// derived and every key request queued and nothing sent: one batched |
890 | 899 | /// `generate_keys` for every ciphertext leaf of every row when it is |
891 | 900 | /// awaited, however many rows and fields there are. Its failure is the |
@@ -947,8 +956,11 @@ pub fn plan_with( |
947 | 956 | /// |
948 | 957 | /// # Errors |
949 | 958 | /// |
950 | | -/// [`Error::Source`] if the source does not fit the plan; [`Error::Term`] |
951 | | -/// if a value has no term the plan asks for. Both are decided here, before |
| 959 | +/// [`Error::Source`] if the source does not fit the plan — a row that is |
| 960 | +/// not an object, a field the plan does not name or one it names that the |
| 961 | +/// row lacks, or a value of another kind than its field declares, which is |
| 962 | +/// how a value no term is defined for is refused: every indexed field |
| 963 | +/// declares its kind and the kind check comes first. Decided here, before |
952 | 964 | /// the pending exists. A failure of the pending itself is the engine's. |
953 | 965 | /// |
954 | 966 | /// A plan with a target field needs the resolver that built it: |
|
0 commit comments