UNPKG

graphile-settings

Version:
125 lines (124 loc) 6.74 kB
"use strict"; 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); }