@finos/legend-graph 32.5.0 → 32.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/lib/graph/metamodel/pure/dataProduct/DataProduct.d.ts +4 -3
  2. package/lib/graph/metamodel/pure/dataProduct/DataProduct.d.ts.map +1 -1
  3. package/lib/graph/metamodel/pure/dataProduct/DataProduct.js +7 -5
  4. package/lib/graph/metamodel/pure/dataProduct/DataProduct.js.map +1 -1
  5. package/lib/graph/metamodel/pure/packageableElements/relation/Accessor.d.ts +1 -0
  6. package/lib/graph/metamodel/pure/packageableElements/relation/Accessor.d.ts.map +1 -1
  7. package/lib/graph/metamodel/pure/packageableElements/relation/Accessor.js +5 -1
  8. package/lib/graph/metamodel/pure/packageableElements/relation/Accessor.js.map +1 -1
  9. package/lib/graph-manager/action/query/Query.d.ts +7 -0
  10. package/lib/graph-manager/action/query/Query.d.ts.map +1 -1
  11. package/lib/graph-manager/action/query/Query.js +7 -0
  12. package/lib/graph-manager/action/query/Query.js.map +1 -1
  13. package/lib/graph-manager/helpers/DataProductHelper.d.ts +7 -2
  14. package/lib/graph-manager/helpers/DataProductHelper.d.ts.map +1 -1
  15. package/lib/graph-manager/helpers/DataProductHelper.js +27 -2
  16. package/lib/graph-manager/helpers/DataProductHelper.js.map +1 -1
  17. package/lib/graph-manager/protocol/pure/v1/V1_PureGraphManager.d.ts +13 -1
  18. package/lib/graph-manager/protocol/pure/v1/V1_PureGraphManager.d.ts.map +1 -1
  19. package/lib/graph-manager/protocol/pure/v1/V1_PureGraphManager.js +214 -92
  20. package/lib/graph-manager/protocol/pure/v1/V1_PureGraphManager.js.map +1 -1
  21. package/lib/graph-manager/protocol/pure/v1/engine/V1_EngineHelper.d.ts.map +1 -1
  22. package/lib/graph-manager/protocol/pure/v1/engine/V1_EngineHelper.js +20 -2
  23. package/lib/graph-manager/protocol/pure/v1/engine/V1_EngineHelper.js.map +1 -1
  24. package/lib/graph-manager/protocol/pure/v1/engine/analytics/V1_MappingModelCoverageAnalysis.d.ts.map +1 -1
  25. package/lib/graph-manager/protocol/pure/v1/engine/analytics/V1_MappingModelCoverageAnalysis.js +7 -0
  26. package/lib/graph-manager/protocol/pure/v1/engine/analytics/V1_MappingModelCoverageAnalysis.js.map +1 -1
  27. package/lib/graph-manager/protocol/pure/v1/engine/query/V1_Query.d.ts +6 -1
  28. package/lib/graph-manager/protocol/pure/v1/engine/query/V1_Query.d.ts.map +1 -1
  29. package/lib/graph-manager/protocol/pure/v1/engine/query/V1_Query.js +16 -0
  30. package/lib/graph-manager/protocol/pure/v1/engine/query/V1_Query.js.map +1 -1
  31. package/lib/graph-manager/protocol/pure/v1/transformation/pureGraph/to/helpers/V1_DataProductBuilder.d.ts +1 -1
  32. package/lib/graph-manager/protocol/pure/v1/transformation/pureGraph/to/helpers/V1_DataProductBuilder.d.ts.map +1 -1
  33. package/lib/graph-manager/protocol/pure/v1/transformation/pureGraph/to/helpers/V1_DataProductBuilder.js +6 -6
  34. package/lib/graph-manager/protocol/pure/v1/transformation/pureGraph/to/helpers/V1_DataProductBuilder.js.map +1 -1
  35. package/lib/graph-manager/protocol/pure/v1/transformation/pureProtocol/V1_PureProtocolSerialization.d.ts.map +1 -1
  36. package/lib/graph-manager/protocol/pure/v1/transformation/pureProtocol/V1_PureProtocolSerialization.js +14 -10
  37. package/lib/graph-manager/protocol/pure/v1/transformation/pureProtocol/V1_PureProtocolSerialization.js.map +1 -1
  38. package/lib/package.json +1 -1
  39. package/package.json +3 -3
  40. package/src/graph/metamodel/pure/dataProduct/DataProduct.ts +13 -5
  41. package/src/graph/metamodel/pure/packageableElements/relation/Accessor.ts +6 -1
  42. package/src/graph-manager/action/query/Query.ts +9 -0
  43. package/src/graph-manager/helpers/DataProductHelper.ts +47 -4
  44. package/src/graph-manager/protocol/pure/v1/V1_PureGraphManager.ts +488 -484
  45. package/src/graph-manager/protocol/pure/v1/engine/V1_EngineHelper.ts +22 -0
  46. package/src/graph-manager/protocol/pure/v1/engine/analytics/V1_MappingModelCoverageAnalysis.ts +7 -0
  47. package/src/graph-manager/protocol/pure/v1/engine/query/V1_Query.ts +28 -0
  48. package/src/graph-manager/protocol/pure/v1/transformation/pureGraph/to/helpers/V1_DataProductBuilder.ts +6 -3
  49. package/src/graph-manager/protocol/pure/v1/transformation/pureProtocol/V1_PureProtocolSerialization.ts +21 -23
@@ -17,6 +17,8 @@ import { GRAPH_MANAGER_EVENT } from '../../../../__lib__/GraphManagerEvent.js';
17
17
  import { CORE_PURE_PATH, PackageableElementPointerType, } from '../../../../graph/MetaModelConst.js';
18
18
  import { ActionState, TracerService, LogEvent, getClass, guaranteeNonNullable, UnsupportedOperationError, assertErrorThrown, promisify, StopWatch, isNonNullable, filterByType, isString, assertNonEmptyString, uniq, guaranteeType, guaranteeNonEmptyString, uuid, } from '@finos/legend-shared';
19
19
  import { AbstractPureGraphManager, } from '../../../../graph-manager/AbstractPureGraphManager.js';
20
+ import { Mapping } from '../../../../graph/metamodel/pure/packageableElements/mapping/Mapping.js';
21
+ import { PackageableRuntime } from '../../../../graph/metamodel/pure/packageableElements/runtime/PackageableRuntime.js';
20
22
  import { PureModel, } from '../../../../graph/PureModel.js';
21
23
  import { RawLambda } from '../../../../graph/metamodel/pure/rawValueSpecification/RawLambda.js';
22
24
  import { ServiceRegistrationSuccess, ServiceRegistrationFail, } from '../../../../graph-manager/action/service/ServiceRegistrationResult.js';
@@ -125,7 +127,7 @@ import { V1_INTERNAL__UnknownElement } from './model/packageableElements/V1_INTE
125
127
  import { V1_HostedService } from './model/packageableElements/function/V1_HostedService.js';
126
128
  import { V1_UserListOwnership } from './model/packageableElements/service/V1_ServiceOwnership.js';
127
129
  import { V1_PureSingleExecution } from './model/packageableElements/service/V1_ServiceExecution.js';
128
- import { V1_RuntimePointer, } from './model/packageableElements/runtime/V1_Runtime.js';
130
+ import { V1_EngineRuntime, V1_RuntimePointer, } from './model/packageableElements/runtime/V1_Runtime.js';
129
131
  import { V1_buildDebugTestsResult } from './engine/test/V1_DebugTestsResult.js';
130
132
  import { V1_CompleteCodeInput } from './engine/compilation/V1_CompleteCodeInput.js';
131
133
  import { V1_QueryParameterValue } from './engine/query/V1_Query.js';
@@ -134,7 +136,7 @@ import { V1_buildFunctionSignature, V1_createGenericTypeWithElementPath, } from
134
136
  import { V1_DataProduct } from './model/packageableElements/dataProduct/V1_DataProduct.js';
135
137
  import { V1_DataProductArtifact, V1_ModelAccessPointGroupInfo, } from './lakehouse/deploy/V1_DataProductArtifact.js';
136
138
  import { DataProductAnalysisQueryResult, DataProductAnalysis, } from '../../../action/analytics/data-product/DataProductAnalysis.js';
137
- import { DataProductAccessType, ModelAccessPointGroup, NativeModelAccess, NativeModelExecutionContext, } from '../../../../graph/metamodel/pure/dataProduct/DataProduct.js';
139
+ import { DataProductAccessType, DataProductElementScope, ModelAccessPointGroup, NativeModelAccess, NativeModelExecutionContext, } from '../../../../graph/metamodel/pure/dataProduct/DataProduct.js';
138
140
  import { V1_MemSQLFunction } from './model/packageableElements/function/V1_MemSQLFunction.js';
139
141
  import { LineageModel } from '../../../../graph/metamodel/pure/lineage/LineageModel.js';
140
142
  import { V1_LineageInput, } from './model/lineage/V1_Lineage.js';
@@ -143,6 +145,11 @@ import { V1_DevMetadataPushRequest, V1_MetadataRequestOptions, V1_MetadatProject
143
145
  import { IngestDefinition } from '../../../../graph/metamodel/pure/packageableElements/ingest/IngestDefinition.js';
144
146
  import { Database } from '../../../../graph/metamodel/pure/packageableElements/store/relational/model/Database.js';
145
147
  import { V1_createAccessorFromPackageableElement } from './helpers/V1_AccessorHelper.js';
148
+ /**
149
+ * Number of elements to process synchronously before yielding to the event loop.
150
+ * This avoids per-element setTimeout overhead while keeping the UI responsive.
151
+ */
152
+ const GRAPH_BUILDER_BATCH_SIZE = 100;
146
153
  class V1_PureModelContextDataIndex {
147
154
  elements = [];
148
155
  nativeElements = [];
@@ -694,82 +701,122 @@ export class V1_PureGraphManager extends AbstractPureGraphManager {
694
701
  // this way, as we build the a graph, we know the next step's duplication check
695
702
  // has path cache consisting of all element from its base graphs
696
703
  const elementPathCache = new Set(graph.allElements.map((el) => el.path));
697
- await Promise.all(inputs.flatMap(async (input) => {
698
- // create the package cache
704
+ // NOTE: We must index ALL native elements across ALL inputs before indexing
705
+ // plugin-contributed ("other") elements. Plugin elements
706
+ // may resolve references to native elements (e.g. Mapping, Runtime) from
707
+ // other inputs during their first pass. If we process each input fully
708
+ // (native + other) before moving to the next, a plugin element in input[0]
709
+ // could fail to find a native element that only exists in input[1].
710
+ const packageCaches = new Map();
711
+ const createFirstPassBuilder = (input, packageCache, element) => new V1_ElementFirstPassBuilder(this.getBuilderContext(graph, input.model, element, options), packageCache, elementPathCache);
712
+ for (const input of inputs) {
699
713
  const packageCache = new Map();
700
- await Promise.all(input.data.nativeElements.map((element) => {
701
- return this.visitWithGraphBuilderErrorHandling(element, new V1_ElementFirstPassBuilder(this.getBuilderContext(graph, input.model, element, options), packageCache, elementPathCache));
702
- }));
703
- await Promise.all(this.graphBuilderExtensions.sortedExtraElementBuilders.flatMap((builder) => (input.data.otherElementsByBuilder.get(builder) ?? []).map((element) => {
704
- return this.visitWithGraphBuilderErrorHandling(element, new V1_ElementFirstPassBuilder(this.getBuilderContext(graph, input.model, element, options), packageCache, elementPathCache));
705
- })));
706
- }));
714
+ packageCaches.set(input, packageCache);
715
+ // Phase 1: index native elements for this input
716
+ await this.runBatchedLoop(input.data.nativeElements, (element) => this.visitWithGraphBuilderErrorHandling(element, createFirstPassBuilder(input, packageCache, element)));
717
+ }
718
+ // Phase 2: index other (plugin-contributed) elements across all inputs,
719
+ // now that all native elements have been indexed
720
+ for (const input of inputs) {
721
+ const packageCache = guaranteeNonNullable(packageCaches.get(input));
722
+ const otherElements = this.graphBuilderExtensions.sortedExtraElementBuilders.flatMap((builder) => input.data.otherElementsByBuilder.get(builder) ?? []);
723
+ await this.runBatchedLoop(otherElements, (element) => this.visitWithGraphBuilderErrorHandling(element, createFirstPassBuilder(input, packageCache, element)));
724
+ }
707
725
  }
708
726
  async buildTypes(graph, inputs, options) {
709
727
  // Second pass
710
- await Promise.all(inputs.flatMap((input) => input.data.profiles.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementSecondPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
711
- await Promise.all(inputs.flatMap((input) => input.data.classes.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementSecondPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
712
- await Promise.all(inputs.flatMap((input) => input.data.enumerations.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementSecondPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
713
- await Promise.all(inputs.flatMap((input) => input.data.measures.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementSecondPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
714
- await Promise.all(inputs.flatMap((input) => input.data.functions.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementSecondPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
728
+ await this.processElementsInBatches(graph, inputs, (data) => data.profiles, (ctx) => new V1_ElementSecondPassBuilder(ctx), options);
729
+ await this.processElementsInBatches(graph, inputs, (data) => data.classes, (ctx) => new V1_ElementSecondPassBuilder(ctx), options);
730
+ await this.processElementsInBatches(graph, inputs, (data) => data.enumerations, (ctx) => new V1_ElementSecondPassBuilder(ctx), options);
731
+ await this.processElementsInBatches(graph, inputs, (data) => data.measures, (ctx) => new V1_ElementSecondPassBuilder(ctx), options);
732
+ await this.processElementsInBatches(graph, inputs, (data) => data.functions, (ctx) => new V1_ElementSecondPassBuilder(ctx), options);
715
733
  // Third pass
716
- await Promise.all(inputs.flatMap((input) => input.data.classes.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementThirdPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
717
- await Promise.all(inputs.flatMap((input) => input.data.associations.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementThirdPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
734
+ await this.processElementsInBatches(graph, inputs, (data) => data.classes, (ctx) => new V1_ElementThirdPassBuilder(ctx), options);
735
+ await this.processElementsInBatches(graph, inputs, (data) => data.associations, (ctx) => new V1_ElementThirdPassBuilder(ctx), options);
718
736
  // Fourth Pass
719
- await Promise.all(inputs.flatMap((input) => input.data.classes.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementFourthPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
720
- await Promise.all(inputs.flatMap((input) => input.data.associations.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementFourthPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
737
+ await this.processElementsInBatches(graph, inputs, (data) => data.classes, (ctx) => new V1_ElementFourthPassBuilder(ctx), options);
738
+ await this.processElementsInBatches(graph, inputs, (data) => data.associations, (ctx) => new V1_ElementFourthPassBuilder(ctx), options);
721
739
  // Fifth pass
722
- await Promise.all(inputs.flatMap((input) => input.data.classes.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementFifthPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
740
+ await this.processElementsInBatches(graph, inputs, (data) => data.classes, (ctx) => new V1_ElementFifthPassBuilder(ctx), options);
723
741
  }
724
742
  async buildFunctionActivators(graph, inputs, options) {
725
- await Promise.all(inputs.flatMap((input) => input.data.functionActivators.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementSecondPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
743
+ await this.processElementsInBatches(graph, inputs, (data) => data.functionActivators, (ctx) => new V1_ElementSecondPassBuilder(ctx), options);
726
744
  }
727
745
  async buildStores(graph, inputs, options) {
728
- await Promise.all(inputs.flatMap((input) => input.data.stores.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementSecondPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
729
- await Promise.all(inputs.flatMap((input) => input.data.stores.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementThirdPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
730
- await Promise.all(inputs.flatMap((input) => input.data.stores.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementFourthPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
731
- await Promise.all(inputs.flatMap((input) => input.data.stores.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementFifthPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
746
+ await this.processElementsInBatches(graph, inputs, (data) => data.stores, (ctx) => new V1_ElementSecondPassBuilder(ctx), options);
747
+ await this.processElementsInBatches(graph, inputs, (data) => data.stores, (ctx) => new V1_ElementThirdPassBuilder(ctx), options);
748
+ await this.processElementsInBatches(graph, inputs, (data) => data.stores, (ctx) => new V1_ElementFourthPassBuilder(ctx), options);
749
+ await this.processElementsInBatches(graph, inputs, (data) => data.stores, (ctx) => new V1_ElementFifthPassBuilder(ctx), options);
732
750
  }
733
751
  async buildMappings(graph, inputs, options) {
734
- await Promise.all(inputs.flatMap((input) => input.data.mappings.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementSecondPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
735
- await Promise.all(inputs.flatMap((input) => input.data.mappings.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementThirdPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
736
- await Promise.all(inputs.flatMap((input) => input.data.mappings.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementFourthPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
752
+ await this.processElementsInBatches(graph, inputs, (data) => data.mappings, (ctx) => new V1_ElementSecondPassBuilder(ctx), options);
753
+ await this.processElementsInBatches(graph, inputs, (data) => data.mappings, (ctx) => new V1_ElementThirdPassBuilder(ctx), options);
754
+ await this.processElementsInBatches(graph, inputs, (data) => data.mappings, (ctx) => new V1_ElementFourthPassBuilder(ctx), options);
737
755
  }
738
756
  async buildConnectionsAndRuntimes(graph, inputs, options) {
739
757
  // NOTE: connections must be built before runtimes
740
- await Promise.all(inputs.flatMap((input) => input.data.connections.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementSecondPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
741
- await Promise.all(inputs.flatMap((input) => input.data.runtimes.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementSecondPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
758
+ await this.processElementsInBatches(graph, inputs, (data) => data.connections, (ctx) => new V1_ElementSecondPassBuilder(ctx), options);
759
+ await this.processElementsInBatches(graph, inputs, (data) => data.runtimes, (ctx) => new V1_ElementSecondPassBuilder(ctx), options);
742
760
  }
743
761
  async buildServices(graph, inputs, options) {
744
- await Promise.all(inputs.flatMap((input) => input.data.services.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementSecondPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
745
- await Promise.all(inputs.flatMap((input) => input.data.executionEnvironments.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementSecondPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
762
+ await this.processElementsInBatches(graph, inputs, (data) => data.services, (ctx) => new V1_ElementSecondPassBuilder(ctx), options);
763
+ await this.processElementsInBatches(graph, inputs, (data) => data.executionEnvironments, (ctx) => new V1_ElementSecondPassBuilder(ctx), options);
746
764
  }
747
765
  async buildDataElements(graph, inputs, options) {
748
- await Promise.all(inputs.flatMap((input) => input.data.dataElements.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementSecondPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
766
+ await this.processElementsInBatches(graph, inputs, (data) => data.dataElements, (ctx) => new V1_ElementSecondPassBuilder(ctx), options);
749
767
  }
750
768
  async buildDataProducts(graph, inputs, options) {
751
- await Promise.all(inputs.flatMap((input) => input.data.products.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementSecondPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
769
+ await this.processElementsInBatches(graph, inputs, (data) => data.products, (ctx) => new V1_ElementSecondPassBuilder(ctx), options);
752
770
  }
753
771
  async buildFileGenerations(graph, inputs, options) {
754
- await Promise.all(inputs.flatMap((input) => input.data.fileGenerations.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementSecondPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
772
+ await this.processElementsInBatches(graph, inputs, (data) => data.fileGenerations, (ctx) => new V1_ElementSecondPassBuilder(ctx), options);
755
773
  }
756
774
  async buildGenerationSpecifications(graph, inputs, options) {
757
- await Promise.all(inputs.flatMap((input) => input.data.generationSpecifications.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementSecondPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
775
+ await this.processElementsInBatches(graph, inputs, (data) => data.generationSpecifications, (ctx) => new V1_ElementSecondPassBuilder(ctx), options);
758
776
  }
759
777
  async buildSectionIndices(graph, inputs, options) {
760
- await Promise.all(inputs.flatMap((input) => input.data.sectionIndices.map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementSecondPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
778
+ await this.processElementsInBatches(graph, inputs, (data) => data.sectionIndices, (ctx) => new V1_ElementSecondPassBuilder(ctx), options);
761
779
  }
762
780
  async buildOtherElements(graph, inputs, options) {
763
- await Promise.all(this.graphBuilderExtensions.sortedExtraElementBuilders.map(async (builder) => {
764
- await Promise.all(inputs.flatMap((input) => (input.data.otherElementsByBuilder.get(builder) ?? []).map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementSecondPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
765
- await Promise.all(inputs.flatMap((input) => (input.data.otherElementsByBuilder.get(builder) ?? []).map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementThirdPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
766
- await Promise.all(inputs.flatMap((input) => (input.data.otherElementsByBuilder.get(builder) ?? []).map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementFourthPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
767
- await Promise.all(inputs.flatMap((input) => (input.data.otherElementsByBuilder.get(builder) ?? []).map((element) => this.visitWithGraphBuilderErrorHandling(element, new V1_ElementFifthPassBuilder(this.getBuilderContext(graph, input.model, element, options))))));
768
- }));
781
+ for (const builder of this.graphBuilderExtensions
782
+ .sortedExtraElementBuilders) {
783
+ const getElements = (data) => data.otherElementsByBuilder.get(builder) ?? [];
784
+ await this.processElementsInBatches(graph, inputs, getElements, (ctx) => new V1_ElementSecondPassBuilder(ctx), options);
785
+ await this.processElementsInBatches(graph, inputs, getElements, (ctx) => new V1_ElementThirdPassBuilder(ctx), options);
786
+ await this.processElementsInBatches(graph, inputs, getElements, (ctx) => new V1_ElementFourthPassBuilder(ctx), options);
787
+ await this.processElementsInBatches(graph, inputs, getElements, (ctx) => new V1_ElementFifthPassBuilder(ctx), options);
788
+ }
789
+ }
790
+ /**
791
+ * Run a callback for each item in the array, processing items in batches
792
+ * of {@link GRAPH_BUILDER_BATCH_SIZE} and yielding to the event loop between
793
+ * batches to keep the UI responsive.
794
+ */
795
+ async runBatchedLoop(items, process) {
796
+ for (let i = 0; i < items.length; i += GRAPH_BUILDER_BATCH_SIZE) {
797
+ if (i > 0) {
798
+ await new Promise((resolve) => setTimeout(resolve, 0));
799
+ }
800
+ const end = Math.min(i + GRAPH_BUILDER_BATCH_SIZE, items.length);
801
+ for (let j = i; j < end; j++) {
802
+ process(guaranteeNonNullable(items[j]));
803
+ }
804
+ }
805
+ }
806
+ /**
807
+ * Process elements from inputs in batches, yielding to the event loop
808
+ * between batches to keep the UI responsive.
809
+ */
810
+ async processElementsInBatches(graph, inputs, getElements, createVisitor, options) {
811
+ const allItems = inputs.flatMap((input) => getElements(input.data).map((element) => ({
812
+ element,
813
+ model: input.model,
814
+ })));
815
+ await this.runBatchedLoop(allItems, (item) => this.visitWithGraphBuilderErrorHandling(item.element, createVisitor(this.getBuilderContext(graph, item.model, item.element, options))));
769
816
  }
770
817
  visitWithGraphBuilderErrorHandling(element, visitor) {
771
818
  try {
772
- return promisify(() => element.accept_PackageableElementVisitor(visitor));
819
+ return element.accept_PackageableElementVisitor(visitor);
773
820
  }
774
821
  catch (err) {
775
822
  assertErrorThrown(err);
@@ -1722,22 +1769,21 @@ export class V1_PureGraphManager extends AbstractPureGraphManager {
1722
1769
  const artifact = V1_DataProductArtifact.serialization.fromJson(artifactJson);
1723
1770
  return this.buildDataProductAnalysis(artifact, dataProductPath, pureGraph, accessPointId, dataProductAccessType, projectInfo, graphReport);
1724
1771
  }
1725
- async buildDataProductAnalysis(artifact, dataProductPath, pureGraph, accessPointId, dataProductAccessType, projectInfo, graphReport) {
1726
- // Collect all mapping generation infos from model access point groups and native model access
1727
- const allMappingGenInfos = new Map();
1728
- const modelAccessPointGroups = artifact.accessPointGroups.filter((group) => group instanceof V1_ModelAccessPointGroupInfo);
1729
- for (const group of modelAccessPointGroups) {
1730
- allMappingGenInfos.set(group.mappingGeneration.path, group.mappingGeneration);
1731
- }
1732
- if (artifact.nativeModelAccess?.mappingGenerations) {
1733
- for (const [path, genInfo] of artifact.nativeModelAccess
1734
- .mappingGenerations) {
1735
- if (!allMappingGenInfos.has(path)) {
1736
- allMappingGenInfos.set(path, genInfo);
1737
- }
1772
+ resolveArtifactElements(elementPaths, pureGraph) {
1773
+ const scopes = [];
1774
+ for (const path of elementPaths) {
1775
+ const el = pureGraph.getNullableElement(path, true);
1776
+ if (el) {
1777
+ const scope = new DataProductElementScope();
1778
+ scope.element = PackageableElementExplicitReference.create(el);
1779
+ scopes.push(scope);
1738
1780
  }
1739
1781
  }
1740
- // Resolve mapping path from accessPointId and dataProductAccessType
1782
+ return scopes;
1783
+ }
1784
+ async buildDataProductAnalysis(artifact, dataProductPath, pureGraph, accessPointId, dataProductAccessType, projectInfo, graphReport) {
1785
+ const modelAccessPointGroups = artifact.accessPointGroups.filter((group) => group instanceof V1_ModelAccessPointGroupInfo);
1786
+ // Resolve the target access group and mapping path
1741
1787
  let mappingPath;
1742
1788
  let accessGroup = undefined;
1743
1789
  if (dataProductAccessType === DataProductAccessType.MODEL) {
@@ -1754,23 +1800,53 @@ export class V1_PureGraphManager extends AbstractPureGraphManager {
1754
1800
  accessGroup = nativeCtx;
1755
1801
  }
1756
1802
  }
1803
+ if (!accessGroup) {
1804
+ throw new Error(`Can't resolve access point '${accessPointId}' (type: ${dataProductAccessType}) in data product '${dataProductPath}'`);
1805
+ }
1757
1806
  if (!mappingPath) {
1758
- throw new Error(`Can't resolve mapping path for access point '${accessPointId}' (type: ${dataProductAccessType}) in data product '${dataProductPath}'`);
1807
+ throw new Error(`Can't resolve mapping path '${mappingPath}' for access point '${accessPointId}' (type: ${dataProductAccessType}) in data product '${dataProductPath}'`);
1759
1808
  }
1760
- if (!accessGroup) {
1761
- throw new Error(`Can't resolve access group for access point '${accessPointId}' (type: ${dataProductAccessType}) in data product '${dataProductPath}'`);
1809
+ // prevent refetching artifact
1810
+ const includedGenInfos = new Map();
1811
+ if (artifact.nativeModelAccess?.mappingGenerations) {
1812
+ for (const [path, genInfo] of artifact.nativeModelAccess
1813
+ .mappingGenerations) {
1814
+ includedGenInfos.set(path, genInfo);
1815
+ }
1816
+ }
1817
+ for (const group of modelAccessPointGroups) {
1818
+ if (!includedGenInfos.has(group.mappingGeneration.path)) {
1819
+ includedGenInfos.set(group.mappingGeneration.path, group.mappingGeneration);
1820
+ }
1821
+ }
1822
+ const nativeRuntimePaths = new Map();
1823
+ if (artifact.nativeModelAccess?.nativeModelExecutionContexts) {
1824
+ for (const ctx of artifact.nativeModelAccess
1825
+ .nativeModelExecutionContexts) {
1826
+ const rtPath = ctx.runtimeGeneration?.path;
1827
+ if (rtPath) {
1828
+ nativeRuntimePaths.set(ctx.key, rtPath);
1829
+ }
1830
+ }
1762
1831
  }
1763
- // Build the minimal graph using ONLY the elements from the resolved mapping
1764
- const resolvedMappingGenInfo = mappingPath
1765
- ? allMappingGenInfos.get(mappingPath)
1832
+ // Only add a stub for the resolved mapping to the graph
1833
+ const resolvedMappingStub = new V1_Mapping();
1834
+ resolvedMappingStub.package = extractPackagePathFromPath(mappingPath) ?? '';
1835
+ resolvedMappingStub.name = extractElementNameFromPath(mappingPath);
1836
+ // Only add a runtime stub for the resolved native context (if applicable)
1837
+ const resolvedRuntimePath = dataProductAccessType === DataProductAccessType.NATIVE
1838
+ ? nativeRuntimePaths.get(accessPointId)
1766
1839
  : undefined;
1767
- if (!resolvedMappingGenInfo) {
1768
- throw new Error(`Can't find mapping generation info for access point '${accessPointId}' (type: ${dataProductAccessType}) in data product '${dataProductPath}'`);
1840
+ let resolvedRuntimeStub;
1841
+ if (resolvedRuntimePath) {
1842
+ resolvedRuntimeStub = new V1_PackageableRuntime();
1843
+ resolvedRuntimeStub.package =
1844
+ extractPackagePathFromPath(resolvedRuntimePath) ?? '';
1845
+ resolvedRuntimeStub.name =
1846
+ extractElementNameFromPath(resolvedRuntimePath);
1847
+ resolvedRuntimeStub.runtimeValue = new V1_EngineRuntime();
1769
1848
  }
1770
- // Create a dummy mapping for the resolved mapping path
1771
- const dummyMapping = new V1_Mapping();
1772
- dummyMapping.package = extractPackagePathFromPath(mappingPath) ?? '';
1773
- dummyMapping.name = extractElementNameFromPath(mappingPath);
1849
+ // Create a dummy data product element
1774
1850
  // Create a dummy data product element
1775
1851
  const dummyDataProduct = new V1_DataProduct();
1776
1852
  dummyDataProduct.package =
@@ -1778,9 +1854,11 @@ export class V1_PureGraphManager extends AbstractPureGraphManager {
1778
1854
  dummyDataProduct.name = extractElementNameFromPath(dataProductPath);
1779
1855
  dummyDataProduct.title = artifact.dataProduct.title;
1780
1856
  dummyDataProduct.description = artifact.dataProduct.description;
1781
- // Build the minimal graph from the resolved mapping's model elements + dummy mapping + dummy data product
1782
- const graphEntities = resolvedMappingGenInfo.model.elements
1783
- .concat([dummyMapping])
1857
+ // Only load model elements for the resolved mapping
1858
+ const allModelElements = includedGenInfos.get(mappingPath)?.model.elements ?? [];
1859
+ const graphEntities = allModelElements
1860
+ .concat(resolvedMappingStub)
1861
+ .concat(resolvedRuntimeStub ? [resolvedRuntimeStub] : [])
1784
1862
  .concat(dummyDataProduct)
1785
1863
  .filter((el) => !pureGraph.getNullableElement(el.path, false))
1786
1864
  .map((el) => this.elementProtocolToEntity(el));
@@ -1788,30 +1866,74 @@ export class V1_PureGraphManager extends AbstractPureGraphManager {
1788
1866
  origin: new LegendSDLC(projectInfo.groupId, projectInfo.artifactId, projectInfo.versionId),
1789
1867
  }, graphReport);
1790
1868
  const data = pureGraph.getDataProduct(dataProductPath);
1791
- // build access point group
1792
1869
  let exec;
1870
+ if (artifact.nativeModelAccess?.defaultExecutionContext &&
1871
+ artifact.nativeModelAccess.nativeModelExecutionContexts.length) {
1872
+ const na = new NativeModelAccess();
1873
+ na.nativeModelExecutionContexts =
1874
+ artifact.nativeModelAccess.nativeModelExecutionContexts.map((ctxInfo) => {
1875
+ const ctx = new NativeModelExecutionContext();
1876
+ ctx.key = ctxInfo.key;
1877
+ const ctxMappingPath = ctxInfo.mapping;
1878
+ const ctxMapping = ctxMappingPath === mappingPath
1879
+ ? pureGraph.getMapping(ctxMappingPath)
1880
+ : new Mapping(ctxMappingPath);
1881
+ ctx.mapping =
1882
+ PackageableElementExplicitReference.create(ctxMapping);
1883
+ const rtPath = nativeRuntimePaths.get(ctxInfo.key);
1884
+ if (rtPath) {
1885
+ const ctxRuntime = rtPath === resolvedRuntimePath
1886
+ ? pureGraph.getRuntime(rtPath)
1887
+ : new PackageableRuntime(rtPath);
1888
+ ctx.runtime =
1889
+ PackageableElementExplicitReference.create(ctxRuntime);
1890
+ }
1891
+ ctx.__owner = na;
1892
+ return ctx;
1893
+ });
1894
+ const defaultExecutionContext = na.nativeModelExecutionContexts.find((ctx) => ctx.key === artifact.nativeModelAccess?.defaultExecutionContext);
1895
+ if (!defaultExecutionContext) {
1896
+ throw new Error(`Can't find execution context matching default context in '${dataProductPath}'`);
1897
+ }
1898
+ na.defaultExecutionContext = defaultExecutionContext;
1899
+ na.featuredElements = this.resolveArtifactElements(artifact.nativeModelAccess.elements, pureGraph);
1900
+ data.nativeModelAccess = na;
1901
+ }
1902
+ if (modelAccessPointGroups.length > 0) {
1903
+ data.accessPointGroups = modelAccessPointGroups.map((groupInfo) => {
1904
+ const group = new ModelAccessPointGroup();
1905
+ group.id = groupInfo.id;
1906
+ const groupMappingPath = groupInfo.mappingGeneration.path;
1907
+ const groupMapping = groupMappingPath === mappingPath
1908
+ ? pureGraph.getMapping(groupMappingPath)
1909
+ : new Mapping(groupMappingPath);
1910
+ group.mapping =
1911
+ PackageableElementExplicitReference.create(groupMapping);
1912
+ group.featuredElements = this.resolveArtifactElements(groupInfo.elements, pureGraph);
1913
+ return group;
1914
+ });
1915
+ }
1916
+ // Resolve the target exec state
1793
1917
  if (accessGroup instanceof V1_ModelAccessPointGroupInfo) {
1794
- const group = new ModelAccessPointGroup();
1795
- group.id = accessGroup.id;
1796
- data.accessPointGroups = [group];
1797
- group.mapping = PackageableElementExplicitReference.create(pureGraph.getMapping(mappingPath));
1798
- exec = group;
1918
+ exec = data.accessPointGroups.find((g) => g instanceof ModelAccessPointGroup && g.id === accessGroup.id);
1799
1919
  }
1800
1920
  else {
1801
- const nativeAccess = new NativeModelExecutionContext();
1802
- nativeAccess.key = accessGroup.key;
1803
- nativeAccess.mapping = PackageableElementExplicitReference.create(pureGraph.getMapping(mappingPath));
1804
- const na = new NativeModelAccess();
1805
- na.nativeModelExecutionContexts = [nativeAccess];
1806
- data.nativeModelAccess = na;
1807
- exec = nativeAccess;
1921
+ exec = data.nativeModelAccess?.nativeModelExecutionContexts.find((ctx) => ctx.key === accessGroup.key);
1922
+ }
1923
+ if (!exec) {
1924
+ throw new Error(`Can't find execution matching access id in '${dataProductPath}'`);
1808
1925
  }
1809
- // Build MappingModelCoverageAnalysisResult for the resolved mapping only
1926
+ // Build MappingModelCoverageAnalysisResult for all included mappings
1810
1927
  const mappingToMappingCoverageResult = new Map();
1811
- const v1Result = new V1_MappingModelCoverageAnalysisResult();
1812
- v1Result.mappedEntities = resolvedMappingGenInfo.mappedEntities;
1813
- v1Result.model = resolvedMappingGenInfo.model;
1814
- mappingToMappingCoverageResult.set(mappingPath, V1_buildModelCoverageAnalysisResult(v1Result, this, pureGraph.getMapping(mappingPath), resolvedMappingGenInfo.model));
1928
+ for (const [mPath, genInfo] of includedGenInfos) {
1929
+ const v1Result = new V1_MappingModelCoverageAnalysisResult();
1930
+ v1Result.mappedEntities = genInfo.mappedEntities;
1931
+ v1Result.model = genInfo.model;
1932
+ const coverageMapping = mPath === mappingPath
1933
+ ? pureGraph.getMapping(mPath)
1934
+ : new Mapping(mPath);
1935
+ mappingToMappingCoverageResult.set(mPath, V1_buildModelCoverageAnalysisResult(v1Result, this, coverageMapping, genInfo.model));
1936
+ }
1815
1937
  // Build the analysis result
1816
1938
  const result = new DataProductAnalysis();
1817
1939
  result.path = dataProductPath;