@finos/legend-graph 32.5.1 → 32.5.3

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 (60) 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-manager/AbstractPureGraphManager.d.ts +1 -0
  6. package/lib/graph-manager/AbstractPureGraphManager.d.ts.map +1 -1
  7. package/lib/graph-manager/AbstractPureGraphManager.js.map +1 -1
  8. package/lib/graph-manager/action/analytics/data-product/DataProductAnalysis.d.ts +4 -4
  9. package/lib/graph-manager/action/analytics/data-product/DataProductAnalysis.d.ts.map +1 -1
  10. package/lib/graph-manager/action/analytics/data-product/DataProductAnalysis.js.map +1 -1
  11. package/lib/graph-manager/action/query/Query.d.ts +2 -0
  12. package/lib/graph-manager/action/query/Query.d.ts.map +1 -1
  13. package/lib/graph-manager/action/query/Query.js +2 -0
  14. package/lib/graph-manager/action/query/Query.js.map +1 -1
  15. package/lib/graph-manager/protocol/pure/v1/V1_PureGraphManager.d.ts +22 -1
  16. package/lib/graph-manager/protocol/pure/v1/V1_PureGraphManager.d.ts.map +1 -1
  17. package/lib/graph-manager/protocol/pure/v1/V1_PureGraphManager.js +289 -102
  18. package/lib/graph-manager/protocol/pure/v1/V1_PureGraphManager.js.map +1 -1
  19. package/lib/graph-manager/protocol/pure/v1/engine/V1_EngineHelper.d.ts.map +1 -1
  20. package/lib/graph-manager/protocol/pure/v1/engine/V1_EngineHelper.js +3 -0
  21. package/lib/graph-manager/protocol/pure/v1/engine/V1_EngineHelper.js.map +1 -1
  22. package/lib/graph-manager/protocol/pure/v1/engine/V1_EngineServerClient.d.ts +1 -0
  23. package/lib/graph-manager/protocol/pure/v1/engine/V1_EngineServerClient.d.ts.map +1 -1
  24. package/lib/graph-manager/protocol/pure/v1/engine/V1_EngineServerClient.js +2 -0
  25. package/lib/graph-manager/protocol/pure/v1/engine/V1_EngineServerClient.js.map +1 -1
  26. package/lib/graph-manager/protocol/pure/v1/engine/V1_GraphManagerEngine.d.ts +1 -0
  27. package/lib/graph-manager/protocol/pure/v1/engine/V1_GraphManagerEngine.d.ts.map +1 -1
  28. package/lib/graph-manager/protocol/pure/v1/engine/V1_RemoteEngine.d.ts +1 -0
  29. package/lib/graph-manager/protocol/pure/v1/engine/V1_RemoteEngine.d.ts.map +1 -1
  30. package/lib/graph-manager/protocol/pure/v1/engine/V1_RemoteEngine.js +3 -0
  31. package/lib/graph-manager/protocol/pure/v1/engine/V1_RemoteEngine.js.map +1 -1
  32. package/lib/graph-manager/protocol/pure/v1/engine/analytics/V1_MappingModelCoverageAnalysis.d.ts.map +1 -1
  33. package/lib/graph-manager/protocol/pure/v1/engine/analytics/V1_MappingModelCoverageAnalysis.js +7 -0
  34. package/lib/graph-manager/protocol/pure/v1/engine/analytics/V1_MappingModelCoverageAnalysis.js.map +1 -1
  35. package/lib/graph-manager/protocol/pure/v1/engine/query/V1_Query.d.ts +2 -1
  36. package/lib/graph-manager/protocol/pure/v1/engine/query/V1_Query.d.ts.map +1 -1
  37. package/lib/graph-manager/protocol/pure/v1/engine/query/V1_Query.js +3 -1
  38. package/lib/graph-manager/protocol/pure/v1/engine/query/V1_Query.js.map +1 -1
  39. package/lib/graph-manager/protocol/pure/v1/transformation/pureGraph/to/helpers/V1_DataProductBuilder.d.ts +1 -1
  40. package/lib/graph-manager/protocol/pure/v1/transformation/pureGraph/to/helpers/V1_DataProductBuilder.d.ts.map +1 -1
  41. package/lib/graph-manager/protocol/pure/v1/transformation/pureGraph/to/helpers/V1_DataProductBuilder.js +6 -6
  42. package/lib/graph-manager/protocol/pure/v1/transformation/pureGraph/to/helpers/V1_DataProductBuilder.js.map +1 -1
  43. package/lib/graph-manager/protocol/pure/v1/transformation/pureProtocol/V1_PureProtocolSerialization.d.ts.map +1 -1
  44. package/lib/graph-manager/protocol/pure/v1/transformation/pureProtocol/V1_PureProtocolSerialization.js +14 -10
  45. package/lib/graph-manager/protocol/pure/v1/transformation/pureProtocol/V1_PureProtocolSerialization.js.map +1 -1
  46. package/lib/package.json +1 -1
  47. package/package.json +3 -3
  48. package/src/graph/metamodel/pure/dataProduct/DataProduct.ts +13 -5
  49. package/src/graph-manager/AbstractPureGraphManager.ts +4 -0
  50. package/src/graph-manager/action/analytics/data-product/DataProductAnalysis.ts +11 -4
  51. package/src/graph-manager/action/query/Query.ts +2 -0
  52. package/src/graph-manager/protocol/pure/v1/V1_PureGraphManager.ts +690 -499
  53. package/src/graph-manager/protocol/pure/v1/engine/V1_EngineHelper.ts +3 -0
  54. package/src/graph-manager/protocol/pure/v1/engine/V1_EngineServerClient.ts +12 -0
  55. package/src/graph-manager/protocol/pure/v1/engine/V1_GraphManagerEngine.ts +5 -0
  56. package/src/graph-manager/protocol/pure/v1/engine/V1_RemoteEngine.ts +10 -0
  57. package/src/graph-manager/protocol/pure/v1/engine/analytics/V1_MappingModelCoverageAnalysis.ts +7 -0
  58. package/src/graph-manager/protocol/pure/v1/engine/query/V1_Query.ts +3 -1
  59. package/src/graph-manager/protocol/pure/v1/transformation/pureGraph/to/helpers/V1_DataProductBuilder.ts +6 -3
  60. package/src/graph-manager/protocol/pure/v1/transformation/pureProtocol/V1_PureProtocolSerialization.ts +21 -23
@@ -51,8 +51,9 @@ import {
51
51
  type ExecutionOptions,
52
52
  type ServiceRegistrationOptions,
53
53
  } from '../../../../graph-manager/AbstractPureGraphManager.js';
54
- import type { Mapping } from '../../../../graph/metamodel/pure/packageableElements/mapping/Mapping.js';
54
+ import { Mapping } from '../../../../graph/metamodel/pure/packageableElements/mapping/Mapping.js';
55
55
  import type { Runtime } from '../../../../graph/metamodel/pure/packageableElements/runtime/Runtime.js';
56
+ import { PackageableRuntime } from '../../../../graph/metamodel/pure/packageableElements/runtime/PackageableRuntime.js';
56
57
  import type { PackageableElement } from '../../../../graph/metamodel/pure/packageableElements/PackageableElement.js';
57
58
  import {
58
59
  type SystemModel,
@@ -348,6 +349,7 @@ import { V1_UserListOwnership } from './model/packageableElements/service/V1_Ser
348
349
  import { V1_PureSingleExecution } from './model/packageableElements/service/V1_ServiceExecution.js';
349
350
  import {
350
351
  type V1_Runtime,
352
+ V1_EngineRuntime,
351
353
  V1_RuntimePointer,
352
354
  } from './model/packageableElements/runtime/V1_Runtime.js';
353
355
  import type { TestDebug } from '../../../../graph/metamodel/pure/test/result/DebugTestsResult.js';
@@ -379,10 +381,14 @@ import {
379
381
  DataProductAnalysis,
380
382
  } from '../../../action/analytics/data-product/DataProductAnalysis.js';
381
383
  import {
384
+ AccessPointGroup,
382
385
  DataProductAccessType,
386
+ DataProductElementScope,
387
+ LakehouseAccessPoint,
383
388
  ModelAccessPointGroup,
384
389
  NativeModelAccess,
385
390
  NativeModelExecutionContext,
391
+ type DataProductElement,
386
392
  } from '../../../../graph/metamodel/pure/dataProduct/DataProduct.js';
387
393
  import { V1_MemSQLFunction } from './model/packageableElements/function/V1_MemSQLFunction.js';
388
394
  import { LineageModel } from '../../../../graph/metamodel/pure/lineage/LineageModel.js';
@@ -403,6 +409,12 @@ import { IngestDefinition } from '../../../../graph/metamodel/pure/packageableEl
403
409
  import { Database } from '../../../../graph/metamodel/pure/packageableElements/store/relational/model/Database.js';
404
410
  import { V1_createAccessorFromPackageableElement } from './helpers/V1_AccessorHelper.js';
405
411
 
412
+ /**
413
+ * Number of elements to process synchronously before yielding to the event loop.
414
+ * This avoids per-element setTimeout overhead while keeping the UI responsive.
415
+ */
416
+ const GRAPH_BUILDER_BATCH_SIZE = 100;
417
+
406
418
  class V1_PureModelContextDataIndex {
407
419
  elements: V1_PackageableElement[] = [];
408
420
  nativeElements: V1_PackageableElement[] = [];
@@ -1297,46 +1309,57 @@ export class V1_PureGraphManager extends AbstractPureGraphManager {
1297
1309
  graph.allElements.map((el) => el.path),
1298
1310
  );
1299
1311
 
1300
- await Promise.all(
1301
- inputs.flatMap(async (input) => {
1302
- // create the package cache
1303
- const packageCache = new Map<string, Package>();
1304
- await Promise.all(
1305
- input.data.nativeElements.map((element) => {
1306
- return this.visitWithGraphBuilderErrorHandling(
1307
- element,
1308
- new V1_ElementFirstPassBuilder(
1309
- this.getBuilderContext(graph, input.model, element, options),
1310
- packageCache,
1311
- elementPathCache,
1312
- ),
1313
- );
1314
- }),
1315
- );
1316
- await Promise.all(
1317
- this.graphBuilderExtensions.sortedExtraElementBuilders.flatMap(
1318
- (builder) =>
1319
- (input.data.otherElementsByBuilder.get(builder) ?? []).map(
1320
- (element) => {
1321
- return this.visitWithGraphBuilderErrorHandling(
1322
- element,
1323
- new V1_ElementFirstPassBuilder(
1324
- this.getBuilderContext(
1325
- graph,
1326
- input.model,
1327
- element,
1328
- options,
1329
- ),
1330
- packageCache,
1331
- elementPathCache,
1332
- ),
1333
- );
1334
- },
1335
- ),
1336
- ),
1312
+ // NOTE: We must index ALL native elements across ALL inputs before indexing
1313
+ // plugin-contributed ("other") elements. Plugin elements
1314
+ // may resolve references to native elements (e.g. Mapping, Runtime) from
1315
+ // other inputs during their first pass. If we process each input fully
1316
+ // (native + other) before moving to the next, a plugin element in input[0]
1317
+ // could fail to find a native element that only exists in input[1].
1318
+ const packageCaches = new Map<
1319
+ V1_PureGraphBuilderInput,
1320
+ Map<string, Package>
1321
+ >();
1322
+
1323
+ const createFirstPassBuilder = (
1324
+ input: V1_PureGraphBuilderInput,
1325
+ packageCache: Map<string, Package>,
1326
+ element: V1_PackageableElement,
1327
+ ): V1_ElementFirstPassBuilder =>
1328
+ new V1_ElementFirstPassBuilder(
1329
+ this.getBuilderContext(graph, input.model, element, options),
1330
+ packageCache,
1331
+ elementPathCache,
1332
+ );
1333
+
1334
+ for (const input of inputs) {
1335
+ const packageCache = new Map<string, Package>();
1336
+ packageCaches.set(input, packageCache);
1337
+
1338
+ // Phase 1: index native elements for this input
1339
+ await this.runBatchedLoop(input.data.nativeElements, (element) =>
1340
+ this.visitWithGraphBuilderErrorHandling(
1341
+ element,
1342
+ createFirstPassBuilder(input, packageCache, element),
1343
+ ),
1344
+ );
1345
+ }
1346
+
1347
+ // Phase 2: index other (plugin-contributed) elements across all inputs,
1348
+ // now that all native elements have been indexed
1349
+ for (const input of inputs) {
1350
+ const packageCache = guaranteeNonNullable(packageCaches.get(input));
1351
+
1352
+ const otherElements =
1353
+ this.graphBuilderExtensions.sortedExtraElementBuilders.flatMap(
1354
+ (builder) => input.data.otherElementsByBuilder.get(builder) ?? [],
1337
1355
  );
1338
- }),
1339
- );
1356
+ await this.runBatchedLoop(otherElements, (element) =>
1357
+ this.visitWithGraphBuilderErrorHandling(
1358
+ element,
1359
+ createFirstPassBuilder(input, packageCache, element),
1360
+ ),
1361
+ );
1362
+ }
1340
1363
  }
1341
1364
 
1342
1365
  private async buildTypes(
@@ -1345,128 +1368,78 @@ export class V1_PureGraphManager extends AbstractPureGraphManager {
1345
1368
  options?: GraphBuilderOptions,
1346
1369
  ): Promise<void> {
1347
1370
  // Second pass
1348
- await Promise.all(
1349
- inputs.flatMap((input) =>
1350
- input.data.profiles.map((element) =>
1351
- this.visitWithGraphBuilderErrorHandling(
1352
- element,
1353
- new V1_ElementSecondPassBuilder(
1354
- this.getBuilderContext(graph, input.model, element, options),
1355
- ),
1356
- ),
1357
- ),
1358
- ),
1371
+ await this.processElementsInBatches(
1372
+ graph,
1373
+ inputs,
1374
+ (data) => data.profiles,
1375
+ (ctx) => new V1_ElementSecondPassBuilder(ctx),
1376
+ options,
1359
1377
  );
1360
- await Promise.all(
1361
- inputs.flatMap((input) =>
1362
- input.data.classes.map((element) =>
1363
- this.visitWithGraphBuilderErrorHandling(
1364
- element,
1365
- new V1_ElementSecondPassBuilder(
1366
- this.getBuilderContext(graph, input.model, element, options),
1367
- ),
1368
- ),
1369
- ),
1370
- ),
1378
+ await this.processElementsInBatches(
1379
+ graph,
1380
+ inputs,
1381
+ (data) => data.classes,
1382
+ (ctx) => new V1_ElementSecondPassBuilder(ctx),
1383
+ options,
1371
1384
  );
1372
- await Promise.all(
1373
- inputs.flatMap((input) =>
1374
- input.data.enumerations.map((element) =>
1375
- this.visitWithGraphBuilderErrorHandling(
1376
- element,
1377
- new V1_ElementSecondPassBuilder(
1378
- this.getBuilderContext(graph, input.model, element, options),
1379
- ),
1380
- ),
1381
- ),
1382
- ),
1385
+ await this.processElementsInBatches(
1386
+ graph,
1387
+ inputs,
1388
+ (data) => data.enumerations,
1389
+ (ctx) => new V1_ElementSecondPassBuilder(ctx),
1390
+ options,
1383
1391
  );
1384
- await Promise.all(
1385
- inputs.flatMap((input) =>
1386
- input.data.measures.map((element) =>
1387
- this.visitWithGraphBuilderErrorHandling(
1388
- element,
1389
- new V1_ElementSecondPassBuilder(
1390
- this.getBuilderContext(graph, input.model, element, options),
1391
- ),
1392
- ),
1393
- ),
1394
- ),
1392
+ await this.processElementsInBatches(
1393
+ graph,
1394
+ inputs,
1395
+ (data) => data.measures,
1396
+ (ctx) => new V1_ElementSecondPassBuilder(ctx),
1397
+ options,
1395
1398
  );
1396
- await Promise.all(
1397
- inputs.flatMap((input) =>
1398
- input.data.functions.map((element) =>
1399
- this.visitWithGraphBuilderErrorHandling(
1400
- element,
1401
- new V1_ElementSecondPassBuilder(
1402
- this.getBuilderContext(graph, input.model, element, options),
1403
- ),
1404
- ),
1405
- ),
1406
- ),
1399
+ await this.processElementsInBatches(
1400
+ graph,
1401
+ inputs,
1402
+ (data) => data.functions,
1403
+ (ctx) => new V1_ElementSecondPassBuilder(ctx),
1404
+ options,
1407
1405
  );
1408
1406
  // Third pass
1409
- await Promise.all(
1410
- inputs.flatMap((input) =>
1411
- input.data.classes.map((element) =>
1412
- this.visitWithGraphBuilderErrorHandling(
1413
- element,
1414
- new V1_ElementThirdPassBuilder(
1415
- this.getBuilderContext(graph, input.model, element, options),
1416
- ),
1417
- ),
1418
- ),
1419
- ),
1407
+ await this.processElementsInBatches(
1408
+ graph,
1409
+ inputs,
1410
+ (data) => data.classes,
1411
+ (ctx) => new V1_ElementThirdPassBuilder(ctx),
1412
+ options,
1420
1413
  );
1421
- await Promise.all(
1422
- inputs.flatMap((input) =>
1423
- input.data.associations.map((element) =>
1424
- this.visitWithGraphBuilderErrorHandling(
1425
- element,
1426
- new V1_ElementThirdPassBuilder(
1427
- this.getBuilderContext(graph, input.model, element, options),
1428
- ),
1429
- ),
1430
- ),
1431
- ),
1414
+ await this.processElementsInBatches(
1415
+ graph,
1416
+ inputs,
1417
+ (data) => data.associations,
1418
+ (ctx) => new V1_ElementThirdPassBuilder(ctx),
1419
+ options,
1432
1420
  );
1433
1421
  // Fourth Pass
1434
- await Promise.all(
1435
- inputs.flatMap((input) =>
1436
- input.data.classes.map((element) =>
1437
- this.visitWithGraphBuilderErrorHandling(
1438
- element,
1439
- new V1_ElementFourthPassBuilder(
1440
- this.getBuilderContext(graph, input.model, element, options),
1441
- ),
1442
- ),
1443
- ),
1444
- ),
1422
+ await this.processElementsInBatches(
1423
+ graph,
1424
+ inputs,
1425
+ (data) => data.classes,
1426
+ (ctx) => new V1_ElementFourthPassBuilder(ctx),
1427
+ options,
1445
1428
  );
1446
- await Promise.all(
1447
- inputs.flatMap((input) =>
1448
- input.data.associations.map((element) =>
1449
- this.visitWithGraphBuilderErrorHandling(
1450
- element,
1451
- new V1_ElementFourthPassBuilder(
1452
- this.getBuilderContext(graph, input.model, element, options),
1453
- ),
1454
- ),
1455
- ),
1456
- ),
1429
+ await this.processElementsInBatches(
1430
+ graph,
1431
+ inputs,
1432
+ (data) => data.associations,
1433
+ (ctx) => new V1_ElementFourthPassBuilder(ctx),
1434
+ options,
1457
1435
  );
1458
1436
  // Fifth pass
1459
- await Promise.all(
1460
- inputs.flatMap((input) =>
1461
- input.data.classes.map((element) =>
1462
- this.visitWithGraphBuilderErrorHandling(
1463
- element,
1464
- new V1_ElementFifthPassBuilder(
1465
- this.getBuilderContext(graph, input.model, element, options),
1466
- ),
1467
- ),
1468
- ),
1469
- ),
1437
+ await this.processElementsInBatches(
1438
+ graph,
1439
+ inputs,
1440
+ (data) => data.classes,
1441
+ (ctx) => new V1_ElementFifthPassBuilder(ctx),
1442
+ options,
1470
1443
  );
1471
1444
  }
1472
1445
 
@@ -1475,17 +1448,12 @@ export class V1_PureGraphManager extends AbstractPureGraphManager {
1475
1448
  inputs: V1_PureGraphBuilderInput[],
1476
1449
  options?: GraphBuilderOptions,
1477
1450
  ): Promise<void> {
1478
- await Promise.all(
1479
- inputs.flatMap((input) =>
1480
- input.data.functionActivators.map((element) =>
1481
- this.visitWithGraphBuilderErrorHandling(
1482
- element,
1483
- new V1_ElementSecondPassBuilder(
1484
- this.getBuilderContext(graph, input.model, element, options),
1485
- ),
1486
- ),
1487
- ),
1488
- ),
1451
+ await this.processElementsInBatches(
1452
+ graph,
1453
+ inputs,
1454
+ (data) => data.functionActivators,
1455
+ (ctx) => new V1_ElementSecondPassBuilder(ctx),
1456
+ options,
1489
1457
  );
1490
1458
  }
1491
1459
 
@@ -1494,53 +1462,33 @@ export class V1_PureGraphManager extends AbstractPureGraphManager {
1494
1462
  inputs: V1_PureGraphBuilderInput[],
1495
1463
  options?: GraphBuilderOptions,
1496
1464
  ): Promise<void> {
1497
- await Promise.all(
1498
- inputs.flatMap((input) =>
1499
- input.data.stores.map((element) =>
1500
- this.visitWithGraphBuilderErrorHandling(
1501
- element,
1502
- new V1_ElementSecondPassBuilder(
1503
- this.getBuilderContext(graph, input.model, element, options),
1504
- ),
1505
- ),
1506
- ),
1507
- ),
1465
+ await this.processElementsInBatches(
1466
+ graph,
1467
+ inputs,
1468
+ (data) => data.stores,
1469
+ (ctx) => new V1_ElementSecondPassBuilder(ctx),
1470
+ options,
1508
1471
  );
1509
- await Promise.all(
1510
- inputs.flatMap((input) =>
1511
- input.data.stores.map((element) =>
1512
- this.visitWithGraphBuilderErrorHandling(
1513
- element,
1514
- new V1_ElementThirdPassBuilder(
1515
- this.getBuilderContext(graph, input.model, element, options),
1516
- ),
1517
- ),
1518
- ),
1519
- ),
1472
+ await this.processElementsInBatches(
1473
+ graph,
1474
+ inputs,
1475
+ (data) => data.stores,
1476
+ (ctx) => new V1_ElementThirdPassBuilder(ctx),
1477
+ options,
1520
1478
  );
1521
- await Promise.all(
1522
- inputs.flatMap((input) =>
1523
- input.data.stores.map((element) =>
1524
- this.visitWithGraphBuilderErrorHandling(
1525
- element,
1526
- new V1_ElementFourthPassBuilder(
1527
- this.getBuilderContext(graph, input.model, element, options),
1528
- ),
1529
- ),
1530
- ),
1531
- ),
1479
+ await this.processElementsInBatches(
1480
+ graph,
1481
+ inputs,
1482
+ (data) => data.stores,
1483
+ (ctx) => new V1_ElementFourthPassBuilder(ctx),
1484
+ options,
1532
1485
  );
1533
- await Promise.all(
1534
- inputs.flatMap((input) =>
1535
- input.data.stores.map((element) =>
1536
- this.visitWithGraphBuilderErrorHandling(
1537
- element,
1538
- new V1_ElementFifthPassBuilder(
1539
- this.getBuilderContext(graph, input.model, element, options),
1540
- ),
1541
- ),
1542
- ),
1543
- ),
1486
+ await this.processElementsInBatches(
1487
+ graph,
1488
+ inputs,
1489
+ (data) => data.stores,
1490
+ (ctx) => new V1_ElementFifthPassBuilder(ctx),
1491
+ options,
1544
1492
  );
1545
1493
  }
1546
1494
 
@@ -1549,41 +1497,26 @@ export class V1_PureGraphManager extends AbstractPureGraphManager {
1549
1497
  inputs: V1_PureGraphBuilderInput[],
1550
1498
  options?: GraphBuilderOptions,
1551
1499
  ): Promise<void> {
1552
- await Promise.all(
1553
- inputs.flatMap((input) =>
1554
- input.data.mappings.map((element) =>
1555
- this.visitWithGraphBuilderErrorHandling(
1556
- element,
1557
- new V1_ElementSecondPassBuilder(
1558
- this.getBuilderContext(graph, input.model, element, options),
1559
- ),
1560
- ),
1561
- ),
1562
- ),
1500
+ await this.processElementsInBatches(
1501
+ graph,
1502
+ inputs,
1503
+ (data) => data.mappings,
1504
+ (ctx) => new V1_ElementSecondPassBuilder(ctx),
1505
+ options,
1563
1506
  );
1564
- await Promise.all(
1565
- inputs.flatMap((input) =>
1566
- input.data.mappings.map((element) =>
1567
- this.visitWithGraphBuilderErrorHandling(
1568
- element,
1569
- new V1_ElementThirdPassBuilder(
1570
- this.getBuilderContext(graph, input.model, element, options),
1571
- ),
1572
- ),
1573
- ),
1574
- ),
1507
+ await this.processElementsInBatches(
1508
+ graph,
1509
+ inputs,
1510
+ (data) => data.mappings,
1511
+ (ctx) => new V1_ElementThirdPassBuilder(ctx),
1512
+ options,
1575
1513
  );
1576
- await Promise.all(
1577
- inputs.flatMap((input) =>
1578
- input.data.mappings.map((element) =>
1579
- this.visitWithGraphBuilderErrorHandling(
1580
- element,
1581
- new V1_ElementFourthPassBuilder(
1582
- this.getBuilderContext(graph, input.model, element, options),
1583
- ),
1584
- ),
1585
- ),
1586
- ),
1514
+ await this.processElementsInBatches(
1515
+ graph,
1516
+ inputs,
1517
+ (data) => data.mappings,
1518
+ (ctx) => new V1_ElementFourthPassBuilder(ctx),
1519
+ options,
1587
1520
  );
1588
1521
  }
1589
1522
 
@@ -1593,29 +1526,19 @@ export class V1_PureGraphManager extends AbstractPureGraphManager {
1593
1526
  options?: GraphBuilderOptions,
1594
1527
  ): Promise<void> {
1595
1528
  // NOTE: connections must be built before runtimes
1596
- await Promise.all(
1597
- inputs.flatMap((input) =>
1598
- input.data.connections.map((element) =>
1599
- this.visitWithGraphBuilderErrorHandling(
1600
- element,
1601
- new V1_ElementSecondPassBuilder(
1602
- this.getBuilderContext(graph, input.model, element, options),
1603
- ),
1604
- ),
1605
- ),
1606
- ),
1529
+ await this.processElementsInBatches(
1530
+ graph,
1531
+ inputs,
1532
+ (data) => data.connections,
1533
+ (ctx) => new V1_ElementSecondPassBuilder(ctx),
1534
+ options,
1607
1535
  );
1608
- await Promise.all(
1609
- inputs.flatMap((input) =>
1610
- input.data.runtimes.map((element) =>
1611
- this.visitWithGraphBuilderErrorHandling(
1612
- element,
1613
- new V1_ElementSecondPassBuilder(
1614
- this.getBuilderContext(graph, input.model, element, options),
1615
- ),
1616
- ),
1617
- ),
1618
- ),
1536
+ await this.processElementsInBatches(
1537
+ graph,
1538
+ inputs,
1539
+ (data) => data.runtimes,
1540
+ (ctx) => new V1_ElementSecondPassBuilder(ctx),
1541
+ options,
1619
1542
  );
1620
1543
  }
1621
1544
 
@@ -1624,29 +1547,19 @@ export class V1_PureGraphManager extends AbstractPureGraphManager {
1624
1547
  inputs: V1_PureGraphBuilderInput[],
1625
1548
  options?: GraphBuilderOptions,
1626
1549
  ): Promise<void> {
1627
- await Promise.all(
1628
- inputs.flatMap((input) =>
1629
- input.data.services.map((element) =>
1630
- this.visitWithGraphBuilderErrorHandling(
1631
- element,
1632
- new V1_ElementSecondPassBuilder(
1633
- this.getBuilderContext(graph, input.model, element, options),
1634
- ),
1635
- ),
1636
- ),
1637
- ),
1550
+ await this.processElementsInBatches(
1551
+ graph,
1552
+ inputs,
1553
+ (data) => data.services,
1554
+ (ctx) => new V1_ElementSecondPassBuilder(ctx),
1555
+ options,
1638
1556
  );
1639
- await Promise.all(
1640
- inputs.flatMap((input) =>
1641
- input.data.executionEnvironments.map((element) =>
1642
- this.visitWithGraphBuilderErrorHandling(
1643
- element,
1644
- new V1_ElementSecondPassBuilder(
1645
- this.getBuilderContext(graph, input.model, element, options),
1646
- ),
1647
- ),
1648
- ),
1649
- ),
1557
+ await this.processElementsInBatches(
1558
+ graph,
1559
+ inputs,
1560
+ (data) => data.executionEnvironments,
1561
+ (ctx) => new V1_ElementSecondPassBuilder(ctx),
1562
+ options,
1650
1563
  );
1651
1564
  }
1652
1565
 
@@ -1655,17 +1568,12 @@ export class V1_PureGraphManager extends AbstractPureGraphManager {
1655
1568
  inputs: V1_PureGraphBuilderInput[],
1656
1569
  options?: GraphBuilderOptions,
1657
1570
  ): Promise<void> {
1658
- await Promise.all(
1659
- inputs.flatMap((input) =>
1660
- input.data.dataElements.map((element) =>
1661
- this.visitWithGraphBuilderErrorHandling(
1662
- element,
1663
- new V1_ElementSecondPassBuilder(
1664
- this.getBuilderContext(graph, input.model, element, options),
1665
- ),
1666
- ),
1667
- ),
1668
- ),
1571
+ await this.processElementsInBatches(
1572
+ graph,
1573
+ inputs,
1574
+ (data) => data.dataElements,
1575
+ (ctx) => new V1_ElementSecondPassBuilder(ctx),
1576
+ options,
1669
1577
  );
1670
1578
  }
1671
1579
 
@@ -1674,17 +1582,12 @@ export class V1_PureGraphManager extends AbstractPureGraphManager {
1674
1582
  inputs: V1_PureGraphBuilderInput[],
1675
1583
  options?: GraphBuilderOptions,
1676
1584
  ): Promise<void> {
1677
- await Promise.all(
1678
- inputs.flatMap((input) =>
1679
- input.data.products.map((element) =>
1680
- this.visitWithGraphBuilderErrorHandling(
1681
- element,
1682
- new V1_ElementSecondPassBuilder(
1683
- this.getBuilderContext(graph, input.model, element, options),
1684
- ),
1685
- ),
1686
- ),
1687
- ),
1585
+ await this.processElementsInBatches(
1586
+ graph,
1587
+ inputs,
1588
+ (data) => data.products,
1589
+ (ctx) => new V1_ElementSecondPassBuilder(ctx),
1590
+ options,
1688
1591
  );
1689
1592
  }
1690
1593
 
@@ -1693,17 +1596,12 @@ export class V1_PureGraphManager extends AbstractPureGraphManager {
1693
1596
  inputs: V1_PureGraphBuilderInput[],
1694
1597
  options?: GraphBuilderOptions,
1695
1598
  ): Promise<void> {
1696
- await Promise.all(
1697
- inputs.flatMap((input) =>
1698
- input.data.fileGenerations.map((element) =>
1699
- this.visitWithGraphBuilderErrorHandling(
1700
- element,
1701
- new V1_ElementSecondPassBuilder(
1702
- this.getBuilderContext(graph, input.model, element, options),
1703
- ),
1704
- ),
1705
- ),
1706
- ),
1599
+ await this.processElementsInBatches(
1600
+ graph,
1601
+ inputs,
1602
+ (data) => data.fileGenerations,
1603
+ (ctx) => new V1_ElementSecondPassBuilder(ctx),
1604
+ options,
1707
1605
  );
1708
1606
  }
1709
1607
 
@@ -1712,17 +1610,12 @@ export class V1_PureGraphManager extends AbstractPureGraphManager {
1712
1610
  inputs: V1_PureGraphBuilderInput[],
1713
1611
  options?: GraphBuilderOptions,
1714
1612
  ): Promise<void> {
1715
- await Promise.all(
1716
- inputs.flatMap((input) =>
1717
- input.data.generationSpecifications.map((element) =>
1718
- this.visitWithGraphBuilderErrorHandling(
1719
- element,
1720
- new V1_ElementSecondPassBuilder(
1721
- this.getBuilderContext(graph, input.model, element, options),
1722
- ),
1723
- ),
1724
- ),
1725
- ),
1613
+ await this.processElementsInBatches(
1614
+ graph,
1615
+ inputs,
1616
+ (data) => data.generationSpecifications,
1617
+ (ctx) => new V1_ElementSecondPassBuilder(ctx),
1618
+ options,
1726
1619
  );
1727
1620
  }
1728
1621
 
@@ -1731,17 +1624,12 @@ export class V1_PureGraphManager extends AbstractPureGraphManager {
1731
1624
  inputs: V1_PureGraphBuilderInput[],
1732
1625
  options?: GraphBuilderOptions,
1733
1626
  ): Promise<void> {
1734
- await Promise.all(
1735
- inputs.flatMap((input) =>
1736
- input.data.sectionIndices.map((element) =>
1737
- this.visitWithGraphBuilderErrorHandling(
1738
- element,
1739
- new V1_ElementSecondPassBuilder(
1740
- this.getBuilderContext(graph, input.model, element, options),
1741
- ),
1742
- ),
1743
- ),
1744
- ),
1627
+ await this.processElementsInBatches(
1628
+ graph,
1629
+ inputs,
1630
+ (data) => data.sectionIndices,
1631
+ (ctx) => new V1_ElementSecondPassBuilder(ctx),
1632
+ options,
1745
1633
  );
1746
1634
  }
1747
1635
 
@@ -1750,82 +1638,90 @@ export class V1_PureGraphManager extends AbstractPureGraphManager {
1750
1638
  inputs: V1_PureGraphBuilderInput[],
1751
1639
  options?: GraphBuilderOptions,
1752
1640
  ): Promise<void> {
1753
- await Promise.all(
1754
- this.graphBuilderExtensions.sortedExtraElementBuilders.map(
1755
- async (builder) => {
1756
- await Promise.all(
1757
- inputs.flatMap((input) =>
1758
- (input.data.otherElementsByBuilder.get(builder) ?? []).map(
1759
- (element) =>
1760
- this.visitWithGraphBuilderErrorHandling(
1761
- element,
1762
- new V1_ElementSecondPassBuilder(
1763
- this.getBuilderContext(
1764
- graph,
1765
- input.model,
1766
- element,
1767
- options,
1768
- ),
1769
- ),
1770
- ),
1771
- ),
1772
- ),
1773
- );
1774
- await Promise.all(
1775
- inputs.flatMap((input) =>
1776
- (input.data.otherElementsByBuilder.get(builder) ?? []).map(
1777
- (element) =>
1778
- this.visitWithGraphBuilderErrorHandling(
1779
- element,
1780
- new V1_ElementThirdPassBuilder(
1781
- this.getBuilderContext(
1782
- graph,
1783
- input.model,
1784
- element,
1785
- options,
1786
- ),
1787
- ),
1788
- ),
1789
- ),
1790
- ),
1791
- );
1792
- await Promise.all(
1793
- inputs.flatMap((input) =>
1794
- (input.data.otherElementsByBuilder.get(builder) ?? []).map(
1795
- (element) =>
1796
- this.visitWithGraphBuilderErrorHandling(
1797
- element,
1798
- new V1_ElementFourthPassBuilder(
1799
- this.getBuilderContext(
1800
- graph,
1801
- input.model,
1802
- element,
1803
- options,
1804
- ),
1805
- ),
1806
- ),
1807
- ),
1808
- ),
1809
- );
1810
- await Promise.all(
1811
- inputs.flatMap((input) =>
1812
- (input.data.otherElementsByBuilder.get(builder) ?? []).map(
1813
- (element) =>
1814
- this.visitWithGraphBuilderErrorHandling(
1815
- element,
1816
- new V1_ElementFifthPassBuilder(
1817
- this.getBuilderContext(
1818
- graph,
1819
- input.model,
1820
- element,
1821
- options,
1822
- ),
1823
- ),
1824
- ),
1825
- ),
1826
- ),
1827
- );
1828
- },
1641
+ for (const builder of this.graphBuilderExtensions
1642
+ .sortedExtraElementBuilders) {
1643
+ const getElements = (
1644
+ data: V1_PureModelContextDataIndex,
1645
+ ): V1_PackageableElement[] =>
1646
+ data.otherElementsByBuilder.get(builder) ?? [];
1647
+ await this.processElementsInBatches(
1648
+ graph,
1649
+ inputs,
1650
+ getElements,
1651
+ (ctx) => new V1_ElementSecondPassBuilder(ctx),
1652
+ options,
1653
+ );
1654
+ await this.processElementsInBatches(
1655
+ graph,
1656
+ inputs,
1657
+ getElements,
1658
+ (ctx) => new V1_ElementThirdPassBuilder(ctx),
1659
+ options,
1660
+ );
1661
+ await this.processElementsInBatches(
1662
+ graph,
1663
+ inputs,
1664
+ getElements,
1665
+ (ctx) => new V1_ElementFourthPassBuilder(ctx),
1666
+ options,
1667
+ );
1668
+ await this.processElementsInBatches(
1669
+ graph,
1670
+ inputs,
1671
+ getElements,
1672
+ (ctx) => new V1_ElementFifthPassBuilder(ctx),
1673
+ options,
1674
+ );
1675
+ }
1676
+ }
1677
+
1678
+ /**
1679
+ * Run a callback for each item in the array, processing items in batches
1680
+ * of {@link GRAPH_BUILDER_BATCH_SIZE} and yielding to the event loop between
1681
+ * batches to keep the UI responsive.
1682
+ */
1683
+ private async runBatchedLoop<T>(
1684
+ items: T[],
1685
+ process: (item: T) => void,
1686
+ ): Promise<void> {
1687
+ for (let i = 0; i < items.length; i += GRAPH_BUILDER_BATCH_SIZE) {
1688
+ if (i > 0) {
1689
+ await new Promise<void>((resolve) => setTimeout(resolve, 0));
1690
+ }
1691
+ const end = Math.min(i + GRAPH_BUILDER_BATCH_SIZE, items.length);
1692
+ for (let j = i; j < end; j++) {
1693
+ process(guaranteeNonNullable(items[j]));
1694
+ }
1695
+ }
1696
+ }
1697
+
1698
+ /**
1699
+ * Process elements from inputs in batches, yielding to the event loop
1700
+ * between batches to keep the UI responsive.
1701
+ */
1702
+ private async processElementsInBatches(
1703
+ graph: PureModel,
1704
+ inputs: V1_PureGraphBuilderInput[],
1705
+ getElements: (
1706
+ data: V1_PureModelContextDataIndex,
1707
+ ) => V1_PackageableElement[],
1708
+ createVisitor: (
1709
+ ctx: V1_GraphBuilderContext,
1710
+ ) => V1_PackageableElementVisitor<unknown>,
1711
+ options?: GraphBuilderOptions,
1712
+ ): Promise<void> {
1713
+ const allItems = inputs.flatMap((input) =>
1714
+ getElements(input.data).map((element) => ({
1715
+ element,
1716
+ model: input.model,
1717
+ })),
1718
+ );
1719
+ await this.runBatchedLoop(allItems, (item) =>
1720
+ this.visitWithGraphBuilderErrorHandling(
1721
+ item.element,
1722
+ createVisitor(
1723
+ this.getBuilderContext(graph, item.model, item.element, options),
1724
+ ),
1829
1725
  ),
1830
1726
  );
1831
1727
  }
@@ -1833,9 +1729,9 @@ export class V1_PureGraphManager extends AbstractPureGraphManager {
1833
1729
  private visitWithGraphBuilderErrorHandling<T>(
1834
1730
  element: V1_PackageableElement,
1835
1731
  visitor: V1_PackageableElementVisitor<T>,
1836
- ): Promise<T> {
1732
+ ): T {
1837
1733
  try {
1838
- return promisify(() => element.accept_PackageableElementVisitor(visitor));
1734
+ return element.accept_PackageableElementVisitor(visitor);
1839
1735
  } catch (err) {
1840
1736
  assertErrorThrown(err);
1841
1737
  const error =
@@ -3840,6 +3736,24 @@ export class V1_PureGraphManager extends AbstractPureGraphManager {
3840
3736
  );
3841
3737
  }
3842
3738
 
3739
+ private resolveArtifactElements(
3740
+ elementPaths: string[],
3741
+ pureGraph: PureModel,
3742
+ ): DataProductElementScope[] {
3743
+ const scopes: DataProductElementScope[] = [];
3744
+ for (const path of elementPaths) {
3745
+ const el = pureGraph.getNullableElement(path, true);
3746
+ if (el) {
3747
+ const scope = new DataProductElementScope();
3748
+ scope.element = PackageableElementExplicitReference.create(
3749
+ el as DataProductElement,
3750
+ );
3751
+ scopes.push(scope);
3752
+ }
3753
+ }
3754
+ return scopes;
3755
+ }
3756
+
3843
3757
  async buildDataProductAnalysis(
3844
3758
  artifact: V1_DataProductArtifact,
3845
3759
  dataProductPath: string,
@@ -3849,77 +3763,264 @@ export class V1_PureGraphManager extends AbstractPureGraphManager {
3849
3763
  projectInfo: ProjectGAVCoordinates,
3850
3764
  graphReport?: GraphManagerOperationReport,
3851
3765
  ): Promise<DataProductAnalysisQueryResult> {
3852
- // Collect all mapping generation infos from model access point groups and native model access
3853
- const allMappingGenInfos = new Map<string, V1_MappingGenerationInfo>();
3766
+ switch (dataProductAccessType) {
3767
+ case DataProductAccessType.MODEL:
3768
+ return this.buildModelAccessDataProductAnalysis(
3769
+ artifact,
3770
+ dataProductPath,
3771
+ pureGraph,
3772
+ accessPointId,
3773
+ projectInfo,
3774
+ graphReport,
3775
+ );
3776
+ case DataProductAccessType.NATIVE:
3777
+ return this.buildNativeAccessDataProductAnalysis(
3778
+ artifact,
3779
+ dataProductPath,
3780
+ pureGraph,
3781
+ accessPointId,
3782
+ projectInfo,
3783
+ graphReport,
3784
+ );
3785
+ case DataProductAccessType.LAKEHOUSE:
3786
+ return this.buildLakehouseAccessDataProductAnalysis(
3787
+ artifact,
3788
+ dataProductPath,
3789
+ pureGraph,
3790
+ accessPointId,
3791
+ projectInfo,
3792
+ graphReport,
3793
+ );
3794
+ default:
3795
+ throw new UnsupportedOperationError(
3796
+ `Unsupported data product access type: '${dataProductAccessType}'`,
3797
+ );
3798
+ }
3799
+ }
3854
3800
 
3801
+ private async buildModelAccessDataProductAnalysis(
3802
+ artifact: V1_DataProductArtifact,
3803
+ dataProductPath: string,
3804
+ pureGraph: PureModel,
3805
+ accessPointId: string,
3806
+ projectInfo: ProjectGAVCoordinates,
3807
+ graphReport?: GraphManagerOperationReport,
3808
+ ): Promise<DataProductAnalysisQueryResult> {
3855
3809
  const modelAccessPointGroups = artifact.accessPointGroups.filter(
3856
3810
  (group): group is V1_ModelAccessPointGroupInfo =>
3857
3811
  group instanceof V1_ModelAccessPointGroupInfo,
3858
3812
  );
3859
- for (const group of modelAccessPointGroups) {
3860
- allMappingGenInfos.set(
3861
- group.mappingGeneration.path,
3862
- group.mappingGeneration,
3813
+ const accessGroup = modelAccessPointGroups.find(
3814
+ (g) => g.id === accessPointId,
3815
+ );
3816
+ if (!accessGroup) {
3817
+ throw new Error(
3818
+ `Can't resolve access point '${accessPointId}' (type: ${DataProductAccessType.MODEL}) in data product '${dataProductPath}'`,
3863
3819
  );
3864
3820
  }
3821
+ const mappingPath = accessGroup.mappingGeneration.path;
3865
3822
 
3866
- if (artifact.nativeModelAccess?.mappingGenerations) {
3867
- for (const [path, genInfo] of artifact.nativeModelAccess
3868
- .mappingGenerations) {
3869
- if (!allMappingGenInfos.has(path)) {
3870
- allMappingGenInfos.set(path, genInfo);
3871
- }
3872
- }
3873
- }
3874
-
3875
- // Resolve mapping path from accessPointId and dataProductAccessType
3876
- let mappingPath: string | undefined;
3877
- let accessGroup:
3878
- | V1_ModelAccessPointGroupInfo
3879
- | V1_NativeModelExecutionContextInfo
3880
- | undefined = undefined;
3881
- if (dataProductAccessType === DataProductAccessType.MODEL) {
3882
- const group = modelAccessPointGroups.find((g) => g.id === accessPointId);
3883
- if (group) {
3884
- mappingPath = group.mappingGeneration.path;
3885
- accessGroup = group;
3886
- }
3887
- } else if (dataProductAccessType === DataProductAccessType.NATIVE) {
3888
- const nativeCtx =
3889
- artifact.nativeModelAccess?.nativeModelExecutionContexts.find(
3890
- (ctx) => ctx.key === accessPointId,
3891
- );
3892
- if (nativeCtx) {
3893
- mappingPath = nativeCtx.mapping;
3894
- accessGroup = nativeCtx;
3895
- }
3896
- }
3823
+ return this.buildDataProductAnalysisCore(
3824
+ artifact,
3825
+ dataProductPath,
3826
+ pureGraph,
3827
+ mappingPath,
3828
+ accessGroup,
3829
+ undefined, // no resolved runtime path for MODEL access
3830
+ projectInfo,
3831
+ graphReport,
3832
+ );
3833
+ }
3897
3834
 
3898
- if (!mappingPath) {
3835
+ private async buildNativeAccessDataProductAnalysis(
3836
+ artifact: V1_DataProductArtifact,
3837
+ dataProductPath: string,
3838
+ pureGraph: PureModel,
3839
+ accessPointId: string,
3840
+ projectInfo: ProjectGAVCoordinates,
3841
+ graphReport?: GraphManagerOperationReport,
3842
+ ): Promise<DataProductAnalysisQueryResult> {
3843
+ const nativeCtx =
3844
+ artifact.nativeModelAccess?.nativeModelExecutionContexts.find(
3845
+ (ctx) => ctx.key === accessPointId,
3846
+ );
3847
+ if (!nativeCtx) {
3899
3848
  throw new Error(
3900
- `Can't resolve mapping path for access point '${accessPointId}' (type: ${dataProductAccessType}) in data product '${dataProductPath}'`,
3849
+ `Can't resolve access point '${accessPointId}' (type: ${DataProductAccessType.NATIVE}) in data product '${dataProductPath}'`,
3901
3850
  );
3902
3851
  }
3903
- if (!accessGroup) {
3852
+ const mappingPath = nativeCtx.mapping;
3853
+ if (!mappingPath) {
3904
3854
  throw new Error(
3905
- `Can't resolve access group for access point '${accessPointId}' (type: ${dataProductAccessType}) in data product '${dataProductPath}'`,
3855
+ `Can't resolve mapping path for access point '${accessPointId}' (type: ${DataProductAccessType.NATIVE}) in data product '${dataProductPath}'`,
3906
3856
  );
3907
3857
  }
3908
- // Build the minimal graph using ONLY the elements from the resolved mapping
3909
- const resolvedMappingGenInfo = mappingPath
3910
- ? allMappingGenInfos.get(mappingPath)
3911
- : undefined;
3912
3858
 
3913
- if (!resolvedMappingGenInfo) {
3859
+ // Resolve runtime path for the native context
3860
+ const resolvedRuntimePath = nativeCtx.runtimeGeneration?.path;
3861
+
3862
+ return this.buildDataProductAnalysisCore(
3863
+ artifact,
3864
+ dataProductPath,
3865
+ pureGraph,
3866
+ mappingPath,
3867
+ nativeCtx,
3868
+ resolvedRuntimePath,
3869
+ projectInfo,
3870
+ graphReport,
3871
+ );
3872
+ }
3873
+
3874
+ private async buildLakehouseAccessDataProductAnalysis(
3875
+ artifact: V1_DataProductArtifact,
3876
+ dataProductPath: string,
3877
+ pureGraph: PureModel,
3878
+ accessPointId: string,
3879
+ projectInfo: ProjectGAVCoordinates,
3880
+ graphReport?: GraphManagerOperationReport,
3881
+ ): Promise<DataProductAnalysisQueryResult> {
3882
+ // Create a dummy data product element
3883
+ const dummyDataProduct = new V1_DataProduct();
3884
+ dummyDataProduct.package =
3885
+ extractPackagePathFromPath(dataProductPath) ?? '';
3886
+ dummyDataProduct.name = extractElementNameFromPath(dataProductPath);
3887
+ dummyDataProduct.title = artifact.dataProduct.title;
3888
+ dummyDataProduct.description = artifact.dataProduct.description;
3889
+
3890
+ // Build graph with only the data product
3891
+ const graphEntities = [dummyDataProduct]
3892
+ .filter((el) => !pureGraph.getNullableElement(el.path, false))
3893
+ .map((el) => this.elementProtocolToEntity(el));
3894
+ await this.buildGraph(
3895
+ pureGraph,
3896
+ graphEntities,
3897
+ ActionState.create(),
3898
+ {
3899
+ origin: new LegendSDLC(
3900
+ projectInfo.groupId,
3901
+ projectInfo.artifactId,
3902
+ projectInfo.versionId,
3903
+ ),
3904
+ },
3905
+ graphReport,
3906
+ );
3907
+
3908
+ const data = pureGraph.getDataProduct(dataProductPath);
3909
+
3910
+ // Create access point groups with LakehouseAccessPoints from artifact data
3911
+ data.accessPointGroups = artifact.accessPointGroups
3912
+ .filter(
3913
+ (groupInfo) => !(groupInfo instanceof V1_ModelAccessPointGroupInfo),
3914
+ )
3915
+ .map((groupInfo) => {
3916
+ const apGroup = new AccessPointGroup();
3917
+ apGroup.id = groupInfo.id;
3918
+ apGroup.description = groupInfo.description;
3919
+ apGroup.accessPoints = groupInfo.accessPointImplementations.map(
3920
+ (apImpl) => {
3921
+ const lakehouseAP = new LakehouseAccessPoint(
3922
+ apImpl.id,
3923
+ '', // targetEnvironment is not available in the artifact
3924
+ new RawLambda(undefined, undefined),
3925
+ apGroup,
3926
+ );
3927
+ lakehouseAP.description = apImpl.description;
3928
+ return lakehouseAP;
3929
+ },
3930
+ );
3931
+ return apGroup;
3932
+ });
3933
+
3934
+ // Find the lakehouse access point matching the requested id
3935
+ const lakehouseResult = data.accessPointGroups
3936
+ .flatMap((group) => group.accessPoints)
3937
+ .find(
3938
+ (ap): ap is LakehouseAccessPoint =>
3939
+ ap instanceof LakehouseAccessPoint && ap.id === accessPointId,
3940
+ );
3941
+ if (!lakehouseResult) {
3914
3942
  throw new Error(
3915
- `Can't find mapping generation info for access point '${accessPointId}' (type: ${dataProductAccessType}) in data product '${dataProductPath}'`,
3943
+ `Can't resolve lakehouse access point '${accessPointId}' in data product '${dataProductPath}'`,
3916
3944
  );
3917
3945
  }
3918
3946
 
3919
- // Create a dummy mapping for the resolved mapping path
3920
- const dummyMapping = new V1_Mapping();
3921
- dummyMapping.package = extractPackagePathFromPath(mappingPath) ?? '';
3922
- dummyMapping.name = extractElementNameFromPath(mappingPath);
3947
+ const result = new DataProductAnalysis();
3948
+ result.path = dataProductPath;
3949
+ result.title = artifact.dataProduct.title;
3950
+ result.description = artifact.dataProduct.description;
3951
+
3952
+ return new DataProductAnalysisQueryResult(
3953
+ undefined,
3954
+ result,
3955
+ lakehouseResult,
3956
+ );
3957
+ }
3958
+
3959
+ /**
3960
+ * Shared core logic for building data product analysis after the access type
3961
+ * specific resolution has been performed.
3962
+ */
3963
+ private async buildDataProductAnalysisCore(
3964
+ artifact: V1_DataProductArtifact,
3965
+ dataProductPath: string,
3966
+ pureGraph: PureModel,
3967
+ mappingPath: string,
3968
+ accessGroup:
3969
+ | V1_ModelAccessPointGroupInfo
3970
+ | V1_NativeModelExecutionContextInfo,
3971
+ resolvedRuntimePath: string | undefined,
3972
+ projectInfo: ProjectGAVCoordinates,
3973
+ graphReport?: GraphManagerOperationReport,
3974
+ ): Promise<DataProductAnalysisQueryResult> {
3975
+ const modelAccessPointGroups = artifact.accessPointGroups.filter(
3976
+ (group): group is V1_ModelAccessPointGroupInfo =>
3977
+ group instanceof V1_ModelAccessPointGroupInfo,
3978
+ );
3979
+
3980
+ // Collect mapping generation infos from all sources
3981
+ const includedGenInfos = new Map<string, V1_MappingGenerationInfo>();
3982
+
3983
+ if (artifact.nativeModelAccess?.mappingGenerations) {
3984
+ for (const [path, genInfo] of artifact.nativeModelAccess
3985
+ .mappingGenerations) {
3986
+ includedGenInfos.set(path, genInfo);
3987
+ }
3988
+ }
3989
+ for (const group of modelAccessPointGroups) {
3990
+ if (!includedGenInfos.has(group.mappingGeneration.path)) {
3991
+ includedGenInfos.set(
3992
+ group.mappingGeneration.path,
3993
+ group.mappingGeneration,
3994
+ );
3995
+ }
3996
+ }
3997
+
3998
+ const nativeRuntimePaths = new Map<string, string>();
3999
+ if (artifact.nativeModelAccess?.nativeModelExecutionContexts) {
4000
+ for (const ctx of artifact.nativeModelAccess
4001
+ .nativeModelExecutionContexts) {
4002
+ const rtPath = ctx.runtimeGeneration?.path;
4003
+ if (rtPath) {
4004
+ nativeRuntimePaths.set(ctx.key, rtPath);
4005
+ }
4006
+ }
4007
+ }
4008
+
4009
+ // Only add a stub for the resolved mapping to the graph
4010
+ const resolvedMappingStub = new V1_Mapping();
4011
+ resolvedMappingStub.package = extractPackagePathFromPath(mappingPath) ?? '';
4012
+ resolvedMappingStub.name = extractElementNameFromPath(mappingPath);
4013
+
4014
+ // Only add a runtime stub for the resolved native context (if applicable)
4015
+ let resolvedRuntimeStub: V1_PackageableRuntime | undefined;
4016
+ if (resolvedRuntimePath) {
4017
+ resolvedRuntimeStub = new V1_PackageableRuntime();
4018
+ resolvedRuntimeStub.package =
4019
+ extractPackagePathFromPath(resolvedRuntimePath) ?? '';
4020
+ resolvedRuntimeStub.name =
4021
+ extractElementNameFromPath(resolvedRuntimePath);
4022
+ resolvedRuntimeStub.runtimeValue = new V1_EngineRuntime();
4023
+ }
3923
4024
 
3924
4025
  // Create a dummy data product element
3925
4026
  const dummyDataProduct = new V1_DataProduct();
@@ -3928,9 +4029,14 @@ export class V1_PureGraphManager extends AbstractPureGraphManager {
3928
4029
  dummyDataProduct.name = extractElementNameFromPath(dataProductPath);
3929
4030
  dummyDataProduct.title = artifact.dataProduct.title;
3930
4031
  dummyDataProduct.description = artifact.dataProduct.description;
3931
- // Build the minimal graph from the resolved mapping's model elements + dummy mapping + dummy data product
3932
- const graphEntities = resolvedMappingGenInfo.model.elements
3933
- .concat([dummyMapping])
4032
+
4033
+ // Only load model elements for the resolved mapping
4034
+ const allModelElements: V1_PackageableElement[] =
4035
+ includedGenInfos.get(mappingPath)?.model.elements ?? [];
4036
+
4037
+ const graphEntities = allModelElements
4038
+ .concat(resolvedMappingStub)
4039
+ .concat(resolvedRuntimeStub ? [resolvedRuntimeStub] : [])
3934
4040
  .concat(dummyDataProduct)
3935
4041
  .filter((el) => !pureGraph.getNullableElement(el.path, false))
3936
4042
  .map((el) => this.elementProtocolToEntity(el));
@@ -3949,45 +4055,115 @@ export class V1_PureGraphManager extends AbstractPureGraphManager {
3949
4055
  );
3950
4056
 
3951
4057
  const data = pureGraph.getDataProduct(dataProductPath);
3952
- // build access point group
3953
- let exec: ModelAccessPointGroup | NativeModelExecutionContext;
3954
- if (accessGroup instanceof V1_ModelAccessPointGroupInfo) {
3955
- const group = new ModelAccessPointGroup();
3956
- group.id = accessGroup.id;
3957
- data.accessPointGroups = [group];
3958
- group.mapping = PackageableElementExplicitReference.create(
3959
- pureGraph.getMapping(mappingPath),
4058
+
4059
+ let exec: ModelAccessPointGroup | NativeModelExecutionContext | undefined;
4060
+
4061
+ if (
4062
+ artifact.nativeModelAccess?.defaultExecutionContext &&
4063
+ artifact.nativeModelAccess.nativeModelExecutionContexts.length
4064
+ ) {
4065
+ const na = new NativeModelAccess();
4066
+ na.nativeModelExecutionContexts =
4067
+ artifact.nativeModelAccess.nativeModelExecutionContexts.map(
4068
+ (ctxInfo) => {
4069
+ const ctx = new NativeModelExecutionContext();
4070
+ ctx.key = ctxInfo.key;
4071
+ const ctxMappingPath = ctxInfo.mapping;
4072
+ const ctxMapping =
4073
+ ctxMappingPath === mappingPath
4074
+ ? pureGraph.getMapping(ctxMappingPath)
4075
+ : new Mapping(ctxMappingPath);
4076
+ ctx.mapping =
4077
+ PackageableElementExplicitReference.create(ctxMapping);
4078
+ const rtPath = nativeRuntimePaths.get(ctxInfo.key);
4079
+ if (rtPath) {
4080
+ const ctxRuntime =
4081
+ rtPath === resolvedRuntimePath
4082
+ ? pureGraph.getRuntime(rtPath)
4083
+ : new PackageableRuntime(rtPath);
4084
+ ctx.runtime =
4085
+ PackageableElementExplicitReference.create(ctxRuntime);
4086
+ }
4087
+ ctx.__owner = na;
4088
+ return ctx;
4089
+ },
4090
+ );
4091
+ const defaultExecutionContext = na.nativeModelExecutionContexts.find(
4092
+ (ctx) =>
4093
+ ctx.key === artifact.nativeModelAccess?.defaultExecutionContext,
3960
4094
  );
3961
- exec = group;
3962
- } else {
3963
- const nativeAccess = new NativeModelExecutionContext();
3964
- nativeAccess.key = accessGroup.key;
3965
- nativeAccess.mapping = PackageableElementExplicitReference.create(
3966
- pureGraph.getMapping(mappingPath),
4095
+ if (!defaultExecutionContext) {
4096
+ throw new Error(
4097
+ `Can't find execution context matching default context in '${dataProductPath}'`,
4098
+ );
4099
+ }
4100
+ na.defaultExecutionContext = defaultExecutionContext;
4101
+ na.featuredElements = this.resolveArtifactElements(
4102
+ artifact.nativeModelAccess.elements,
4103
+ pureGraph,
3967
4104
  );
3968
- const na = new NativeModelAccess();
3969
- na.nativeModelExecutionContexts = [nativeAccess];
3970
4105
  data.nativeModelAccess = na;
3971
- exec = nativeAccess;
3972
4106
  }
3973
4107
 
3974
- // Build MappingModelCoverageAnalysisResult for the resolved mapping only
4108
+ if (modelAccessPointGroups.length > 0) {
4109
+ data.accessPointGroups = modelAccessPointGroups.map((groupInfo) => {
4110
+ const group = new ModelAccessPointGroup();
4111
+ group.id = groupInfo.id;
4112
+ const groupMappingPath = groupInfo.mappingGeneration.path;
4113
+ const groupMapping =
4114
+ groupMappingPath === mappingPath
4115
+ ? pureGraph.getMapping(groupMappingPath)
4116
+ : new Mapping(groupMappingPath);
4117
+ group.mapping =
4118
+ PackageableElementExplicitReference.create(groupMapping);
4119
+ group.featuredElements = this.resolveArtifactElements(
4120
+ groupInfo.elements,
4121
+ pureGraph,
4122
+ );
4123
+ return group;
4124
+ });
4125
+ }
4126
+
4127
+ // Resolve the target exec state
4128
+ if (accessGroup instanceof V1_ModelAccessPointGroupInfo) {
4129
+ exec = data.accessPointGroups.find(
4130
+ (g) => g instanceof ModelAccessPointGroup && g.id === accessGroup.id,
4131
+ ) as ModelAccessPointGroup;
4132
+ } else {
4133
+ exec = data.nativeModelAccess?.nativeModelExecutionContexts.find(
4134
+ (ctx) => ctx.key === accessGroup.key,
4135
+ );
4136
+ }
4137
+
4138
+ if (!exec) {
4139
+ throw new Error(
4140
+ `Can't find execution matching access id in '${dataProductPath}'`,
4141
+ );
4142
+ }
4143
+
4144
+ // Build MappingModelCoverageAnalysisResult for all included mappings
3975
4145
  const mappingToMappingCoverageResult = new Map<
3976
4146
  string,
3977
4147
  MappingModelCoverageAnalysisResult
3978
4148
  >();
3979
- const v1Result = new V1_MappingModelCoverageAnalysisResult();
3980
- v1Result.mappedEntities = resolvedMappingGenInfo.mappedEntities;
3981
- v1Result.model = resolvedMappingGenInfo.model;
3982
- mappingToMappingCoverageResult.set(
3983
- mappingPath,
3984
- V1_buildModelCoverageAnalysisResult(
3985
- v1Result,
3986
- this,
3987
- pureGraph.getMapping(mappingPath),
3988
- resolvedMappingGenInfo.model,
3989
- ),
3990
- );
4149
+ for (const [mPath, genInfo] of includedGenInfos) {
4150
+ const v1Result = new V1_MappingModelCoverageAnalysisResult();
4151
+ v1Result.mappedEntities = genInfo.mappedEntities;
4152
+ v1Result.model = genInfo.model;
4153
+ const coverageMapping =
4154
+ mPath === mappingPath
4155
+ ? pureGraph.getMapping(mPath)
4156
+ : new Mapping(mPath);
4157
+ mappingToMappingCoverageResult.set(
4158
+ mPath,
4159
+ V1_buildModelCoverageAnalysisResult(
4160
+ v1Result,
4161
+ this,
4162
+ coverageMapping,
4163
+ genInfo.model,
4164
+ ),
4165
+ );
4166
+ }
3991
4167
 
3992
4168
  // Build the analysis result
3993
4169
  const result = new DataProductAnalysis();
@@ -4495,6 +4671,21 @@ export class V1_PureGraphManager extends AbstractPureGraphManager {
4495
4671
  );
4496
4672
  }
4497
4673
 
4674
+ async checkServiceRegisteredByPattern(
4675
+ serviceServerUrl: string,
4676
+ servicePattern: string,
4677
+ ): Promise<boolean> {
4678
+ try {
4679
+ await this.engine.getServiceMetadataByPattern(
4680
+ serviceServerUrl,
4681
+ servicePattern,
4682
+ );
4683
+ return true;
4684
+ } catch {
4685
+ return false;
4686
+ }
4687
+ }
4688
+
4498
4689
  async runServicePostValidations(
4499
4690
  service: Service,
4500
4691
  graph: PureModel,