UNPKG

@finos/legend-graph

Version:
467 lines 21.7 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 { ROOT_PACKAGE_NAME, AUTO_IMPORTS, } from '../graph/MetaModelConst.js'; import { guaranteeNonNullable, guaranteeType, returnUndefOnError, IllegalStateError, isNonNullable, } from '@finos/legend-shared'; import { PrimitiveType } from '../graph/metamodel/pure/packageableElements/domain/PrimitiveType.js'; import { Enumeration } from '../graph/metamodel/pure/packageableElements/domain/Enumeration.js'; import { Multiplicity } from '../graph/metamodel/pure/packageableElements/domain/Multiplicity.js'; import { Package } from '../graph/metamodel/pure/packageableElements/domain/Package.js'; import { Class } from '../graph/metamodel/pure/packageableElements/domain/Class.js'; import { DependencyManager } from '../graph/DependencyManager.js'; import { ConcreteFunctionDefinition } from './metamodel/pure/packageableElements/function/ConcreteFunctionDefinition.js'; import { BasicModel } from './BasicModel.js'; import { FlatData } from '../graph/metamodel/pure/packageableElements/store/flatData/model/FlatData.js'; import { Database } from '../graph/metamodel/pure/packageableElements/store/relational/model/Database.js'; import { ModelStore } from '../graph/metamodel/pure/packageableElements/store/modelToModel/model/ModelStore.js'; import { Measure, Unit, } from '../graph/metamodel/pure/packageableElements/domain/Measure.js'; import { createPath } from '../graph/MetaModelUtils.js'; import { FunctionActivator } from './metamodel/pure/packageableElements/function/FunctionActivator.js'; /** * CoreModel holds meta models which are constant and basic building block of the graph. Since throughout the lifetime * of the application, we rebuild PureModel many times, we cannot have these basic building blocks as part of PureModel * as that will throw off referential equality. * * Also, since project dependency uses primitive types, it might even * cause the dependency model and system model to depend on PureModel which is bad, as it could potentially cause memory leak * as we rebuild the graph. */ export class CoreModel extends BasicModel { primitiveTypesIndex = new Map(); get primitiveTypes() { return Array.from(this.primitiveTypesIndex.values()); } constructor(graphPlugins) { super(ROOT_PACKAGE_NAME.CORE, graphPlugins); this.initializePrimitiveTypes(); // index model store singleton this.setOwnStore(ModelStore.NAME, ModelStore.INSTANCE); } get allOwnElements() { return [...super.allOwnElements, ...this.primitiveTypes]; } /** * NOTE: primitive types are special, they are not put in any package (i.e. they are not linked to `Root` package at all) */ initializePrimitiveTypes() { [ PrimitiveType.STRING, PrimitiveType.BOOLEAN, PrimitiveType.BINARY, PrimitiveType.NUMBER, PrimitiveType.INTEGER, PrimitiveType.FLOAT, PrimitiveType.DECIMAL, PrimitiveType.DATE, PrimitiveType.STRICTDATE, PrimitiveType.DATETIME, PrimitiveType.STRICTTIME, PrimitiveType.LATESTDATE, PrimitiveType.BYTE, ].forEach((primitiveType) => { this.primitiveTypesIndex.set(primitiveType.path, primitiveType); this.setOwnType(primitiveType.path, primitiveType); }); } } export class SystemModel extends BasicModel { autoImports = []; constructor(graphPlugins) { super(ROOT_PACKAGE_NAME.SYSTEM, graphPlugins); } /** * NOTE: auto imports are for special types and profiles from system model * such as `Any` or `doc` profiles. We don't actually build the packages here * just resolving them, so we have to make sure whatever package we have as * auto imports, we must have built some elements with such package, e.g. * * `meta::pure::metamodel::type::Any` covers `meta::pure::metamodel::type` * `meta::pure::profiles::doc` covers `meta::pure::profiles` */ initializeAutoImports() { this.autoImports = AUTO_IMPORTS.map((_package) => guaranteeType(this.getOwnNullableElement(_package, true), Package, `Can't find auto-import package '${_package}'`)); } } export class GenerationModel extends BasicModel { constructor(graphPlugins) { super(ROOT_PACKAGE_NAME.MODEL_GENERATION, graphPlugins); } } /** * The model of Pure, a.k.a the Pure graph */ export class PureModel extends BasicModel { coreModel; systemModel; generationModel; dependencyManager; // used to manage the elements from dependency projects constructor(coreModel, systemModel, graphPlugins) { super(ROOT_PACKAGE_NAME.MAIN, graphPlugins); this.coreModel = coreModel; this.systemModel = systemModel; this.generationModel = new GenerationModel(graphPlugins); this.dependencyManager = new DependencyManager(graphPlugins); } get autoImports() { return this.systemModel.autoImports; } get primitiveTypes() { return this.coreModel.primitiveTypes; } get sectionIndices() { return [ ...this.coreModel.ownSectionIndices, ...this.systemModel.ownSectionIndices, ...this.dependencyManager.sectionIndices, ...this.ownSectionIndices, ...this.generationModel.ownSectionIndices, ]; } get profiles() { return [ ...this.coreModel.ownProfiles, ...this.systemModel.ownProfiles, ...this.dependencyManager.profiles, ...this.ownProfiles, ...this.generationModel.ownProfiles, ]; } get enumerations() { return [ ...this.coreModel.ownEnumerations, ...this.systemModel.ownEnumerations, ...this.dependencyManager.enumerations, ...this.ownEnumerations, ...this.generationModel.ownEnumerations, ]; } get measures() { return [ ...this.coreModel.ownMeasures, ...this.systemModel.ownMeasures, ...this.dependencyManager.measures, ...this.ownMeasures, ...this.generationModel.ownMeasures, ]; } get classes() { return [ ...this.coreModel.ownClasses, ...this.systemModel.ownClasses, ...this.dependencyManager.classes, ...this.ownClasses, ...this.generationModel.ownClasses, ]; } get types() { return [ ...this.coreModel.ownTypes, ...this.systemModel.ownTypes, ...this.dependencyManager.types, ...this.ownTypes, ...this.generationModel.ownTypes, ]; } get associations() { return [ ...this.coreModel.ownAssociations, ...this.systemModel.ownAssociations, ...this.dependencyManager.associations, ...this.ownAssociations, ...this.generationModel.ownAssociations, ]; } get functions() { return [ ...this.coreModel.ownFunctions, ...this.systemModel.ownFunctions, ...this.dependencyManager.functions, ...this.ownFunctions, ...this.generationModel.ownFunctions, ]; } get functionActivators() { return [ ...this.coreModel.ownFunctionActivators, ...this.systemModel.ownFunctionActivators, ...this.dependencyManager.functionActivators, ...this.ownFunctionActivators, ...this.generationModel.ownFunctionActivators, ]; } get stores() { return [ ...this.coreModel.ownStores, ...this.systemModel.ownStores, ...this.dependencyManager.stores, ...this.ownStores, ...this.generationModel.ownStores, ]; } get databases() { return [ ...this.coreModel.ownDatabases, ...this.systemModel.ownDatabases, ...this.dependencyManager.databases, ...this.ownDatabases, ...this.generationModel.ownDatabases, ]; } get mappings() { return [ ...this.coreModel.ownMappings, ...this.systemModel.ownMappings, ...this.dependencyManager.mappings, ...this.ownMappings, ...this.generationModel.ownMappings, ]; } get services() { return [ ...this.coreModel.ownServices, ...this.systemModel.ownServices, ...this.dependencyManager.services, ...this.ownServices, ...this.generationModel.ownServices, ]; } get runtimes() { return [ ...this.coreModel.ownRuntimes, ...this.systemModel.ownRuntimes, ...this.dependencyManager.runtimes, ...this.ownRuntimes, ...this.generationModel.ownRuntimes, ]; } get connections() { return [ ...this.coreModel.ownConnections, ...this.systemModel.ownConnections, ...this.dependencyManager.connections, ...this.ownConnections, ...this.generationModel.ownConnections, ]; } get dataElements() { return [ ...this.coreModel.ownDataElements, ...this.systemModel.ownDataElements, ...this.dependencyManager.dataElements, ...this.ownDataElements, ...this.generationModel.ownDataElements, ]; } get executionEnvironments() { return [ ...this.coreModel.ownExecutionEnvironments, ...this.systemModel.ownExecutionEnvironments, ...this.dependencyManager.executionEnvironments, ...this.ownExecutionEnvironments, ...this.generationModel.ownExecutionEnvironments, ]; } get generationSpecifications() { return [ ...this.coreModel.ownGenerationSpecifications, ...this.systemModel.ownGenerationSpecifications, ...this.dependencyManager.generationSpecifications, ...this.ownGenerationSpecifications, ...this.generationModel.ownGenerationSpecifications, ]; } get fileGenerations() { return [ ...this.coreModel.ownFileGenerations, ...this.systemModel.ownFileGenerations, ...this.dependencyManager.fileGenerations, ...this.ownFileGenerations, ...this.generationModel.ownFileGenerations, ]; } get ingests() { return [ ...this.coreModel.ownIngests, ...this.systemModel.ownIngests, ...this.dependencyManager.ingests, ...this.ownIngests, ...this.generationModel.ownIngests, ]; } get allElements() { return [ ...this.coreModel.allOwnElements, ...this.systemModel.allOwnElements, ...this.dependencyManager.allOwnElements, ...this.allOwnElements, ...this.generationModel.allOwnElements, ]; } get testables() { return [ ...this.coreModel.ownTestables, ...this.systemModel.ownTestables, ...this.dependencyManager.testables, ...this.ownTestables, ...this.generationModel.ownTestables, ]; } getPrimitiveType = (type) => guaranteeNonNullable(this.coreModel.primitiveTypesIndex.get(type), `Can't find primitive type '${type}'`); getType = (path) => guaranteeNonNullable(this.getOwnNullableType(path) ?? this.generationModel.getOwnNullableType(path) ?? this.dependencyManager.getOwnNullableType(path) ?? this.systemModel.getOwnNullableType(path) ?? this.coreModel.getOwnNullableType(path), `Can't find type '${path}'`); getProfile = (path) => guaranteeNonNullable(this.getOwnNullableProfile(path) ?? this.generationModel.getOwnNullableProfile(path) ?? this.dependencyManager.getOwnNullableProfile(path) ?? this.systemModel.getOwnNullableProfile(path), `Can't find profile '${path}'`); getEnumeration = (path) => guaranteeType(this.getType(path), Enumeration, `Can't find enumeration '${path}'`); getMeasure = (path) => guaranteeType(this.getType(path), Measure, `Can't find measure '${path}'`); getUnit = (path) => guaranteeType(this.getType(path), Unit, `Can't find unit '${path}'`); getClass = (path) => guaranteeType(this.getType(path), Class, `Can't find class '${path}'`); getAssociation = (path) => guaranteeNonNullable(this.getOwnNullableAssociation(path) ?? this.generationModel.getOwnNullableAssociation(path) ?? this.dependencyManager.getOwnNullableAssociation(path) ?? this.systemModel.getOwnNullableAssociation(path), `Can't find association '${path}'`); getPropertyOwner = (path) => guaranteeNonNullable(this.getOwnNullableAssociation(path) ?? this.generationModel.getOwnNullableAssociation(path) ?? this.dependencyManager.getOwnNullableAssociation(path) ?? this.systemModel.getOwnNullableAssociation(path) ?? guaranteeType(this.getType(path), Class), `Can't find property owner '${path}'`); getFunction = (path) => guaranteeType(this.getOwnNullableFunction(path) ?? this.generationModel.getOwnNullableFunction(path) ?? this.dependencyManager.getOwnNullableFunction(path) ?? this.systemModel.getOwnNullableFunction(path), ConcreteFunctionDefinition, `Can't find function '${path}'`); getFunctionActivator = (path) => guaranteeType(this.getOwnNullableFunctionActivator(path) ?? this.generationModel.getOwnNullableFunctionActivator(path) ?? this.dependencyManager.getOwnNullableFunctionActivator(path) ?? this.systemModel.getOwnNullableFunctionActivator(path), FunctionActivator, `Can't find function activator '${path}'`); getStore = (path) => guaranteeNonNullable(this.getOwnNullableStore(path) ?? this.generationModel.getOwnNullableStore(path) ?? this.dependencyManager.getOwnNullableStore(path) ?? this.systemModel.getOwnNullableStore(path) ?? this.coreModel.getOwnNullableStore(path), `Can't find store '${path}'`); getFlatDataStore = (path) => guaranteeType(this.getStore(path), FlatData, `Can't find flat-data store '${path}'`); getDatabase = (path) => guaranteeType(this.getStore(path), Database, `Can't find database store '${path}'`); getMapping = (path) => guaranteeNonNullable(this.getOwnNullableMapping(path) ?? this.generationModel.getOwnNullableMapping(path) ?? this.dependencyManager.getOwnNullableMapping(path) ?? this.systemModel.getOwnNullableMapping(path), `Can't find mapping '${path}'`); getService = (path) => guaranteeNonNullable(this.getOwnNullableService(path) ?? this.generationModel.getOwnNullableService(path) ?? this.dependencyManager.getOwnNullableService(path) ?? this.systemModel.getOwnNullableService(path), `Can't find service '${path}'`); getConnection = (path) => guaranteeNonNullable(this.getOwnNullableConnection(path) ?? this.generationModel.getOwnNullableConnection(path) ?? this.dependencyManager.getOwnNullableConnection(path) ?? this.systemModel.getOwnNullableConnection(path), `Can't find connection '${path}'`); getRuntime = (path) => guaranteeNonNullable(this.getOwnNullableRuntime(path) ?? this.generationModel.getOwnNullableRuntime(path) ?? this.dependencyManager.getOwnNullableRuntime(path) ?? this.systemModel.getOwnNullableRuntime(path), `Can't find runtime '${path}'`); getGenerationSpecification = (path) => guaranteeNonNullable(this.getOwnNullableGenerationSpecification(path) ?? this.generationModel.getOwnNullableGenerationSpecification(path) ?? this.dependencyManager.getOwnNullableGenerationSpecification(path) ?? this.systemModel.getOwnNullableGenerationSpecification(path), `Can't find generation specification '${path}'`); getFileGeneration = (path) => guaranteeNonNullable(this.getOwnNullableFileGeneration(path) ?? this.generationModel.getOwnNullableFileGeneration(path) ?? this.dependencyManager.getOwnNullableFileGeneration(path) ?? this.systemModel.getOwnNullableFileGeneration(path), `Can't find file generation '${path}'`); getDataElement = (path) => guaranteeNonNullable(this.getOwnNullableDataElement(path) ?? this.generationModel.getOwnNullableDataElement(path) ?? this.dependencyManager.getOwnNullableDataElement(path) ?? this.systemModel.getOwnNullableDataElement(path), `Can't find data element '${path}'`); getExtensionElement(path, extensionElementClass, notFoundErrorMessage) { // NOTE: beware that this method will favor main graph elements over those of subgraphs when resolving return guaranteeNonNullable(this.getOwnNullableExtensionElement(path, extensionElementClass) ?? this.generationModel.getOwnNullableExtensionElement(path, extensionElementClass) ?? this.dependencyManager.getOwnNullableExtensionElement(path, extensionElementClass) ?? this.systemModel.getOwnNullableExtensionElement(path, extensionElementClass), notFoundErrorMessage ?? `Can't find element '${path}'`); } getElement = (path, includePackage) => guaranteeNonNullable(this.getNullableElement(path, includePackage), `Can't find element '${path}'`); getNullableClass = (path) => returnUndefOnError(() => this.getClass(path)); getNullableMapping = (path) => returnUndefOnError(() => this.getMapping(path)); getNullableService = (path) => returnUndefOnError(() => this.getService(path)); getNullableRuntime = (path) => returnUndefOnError(() => this.getRuntime(path)); getNullableFileGeneration = (path) => returnUndefOnError(() => this.getFileGeneration(path)); getNullableElement(path, includePackage) { // NOTE: beware that this method will favor main graph elements over those of subgraphs when resolving const element = super.getOwnNullableElement(path) ?? this.dependencyManager.getNullableElement(path) ?? this.generationModel.getOwnNullableElement(path) ?? this.systemModel.getOwnNullableElement(path) ?? this.coreModel.getOwnNullableElement(path); if (includePackage && !element) { return (this.getNullablePackage(path) ?? this.dependencyManager.getNullableElement(path, true) ?? this.generationModel.getNullablePackage(path) ?? this.systemModel.getNullablePackage(path)); } return element; } getPackages(path) { return [ this.getNullablePackage(path), ...this.dependencyManager.getPackages(path), this.generationModel.getNullablePackage(path), this.systemModel.getNullablePackage(path), ].filter(isNonNullable); } getMultiplicity(lowerBound, upperBound) { let multiplicity; if (lowerBound === 1 && upperBound === 1) { multiplicity = Multiplicity.ONE; } else if (lowerBound === 0 && upperBound === 1) { multiplicity = Multiplicity.ZERO_ONE; } else if (lowerBound === 0 && upperBound === undefined) { multiplicity = Multiplicity.ZERO_MANY; } else if (lowerBound === 1 && upperBound === undefined) { multiplicity = Multiplicity.ONE_MANY; } else if (lowerBound === 0 && upperBound === 0) { multiplicity = Multiplicity.ZERO; } return multiplicity ?? new Multiplicity(lowerBound, upperBound); } addElement(element, packagePath) { const fullPath = createPath(packagePath ?? '', element.name); // check for duplication first, but skip package const existingElement = this.getNullableElement(fullPath, false); if (existingElement) { throw new IllegalStateError(`Can't create element '${fullPath}': another element with the same path already existed`); } super.addOwnElement(element, packagePath); } deleteElement(element) { super.deleteOwnElement(element); const deadReferencesCleaners = this.graphPlugins.flatMap((plugin) => plugin.getExtraDeadReferencesCleaners?.() ?? []); for (const cleaner of deadReferencesCleaners) { cleaner(this); } } renameElement(element, newPath) { // check for duplication first, but skip package const existingElement = this.getNullableElement(newPath, false); if (existingElement) { throw new IllegalStateError(`Can't rename element '${element.path}' to '${newPath}': another element with the same path already existed`); } super.renameOwnElement(element, element.path, newPath); } } //# sourceMappingURL=PureModel.js.map