Field Selection
In addition to computing aggregates, we can also return fields selected directly from the rows themselves.
This is done by mapping over the computed rows, and using the eval_field
function to evaluate each selected field in turn:
let rows = query
.fields
.as_ref()
.map(|fields| {
let mut rows: Vec<IndexMap<models::FieldName, models::RowFieldValue>> = vec![];
for item in &paginated {
let row = eval_row(fields, collection_relationships, variables, state, item)?;
rows.push(row);
}
Ok(rows)
})
.transpose()?;
The eval_field
function works by pattern matching on the field type:
- A
column
is selected using theeval_column
function (oreval_nested_field
if there are nested fields to fetch) - A
relationship
field is selected by evaluating the related collection usingeval_path_element
(we will cover this in the next section), and then recursively executing a query usingexecute_query
:
fn eval_field(
collection_relationships: &BTreeMap<models::RelationshipName, models::Relationship>,
variables: &BTreeMap<models::VariableName, serde_json::Value>,
state: &AppState,
field: &models::Field,
item: &Row,
) -> Result<models::RowFieldValue> {
match field {
models::Field::Column {
column,
fields,
arguments,
} => {
let col_val = eval_column(variables, item, column, arguments)?;
match fields {
None => Ok(models::RowFieldValue(col_val)),
Some(nested_field) => eval_nested_field(
collection_relationships,
variables,
state,
col_val,
nested_field,
),
}
}
models::Field::Relationship {
relationship,
arguments,
query,
} => {
let relationship = collection_relationships.get(relationship).ok_or((
StatusCode::BAD_REQUEST,
Json(models::ErrorResponse {
message: " ".into(),
details: serde_json::Value::Null,
}),
))?;
let source = vec![item.clone()];
let collection = eval_path_element(
collection_relationships,
variables,
state,
relationship,
arguments,
&source,
&None,
)?;
let rows = execute_query(
collection_relationships,
variables,
state,
query,
Root::CurrentRow,
collection,
)?;
let rows_json = serde_json::to_value(rows).map_err(|_| {
(
StatusCode::INTERNAL_SERVER_ERROR,
Json(models::ErrorResponse {
message: "cannot encode rowset".into(),
details: serde_json::Value::Null,
}),
)
})?;
Ok(models::RowFieldValue(rows_json))
}
}
}