Problem
row.try_get::<String, _>("struct_column") fails because STRUCT values arrive as
Kind::List (positional ListValue in protobuf), but FromValue for String
expects Kind::String. There is no FromValue impl that handles STRUCT or ARRAY
values natively.
This blocks all use cases that read STRUCT/ARRAY columns from Spanner query
results:
- Spanner change stream consumption (
READ_* TVF returns deeply nested
ARRAY<STRUCT<ARRAY<STRUCT<...>>>>)
- INFORMATION_SCHEMA queries returning complex column types
- Any application query on tables with STRUCT or ARRAY columns
Current workaround (painful, error-prone)
Users must manually walk the Value tree and reconstruct named fields
from type metadata:
// Read raw value (works because FromValue for Value just clones)
let raw = row.try_get::<Value, _>("struct_column")?;
// Manually iterate the ARRAY<STRUCT> value
let list = raw.try_as_list().ok_or(/* ... */)?;
for elem in list.iter() {
// STRUCT values arrive as positional ListValue on the wire.
// Field names exist only in Type metadata, not in the data payload.
// Users must reconstruct named access themselves:
if let Some(s) = elem.try_as_struct() {
let field_val = s.get("field_name").ok_or(/* ... */)?;
}
}
For positional STRUCTs (Spanner's wire format for change streams), users must
hardcode positional indices or manually walk model::Type.struct_type.fields to
reconstruct field names — a non-trivial recursive algorithm.
What already works
The entire public API surface needed for the implementation already exists:
| API |
Status |
Value::kind() |
✅ Public |
Value::try_as_list(), Value::try_as_struct() |
✅ Public |
Value::as_string(), Value::as_bool(), Value::try_as_f64() |
✅ Public |
Type::code() |
✅ Public |
Type::array_element_type() |
✅ Public |
Into<model::Type> for Type (accesses struct_type) |
✅ Public |
model::StructType and model::struct_type::Field |
✅ Public (constructable) |
serde_json dependency |
✅ Already in workspace & spanner crate |
No new public API methods are required. The implementation can use the
existing Into<model::Type> conversion to read struct_type.fields for
named-field reconstruction.
Related
array_element_type() is already public (types.rs:134) — struct_type() is the
last missing piece for complete type introspection, but not strictly required
since Into<model::Type> is available.
serde_json is already a dependency (workspace Cargo.toml:406, spanner
Cargo.toml:54).
Problem
row.try_get::<String, _>("struct_column")fails because STRUCT values arrive asKind::List(positionalListValuein protobuf), butFromValue for Stringexpects
Kind::String. There is noFromValueimpl that handles STRUCT or ARRAYvalues natively.
This blocks all use cases that read STRUCT/ARRAY columns from Spanner query
results:
READ_*TVF returns deeply nestedARRAY<STRUCT<ARRAY<STRUCT<...>>>>)Current workaround (painful, error-prone)
Users must manually walk the
Valuetree and reconstruct named fieldsfrom type metadata:
For positional STRUCTs (Spanner's wire format for change streams), users must
hardcode positional indices or manually walk
model::Type.struct_type.fieldstoreconstruct field names — a non-trivial recursive algorithm.
What already works
The entire public API surface needed for the implementation already exists:
Value::kind()Value::try_as_list(),Value::try_as_struct()Value::as_string(),Value::as_bool(),Value::try_as_f64()Type::code()Type::array_element_type()Into<model::Type>forType(accessesstruct_type)model::StructTypeandmodel::struct_type::Fieldserde_jsondependencyNo new public API methods are required. The implementation can use the
existing
Into<model::Type>conversion to readstruct_type.fieldsfornamed-field reconstruction.
Related
array_element_type()is already public (types.rs:134) —struct_type()is thelast missing piece for complete type introspection, but not strictly required
since
Into<model::Type>is available.serde_jsonis already a dependency (workspaceCargo.toml:406, spannerCargo.toml:54).