RelationDescriptor.fromJson constructor
RelationDescriptor.fromJson(
- Map<
String, dynamic> json, - String path, {
- PanelDirection direction = PanelDirection.ltr,
direction is not read off json — same rule as ResourceSchema.direction:
a relation always inherits its owning resource's direction, propagated by
ResourceSchema.fromJson through listFromJson below, one level deeper
than PanelSchema.fromJson propagates it into the resource itself.
Implementation
factory RelationDescriptor.fromJson(
Map<String, dynamic> json,
String path, {
PanelDirection direction = PanelDirection.ltr,
}) {
// Required fields first, so a relation missing both its key and its card
// is still reported as the missing key it is.
final key = req<String>(json, 'key', path);
final label = req<String>(json, 'label', path);
final sortNodes = objects(json, 'sorts', path);
final card = CardLayout.fromJson(
object(json, 'card', path) ?? const {},
'$path.card',
);
// A card with no slot at all renders zero widgets, so the section would
// be a heading over nothing — the "disabled corpse" this contract does
// not publish. Every other missing required field already drops the
// relation; an absent, null or `{}` card used to be the one that did
// not, and [listFromJson]'s own doc has always claimed otherwise. The
// server refuses to publish one (`RelationDiscovery` names it in
// `doctor`), and this is the client half of the same rule: a wire shape
// nothing can render is a malformed relation, not a blank one.
if (card == const CardLayout.empty()) {
throw SchemaFormatException(
'$path.card',
'declares no slot, so the relation would render nothing',
);
}
return RelationDescriptor(
key: key,
label: label,
card: card,
// Absent on an older server that predates this field — 'id' is the
// same default `ResourceSchema.recordKey` takes, and the common case.
recordKey: opt<String>(json, 'recordKey') ?? 'id',
// Absent or null on a server predating P9, or one whose relation's
// child model resolves to zero or several mobile resources: either way
// the relation is read-only on this API. `opt` reads a wrong-typed
// value as absent too — a client never invents a capability the server
// did not declare.
resource: opt<String>(json, 'resource'),
// Absent on a server predating P11 reads as disabled/empty — the same
// absence rule the `relations` array itself carries — while a present
// but wrong-typed node throws, the convention ResourceSchema's own
// `search`/`sorts` blocks already follow (object()/objects(), not opt).
search: ResourceSearch.fromJson(object(json, 'search', path) ?? const {}),
sorts: List.generate(
sortNodes.length,
(index) =>
ResourceSort.fromJson(sortNodes[index], '$path.sorts[$index]'),
),
direction: direction,
);
}