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
columnis selected using theeval_columnfunction (oreval_nested_fieldif there are nested fields to fetch) - A
relationshipfield 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: "relationship is undefined".into(),
details: serde_json::Value::Null,
}),
))?;
let source = vec![item.clone()];
let collection = eval_path_element(
collection_relationships,
variables,
state,
relationship,
arguments,
&source,
None,
&None,
)?;
let row_set = execute_query(
collection_relationships,
variables,
state,
query,
Root::Reset,
collection,
)?;
let row_set_json = serde_json::to_value(row_set).map_err(|_| {
(
StatusCode::INTERNAL_SERVER_ERROR,
Json(models::ErrorResponse {
message: "cannot encode rowset".into(),
details: serde_json::Value::Null,
}),
)
})?;
Ok(models::RowFieldValue(row_set_json))
}
}
}