Use lenses
The lens API relates a source record to a target-shaped view. get constructs the view, put reconstructs a source-shaped record from an edited view, and the complement retains source data that get did not place in the view.
Prerequisites
A migration (Build a migration) or a hand-written lens via the lens DSL.
The task
A CompiledMigration exposes the lens operations directly. LensHandle represents a concrete auto-generated or DSL-compiled lens, while ProtolensChainHandle represents a schema-parameterized chain.
const { view, complement } = mig.getJson(oldRecord, "user:body");
const recordView = view as { age: number };
const editedView = { ...recordView, age: recordView.age + 1 };
const updatedOld = mig.putJson(editedView, complement, "user:body") as {
age: number;
};
mig.getJson returns the forward view together with the complement, which retains data discarded by the forward operation. mig.putJson consumes both values and reconstructs a JavaScript record with the edit applied. The law checks below test the round trip for a supplied instance.
To compose two compiled migrations sequentially:
const composed = p.compose(mig_ab, mig_bc);
To compose two concrete LensHandle values:
const composedLens = p.composeLenses(lensAB, lensBC);
To compose schema-parameterized chains, call the method on the first chain:
const composedChain = chainAB.compose(chainBC);
Panproto.compose and Panproto.composeLenses compose compiled migrations and concrete lenses, respectively. ProtolensChainHandle.compose handles protolens chains. Each operation throws if the intermediate schemas or theory transforms do not chain.
Verification
const result = lens.checkLaws(instanceBytes);
console.log(result.holds, result.violation);
// For individual laws:
const getput = lens.checkGetPut(instanceBytes);
const putget = lens.checkPutGet(instanceBytes);
LensHandle.checkLaws(instance) returns a LawCheckResult { holds, violation } covering GetPut and PutGet together. checkGetPut and checkPutGet test each law individually; the Rust property tests in panproto-lens cover PutPut as well, exercised continuously in CI.
Common mistakes
- Calling
putwith a complement produced for a different source schema.putcompares the complement’s source fingerprint with the lens source and returnsComplementMismatchwhen they differ. Recompute the complement with this lens. - Reading
getand then mutating the source before callingput. The complement is computed against the source as it was atgettime; if you mutate the source, the complement is stale. - Composing lenses whose intermediate schemas are isomorphic but not equal. The structural-equality check on
protolens_composablewill reject; rebuild one of the lenses against the other’s schema.