graphile-settings
Version:
graphile settings
125 lines (124 loc) • 6.74 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildBelongsToRelations = buildBelongsToRelations;
exports.buildReverseRelations = buildReverseRelations;
exports.buildManyToManyRelations = buildManyToManyRelations;
const inflection_utils_1 = require("./inflection-utils");
const constraint_meta_builders_1 = require("./constraint-meta-builders");
const table_meta_context_1 = require("./table-meta-context");
const table_resource_utils_1 = require("./table-resource-utils");
function isRecord(value) {
return typeof value === 'object' && value !== null;
}
function buildBelongsToRelations(codec, attributes, uniques, relations, context) {
const belongsTo = [];
for (const [relationName, relation] of Object.entries(relations)) {
// PostGraphile only sets isReferencee when true (reverse FK);
// forward relations have isReferencee undefined, not false.
if (relation.isReferencee)
continue;
const localAttributes = relation.localAttributes || [];
const isUnique = uniques.some((unique) => (0, table_resource_utils_1.sameAttributes)(unique.attributes, localAttributes));
const remoteCodec = relation.remoteResource?.codec;
belongsTo.push({
fieldName: relationName,
isUnique,
type: remoteCodec?.name || null,
keys: (0, table_meta_context_1.buildFieldList)(localAttributes, codec, attributes, context),
references: { name: remoteCodec?.name || 'unknown' },
});
}
return belongsTo;
}
function buildReverseRelations(codec, attributes, relations, context) {
const hasOne = [];
const hasMany = [];
for (const [relationName, relation] of Object.entries(relations)) {
if (relation.isReferencee !== true)
continue;
const remoteUniques = (0, table_resource_utils_1.getUniques)(relation.remoteResource || {});
const remoteAttributes = relation.remoteAttributes || [];
const isUnique = remoteUniques.some((unique) => (0, table_resource_utils_1.sameAttributes)(unique.attributes, remoteAttributes));
const remoteCodec = relation.remoteResource?.codec;
const meta = {
fieldName: relationName,
isUnique,
type: remoteCodec?.name || null,
keys: (0, table_meta_context_1.buildFieldList)(relation.localAttributes || [], codec, attributes, context),
referencedBy: { name: remoteCodec?.name || 'unknown' },
};
if (isUnique) {
hasOne.push(meta);
}
else {
hasMany.push(meta);
}
}
return { hasOne, hasMany };
}
function isManyToManyDetails(value) {
if (!isRecord(value))
return false;
return (isRecord(value.leftTable) &&
isRecord(value.junctionTable) &&
isRecord(value.rightTable) &&
typeof value.leftRelationName === 'string' &&
typeof value.rightRelationName === 'string');
}
function parseManyToManyRelationships(value) {
if (!Array.isArray(value))
return [];
return value.filter(isManyToManyDetails);
}
function getManyToManyRelationships(build, tableResource, codec) {
const relationshipsByResource = build.pgManyToManyRealtionshipsByResource;
if (!(relationshipsByResource instanceof Map))
return [];
const direct = parseManyToManyRelationships(relationshipsByResource.get(tableResource));
if (direct.length > 0)
return direct;
for (const [leftTable, relationships] of relationshipsByResource.entries()) {
const details = parseManyToManyRelationships(relationships);
if (details.length === 0 || !isRecord(leftTable))
continue;
if (leftTable.codec === codec) {
return details;
}
}
return [];
}
function buildManyToManyRelation(details, context) {
const leftCodec = (0, table_resource_utils_1.getResourceCodec)(details.leftTable);
const junctionCodec = (0, table_resource_utils_1.getResourceCodec)(details.junctionTable);
const rightCodec = (0, table_resource_utils_1.getResourceCodec)(details.rightTable);
if (!leftCodec || !junctionCodec || !rightCodec)
return null;
const leftRelation = (0, table_resource_utils_1.getRelation)(details.leftTable, details.leftRelationName);
const junctionRightRelation = (0, table_resource_utils_1.getRelation)(details.junctionTable, details.rightRelationName);
if (!leftRelation || !junctionRightRelation)
return null;
const leftJunctionAttributes = leftRelation.remoteAttributes || [];
const leftTableAttributes = leftRelation.localAttributes || [];
const rightJunctionAttributes = junctionRightRelation.localAttributes || [];
const rightTableAttributes = junctionRightRelation.remoteAttributes || [];
const relationFieldName = (0, inflection_utils_1.safeInflection)(() => context.build.inflection._manyToManyRelation?.(details), details.rightRelationName || rightCodec.name || null);
const junctionLeftConstraint = (0, constraint_meta_builders_1.buildForeignKeyConstraint)(details.leftRelationName || `${junctionCodec.name}_${leftCodec.name}_fkey`, junctionCodec, junctionCodec.attributes, leftJunctionAttributes, leftCodec, leftCodec.attributes, leftTableAttributes, context);
const junctionRightConstraint = (0, constraint_meta_builders_1.buildForeignKeyConstraint)(details.rightRelationName || `${junctionCodec.name}_${rightCodec.name}_fkey`, junctionCodec, junctionCodec.attributes, rightJunctionAttributes, rightCodec, rightCodec.attributes, rightTableAttributes, context);
return {
fieldName: relationFieldName,
type: rightCodec.name || null,
junctionTable: { name: junctionCodec.name || 'unknown' },
junctionLeftConstraint,
junctionLeftKeyAttributes: (0, table_meta_context_1.buildFieldList)(leftJunctionAttributes, junctionCodec, junctionCodec.attributes, context),
junctionRightConstraint,
junctionRightKeyAttributes: (0, table_meta_context_1.buildFieldList)(rightJunctionAttributes, junctionCodec, junctionCodec.attributes, context),
leftKeyAttributes: (0, table_meta_context_1.buildFieldList)(leftTableAttributes, leftCodec, leftCodec.attributes, context),
rightKeyAttributes: (0, table_meta_context_1.buildFieldList)(rightTableAttributes, rightCodec, rightCodec.attributes, context),
rightTable: { name: rightCodec.name || 'unknown' },
};
}
function buildManyToManyRelations(resource, codec, context) {
return getManyToManyRelationships(context.build, resource, codec)
.map((details) => buildManyToManyRelation(details, context))
.filter((relation) => relation !== null);
}