Support checked keyed relationships across portable operations and queries
This commit is contained in:
@@ -32,6 +32,7 @@ export type GenericDependencyPort = Omit<DependencyPort, "requirement"> & {
|
||||
kind: "edge";
|
||||
target: ObjectTypeExpression;
|
||||
cardinality: Extract<DependencyPort["requirement"], { kind: "edge" }>["cardinality"];
|
||||
keyType?: "string" | "boolean" | "int64";
|
||||
primitives: Extract<DependencyPort["requirement"], { kind: "edge" }>["primitives"];
|
||||
}
|
||||
| {
|
||||
|
||||
@@ -33,6 +33,13 @@ export function validateInitialization(workspace: WorkspaceRevision): Capability
|
||||
fail(ownerKey(owner), `Initialization input ${field.input} must name an edge projection on the newborn atom`);
|
||||
return;
|
||||
}
|
||||
if (target.keyType) {
|
||||
fail(
|
||||
ownerKey(owner),
|
||||
"Initialize a keyed relationship through its keyed projection; inverse seeds cannot supply a map key",
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (endpoint.cardinality === "many" || endpoint.cardinality === "many-unique") {
|
||||
const fields: Record<string, ValueType> = {
|
||||
key: { kind: "scalar", name: "string" },
|
||||
|
||||
@@ -250,6 +250,7 @@ export type DependencyPortRequirement =
|
||||
kind: "edge";
|
||||
target: EdgeEndpointConstraint;
|
||||
cardinality: EdgeCardinality;
|
||||
keyType?: "string" | "boolean" | "int64";
|
||||
primitives: EdgePrimitive[];
|
||||
}
|
||||
| {
|
||||
|
||||
@@ -439,7 +439,19 @@ export const edgePrimitiveSignature = (
|
||||
case "disconnect":
|
||||
return {
|
||||
mode: "call",
|
||||
inputType: targetType,
|
||||
inputType:
|
||||
primitive === "connect" && projection.endpoint.keyType
|
||||
? {
|
||||
kind: "record",
|
||||
fields: {
|
||||
mapKey: {
|
||||
kind: "scalar",
|
||||
name: projection.endpoint.keyType === "boolean" ? "bool" : projection.endpoint.keyType,
|
||||
},
|
||||
target: targetType,
|
||||
},
|
||||
}
|
||||
: targetType,
|
||||
outputType: valueType.unit,
|
||||
};
|
||||
case "watch-start":
|
||||
@@ -1398,6 +1410,13 @@ const validateBoundDependencies = (
|
||||
);
|
||||
break;
|
||||
}
|
||||
if (projection.target.keyType && requirement.primitives.includes("connect"))
|
||||
issue(
|
||||
issues,
|
||||
"invalid-dependency-binding",
|
||||
path,
|
||||
"Connect through the keyed projection so the caller supplies a map key",
|
||||
);
|
||||
const traversal = edgeBinding.via
|
||||
? validateTraversal(
|
||||
issues,
|
||||
@@ -1434,13 +1453,14 @@ const validateBoundDependencies = (
|
||||
requirement.target,
|
||||
params.indexes.conformances,
|
||||
) ||
|
||||
requirement.cardinality !== projection.endpoint.cardinality
|
||||
requirement.cardinality !== projection.endpoint.cardinality ||
|
||||
requirement.keyType !== projection.endpoint.keyType
|
||||
) {
|
||||
issue(
|
||||
issues,
|
||||
"invalid-dependency-binding",
|
||||
`${path}.binding`,
|
||||
`Edge port target or cardinality does not match projection ${edgeBinding.projectionId}`,
|
||||
`Edge port target, cardinality or key type does not match projection ${edgeBinding.projectionId}`,
|
||||
);
|
||||
}
|
||||
break;
|
||||
@@ -1822,6 +1842,13 @@ const validateConformances = (
|
||||
continue;
|
||||
}
|
||||
const projection = edgeProjection(attachment.attachment, binding.projectionId);
|
||||
if (projection?.target.keyType && binding.primitive === "connect")
|
||||
issue(
|
||||
issues,
|
||||
"invalid-edge-binding",
|
||||
bindingPath,
|
||||
"Connect through the keyed projection so the caller supplies a map key",
|
||||
);
|
||||
// An owned endpoint may explicitly export read-only traversal, including
|
||||
// a native inverse relationship view. This never exports mutation rights.
|
||||
if (!(binding.primitive === "resolve" && projection?.endpoint.publicTraversal)) {
|
||||
|
||||
Reference in New Issue
Block a user