Alpha. Vary is under active development and not ready for production use. Syntax, APIs, performance, and behaviour may change between releases.

mapping

import mapping covers the one-line list-to-list translations that turn typed query rows into contract values or JSON arrays. The intent is to keep the row-to-response loop out of handlers so the response shape stays in one place: the json ... from ... mapping declaration.

Mapping typed rows

import mapping

let summaries = mapping.map_rows(rows, lambda row: IssueRow: issue_summary(row))

map_rows[Row, Out](rows, mapper) returns a List[Out] with one entry per input row. The contract assertion is "same length"; the mapper is expected to be total.

Mapping to JSON arrays

import mapping

let issues_json = mapping.json_array_map(rows, lambda row: IssueRow: row_to_json(row))
return api_response.ok_array("issues", issues_json)
HelperPurpose
json_array_map(rows, mapper)Maps to a Json array of objects.
json_string_array_map(rows, mapper)Maps to a Json array of strings.
json_object_fields(fields, values)Json object from parallel key and value lists.
json_parse_or_empty_object(text)Empty object on parse failure (tolerant decode).
json_parse_or_empty_array(text)Returns an empty array on parse failure.

Interaction with json ... from ...

The DSL form is preferred when the row-to-response shape is stable:

json issue_summary from IssueRow as row projected by public_field_policy {
    id: row.id
    title: row.title
    severity: row.severity
}

Reach for mapping in these situations:

SituationWhy the declarative form does not fit
Cross-row aggregation instead of per-row projectionjson ... projected by ... is row-local.
Gluing typed rows into api_response.ok_arrayThe envelope wants a List; mapping builds it.
Migrating from hand-rolled loopsBridge until shapes live in a json declaration.

ManualRowMappingRule and ManualResponseEnvelopeRule are the check rules that point new code at this module.