Encode a `nodedb_types::Value` as a Binary Tuple according to the schema.
(value: &Value, schema: &StrictSchema)
| 22 | |
| 23 | /// Encode a `nodedb_types::Value` as a Binary Tuple according to the schema. |
| 24 | pub fn value_to_binary_tuple(value: &Value, schema: &StrictSchema) -> crate::Result<Vec<u8>> { |
| 25 | let map = match value { |
| 26 | Value::Object(m) => m, |
| 27 | _ => { |
| 28 | return Err(crate::Error::BadRequest { |
| 29 | detail: "strict value must be an Object".to_string(), |
| 30 | }); |
| 31 | } |
| 32 | }; |
| 33 | |
| 34 | let schema_columns: std::collections::HashSet<&str> = |
| 35 | schema.columns.iter().map(|c| c.name.as_str()).collect(); |
| 36 | if let Some(unknown) = map.keys().find(|k| !schema_columns.contains(k.as_str())) { |
| 37 | return Err(crate::Error::BadRequest { |
| 38 | detail: format!("unknown field '{unknown}' not present in strict schema"), |
| 39 | }); |
| 40 | } |
| 41 | |
| 42 | let encoder = nodedb_strict::TupleEncoder::new(schema); |
| 43 | let mut values = Vec::with_capacity(schema.columns.len()); |
| 44 | |
| 45 | for col in &schema.columns { |
| 46 | let field_val = map.get(&col.name); |
| 47 | let typed = match field_val { |
| 48 | None | Some(Value::Null) => { |
| 49 | if !col.nullable { |
| 50 | return Err(crate::Error::BadRequest { |
| 51 | detail: format!("column '{}' is NOT NULL but no value provided", col.name), |
| 52 | }); |
| 53 | } |
| 54 | Value::Null |
| 55 | } |
| 56 | Some(v) => coerce_value(v, &col.column_type, &col.name)?, |
| 57 | }; |
| 58 | values.push(typed); |
| 59 | } |
| 60 | |
| 61 | encoder |
| 62 | .encode(&values) |
| 63 | .map_err(|e| crate::Error::BadRequest { |
| 64 | detail: format!("Binary Tuple encode: {e}"), |
| 65 | }) |
| 66 | } |
| 67 | |
| 68 | /// Bitemporal variant: decode msgpack to `Value`, then encode as a Binary |
| 69 | /// Tuple with reserved slots 0/1/2 populated from the supplied timestamps. |