Add undirected edge support to package runtime
This commit is contained in:
+48
-6
@@ -18,6 +18,7 @@ import type {
|
||||
MigrationSpec,
|
||||
SchemaCompileResult,
|
||||
SymbolRef,
|
||||
EdgeDirectionality,
|
||||
TypeRef,
|
||||
} from "./schema-ir.js";
|
||||
|
||||
@@ -464,6 +465,39 @@ const endpointFromOption = (params: {
|
||||
};
|
||||
};
|
||||
|
||||
const symbolKey = (ref: SymbolRef | undefined) =>
|
||||
ref ? [ref.namespace, ref.name, ref.version, ref.hash ?? ""].join(":") : "";
|
||||
|
||||
const endpointRoleKey = (endpoint: ReturnType<typeof endpointFromOption>) =>
|
||||
[
|
||||
symbolKey(endpoint.class),
|
||||
symbolKey(endpoint.interface),
|
||||
endpoint.projection,
|
||||
endpoint.cardinality,
|
||||
].join("|");
|
||||
|
||||
const normalizeEdgeEndpoints = (params: {
|
||||
directionality: "directed" | "undirected";
|
||||
fromEndpoint: ReturnType<typeof endpointFromOption>;
|
||||
toEndpoint: ReturnType<typeof endpointFromOption>;
|
||||
}) => {
|
||||
if (params.directionality === "directed") {
|
||||
return {
|
||||
fromEndpoint: params.fromEndpoint,
|
||||
toEndpoint: params.toEndpoint,
|
||||
};
|
||||
}
|
||||
return endpointRoleKey(params.fromEndpoint) <= endpointRoleKey(params.toEndpoint)
|
||||
? {
|
||||
fromEndpoint: params.fromEndpoint,
|
||||
toEndpoint: params.toEndpoint,
|
||||
}
|
||||
: {
|
||||
fromEndpoint: params.toEndpoint,
|
||||
toEndpoint: params.fromEndpoint,
|
||||
};
|
||||
};
|
||||
|
||||
const symbolArrayFromOption = (
|
||||
value: unknown,
|
||||
defaults: ReturnType<typeof extractFileDefaults>,
|
||||
@@ -633,21 +667,21 @@ const classSchemaFromType = (
|
||||
version: defaults.schemaVersion,
|
||||
});
|
||||
const cardinality = cardinalityFromOption(edgeOption.cardinality);
|
||||
const fromEndpoint = endpointFromOption({
|
||||
const declaredFromEndpoint = endpointFromOption({
|
||||
option: edgeOption.this_endpoint,
|
||||
fallbackClass: classId,
|
||||
fallbackProjection: field.name,
|
||||
fallbackCardinality: cardinality,
|
||||
fallbackVersion: defaults.schemaVersion,
|
||||
});
|
||||
const toEndpoint = endpointFromOption({
|
||||
const declaredToEndpoint = endpointFromOption({
|
||||
option: edgeOption.other_endpoint,
|
||||
fallbackClass: legacyTargetClass.name ? legacyTargetClass : undefined,
|
||||
fallbackProjection: readString(edgeOption, "inverse") ?? "",
|
||||
fallbackCardinality: "many",
|
||||
fallbackVersion: defaults.schemaVersion,
|
||||
});
|
||||
if (!toEndpoint.projection) {
|
||||
if (!declaredToEndpoint.projection) {
|
||||
throw new Error(
|
||||
`Edge field ${type.fullName}.${field.name} requires other_endpoint.projection or inverse`,
|
||||
);
|
||||
@@ -659,13 +693,20 @@ const classSchemaFromType = (
|
||||
) {
|
||||
throw new Error(`Edge field ${type.fullName}.${field.name} must use camino.Ref`);
|
||||
}
|
||||
const isMany = isManyCardinality(fromEndpoint.cardinality);
|
||||
const isMany = isManyCardinality(declaredFromEndpoint.cardinality);
|
||||
if (isMany && !field.repeated) {
|
||||
throw new Error(`Edge field ${type.fullName}.${field.name} must be repeated for ${fromEndpoint.cardinality}`);
|
||||
throw new Error(`Edge field ${type.fullName}.${field.name} must be repeated for ${declaredFromEndpoint.cardinality}`);
|
||||
}
|
||||
if (!isMany && field.repeated) {
|
||||
throw new Error(`Edge field ${type.fullName}.${field.name} must not be repeated for ${fromEndpoint.cardinality}`);
|
||||
throw new Error(`Edge field ${type.fullName}.${field.name} must not be repeated for ${declaredFromEndpoint.cardinality}`);
|
||||
}
|
||||
const directionality: EdgeDirectionality =
|
||||
edgeOption.undirected === true ? "undirected" : "directed";
|
||||
const { fromEndpoint, toEndpoint } = normalizeEdgeEndpoints({
|
||||
directionality,
|
||||
fromEndpoint: declaredFromEndpoint,
|
||||
toEndpoint: declaredToEndpoint,
|
||||
});
|
||||
const edgeId = symbolRefFromOption(edgeOption.id, {
|
||||
namespace: defaults.schemaNamespace,
|
||||
name: `${type.name}.${field.name}`,
|
||||
@@ -679,6 +720,7 @@ const classSchemaFromType = (
|
||||
return [
|
||||
{
|
||||
id: edgeId,
|
||||
directionality,
|
||||
sourceField: fromEndpoint.projection,
|
||||
fromClass: fromEndpoint.class ?? classId,
|
||||
toClass: fallbackToClass,
|
||||
|
||||
Reference in New Issue
Block a user