UNPKG

@finos/legend-graph

Version:
198 lines 11.1 kB
/** * Copyright (c) 2020-present, Goldman Sachs * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { assertTrue, filterByType, findLast, generateEnumerableNameFromToken, guaranteeNonNullable, uniq, UnsupportedOperationError, } from '@finos/legend-shared'; import { AggregationAwareSetImplementation } from '../metamodel/pure/packageableElements/mapping/aggregationAware/AggregationAwareSetImplementation.js'; import { RootRelationalInstanceSetImplementation } from '../metamodel/pure/packageableElements/store/relational/mapping/RootRelationalInstanceSetImplementation.js'; import { InstanceSetImplementation } from '../metamodel/pure/packageableElements/mapping/InstanceSetImplementation.js'; import { LakehouseRuntime, } from '../metamodel/pure/packageableElements/runtime/Runtime.js'; import { OperationSetImplementation } from '../metamodel/pure/packageableElements/mapping/OperationSetImplementation.js'; import { ObjectInputType } from '../metamodel/pure/packageableElements/mapping/DEPRECATED__MappingTest.js'; // ----------------------------------------- Mapping ----------------------------------------- /** * Get all included mappings, accounted for loop and duplication (which should be caught by compiler) */ export const getAllIncludedMappings = (mapping) => { const visited = new Set(); visited.add(mapping); const resolveIncludes = (_mapping) => { _mapping.includes.forEach((incMapping) => { if (!visited.has(incMapping.included.value)) { visited.add(incMapping.included.value); resolveIncludes(incMapping.included.value); } }); }; resolveIncludes(mapping); visited.delete(mapping); return Array.from(visited); }; export const getAllClassMappings = (mapping) => uniq(mapping.classMappings.concat(getAllIncludedMappings(mapping) .map((e) => e.classMappings) .flat())); export const getAllEnumerationMappings = (mapping) => uniq(mapping.enumerationMappings.concat(getAllIncludedMappings(mapping) .map((e) => e.enumerationMappings) .flat())); export const extractClassMappingsFromAggregationAwareClassMappings = (mapping) => { const aggregationAwareClassMappings = mapping.classMappings.filter(filterByType(AggregationAwareSetImplementation)); return [ ...aggregationAwareClassMappings.map((aggregate) => aggregate.mainSetImplementation), ...aggregationAwareClassMappings .map((aggregate) => aggregate.aggregateSetImplementations.map((setImpl) => setImpl.setImplementation)) .flat(), ]; }; export const getOwnClassMappingById = (mapping, id) => guaranteeNonNullable([ ...mapping.classMappings, ...extractClassMappingsFromAggregationAwareClassMappings(mapping), ].find((classMapping) => classMapping.id.value === id), `Can't find class mapping with ID '${id}' in mapping '${mapping.path}'`); export const getClassMappingById = (mapping, id) => guaranteeNonNullable([ ...getAllClassMappings(mapping), ...extractClassMappingsFromAggregationAwareClassMappings(mapping), ].find((classMapping) => classMapping.id.value === id), `Can't find class mapping with ID '${id}' in mapping '${mapping.path}'`); export const getOwnClassMappingsByClass = (mapping, _class) => // TODO: Add association property Mapping to class mappings, AggregationAwareSetImplementation, mappingClass // NOTE: Add in the proper order so find root can resolve properly down the line mapping.classMappings.filter((classMapping) => classMapping.class.value === _class); export const getClassMappingsByClass = (mapping, _class) => // TODO: Add association property Mapping to class mappings, AggregationAwareSetImplementation, mappingClass // NOTE: Add in the proper order so find root can resolve properly down the line getAllClassMappings(mapping).filter((classMapping) => classMapping.class.value === _class); export const getEnumerationMappingsByEnumeration = (mapping, enumeration) => getAllEnumerationMappings(mapping).filter((enumerationMapping) => enumerationMapping.enumeration.value === enumeration); export const getAllSuperSetImplementations = (currentSetImpl) => { if (currentSetImpl instanceof RootRelationalInstanceSetImplementation && currentSetImpl.superSetImplementationId) { const superSetImpl = [ getClassMappingById(currentSetImpl._PARENT, currentSetImpl.superSetImplementationId), ]; const superSetImplFromParents = superSetImpl .map((s) => getAllSuperSetImplementations(s)) .flat(); return superSetImpl.concat(superSetImplFromParents); } else { return []; } }; export const findRootSetImplementation = (classMappingsWithSimilarTarget) => { // NOTE: we use find last so that we can be sure we're picking the root set implementation of the current mapping first, // not the root set implementation of one of the included mappings, in case there's no root, we would prefer the root // of one of the included mappings (whichever comes later), // if there is not root set, and only one set implementation is found, we assume that is the root if (classMappingsWithSimilarTarget.length === 1 && classMappingsWithSimilarTarget[0]?.root.value === false) { return classMappingsWithSimilarTarget[0]; } return findLast(classMappingsWithSimilarTarget, (setImp) => setImp.root.value); }; export const getRootSetImplementation = (mapping, _class) => findRootSetImplementation(getClassMappingsByClass(mapping, _class)); export const findPropertyMapping = (instanceSetImplementation, propertyName, targetId) => { let properties = undefined; properties = instanceSetImplementation.propertyMappings.filter((propertyMapping) => propertyMapping.property.value.name === propertyName); if (targetId === undefined || properties.length === 1) { return properties[0]; } return properties.find((propertyMapping) => propertyMapping.targetSetImplementation && propertyMapping.targetSetImplementation.value.id.value === targetId); }; /** * Get all child set implementation of an operation set implementation (including itself). * This takes into account loops and duplication. */ export const getAllChildSetImplementations = (operationSetImplementation) => { const visitedOperations = new Set(); visitedOperations.add(operationSetImplementation); const _leaves = new Set(); const resolveLeaves = (_opSetImpl) => { _opSetImpl.parameters.forEach((p) => { const setImp = p.setImplementation.value; if (setImp instanceof OperationSetImplementation && !visitedOperations.has(setImp)) { visitedOperations.add(setImp); resolveLeaves(setImp); } else { _leaves.add(setImp); } }); }; resolveLeaves(operationSetImplementation); visitedOperations.delete(operationSetImplementation); return Array.from(_leaves).concat(Array.from(visitedOperations)); }; /** * Get all leaf set implementations (i.e. no operation) of an operation set implementation * This takes into account loops and duplication. */ export const getLeafSetImplementations = (operationSetImplementation) => getAllChildSetImplementations(operationSetImplementation).filter((child) => !(child instanceof OperationSetImplementation)); export const getObjectInputType = (type) => { switch (type) { case ObjectInputType.JSON: return ObjectInputType.JSON; case ObjectInputType.XML: return ObjectInputType.XML; default: throw new UnsupportedOperationError(`Encountered unsupported object input type '${type}'`); } }; export const getMappingCompatibleClasses = (mapping, classes) => { const mappedClasses = new Set(); getAllClassMappings(mapping).forEach((cm) => mappedClasses.add(cm.class.value)); return classes.filter((c) => mappedClasses.has(c)); }; export const getClassCompatibleMappings = (_class, mappings) => { const mappingsWithClassMapped = mappings.filter((mapping) => mapping.classMappings.some((cm) => cm.class.value === _class)); const resolvedMappingIncludes = mappings.filter((mapping) => getAllIncludedMappings(mapping).some((e) => mappingsWithClassMapped.includes(e))); return uniq([...mappingsWithClassMapped, ...resolvedMappingIncludes]); }; export const findMappingLocalProperty = (mappings, propertyName) => { let newProperty; mappings.forEach((mapping) => { mapping.classMappings.forEach((setImplementation) => { if (setImplementation instanceof InstanceSetImplementation) { setImplementation.propertyMappings.forEach((propertyMapping) => { if (propertyMapping.localMappingProperty && propertyMapping.property.value.name === propertyName) { newProperty = propertyMapping.property.value; } }); } }); }); return newProperty; }; // ----------------------------------------- Runtime ----------------------------------------- export const getAllIdentifiedConnections = (runtime) => runtime.connections.flatMap((storeConnections) => storeConnections.storeConnections); export const generateIdentifiedConnectionId = (runtime) => { const generatedId = generateEnumerableNameFromToken(getAllIdentifiedConnections(runtime).map((identifiedConnection) => identifiedConnection.id), 'connection'); assertTrue(!getAllIdentifiedConnections(runtime).find((identifiedConnection) => identifiedConnection.id === generatedId), `Can't auto-generate connection ID with value '${generatedId}'`); return generatedId; }; const isLakehouseRuntime = (runtimeValue) => { return runtimeValue instanceof LakehouseRuntime; }; export const getMappingCompatibleRuntimes = (mapping, runtimes) => // If the runtime claims to cover some mappings which include the specified mapping, // then we deem the runtime to be compatible with the such mapping runtimes.filter((runtime) => runtime.runtimeValue.mappings .flatMap((mappingReference) => [ mappingReference.value, ...getAllIncludedMappings(mappingReference.value), ]) .includes(mapping) || // TODO: remove once mappings are added to the protocol // include lakehouse runtime as for now they have no reference to mappings within their protocol isLakehouseRuntime(runtime.runtimeValue)); //# sourceMappingURL=DSL_Mapping_Helper.js.map