@finos/legend-application-query 13.7.205 → 13.8.0

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 (111) hide show
  1. package/lib/__lib__/LegendQueryNavigation.d.ts +16 -10
  2. package/lib/__lib__/LegendQueryNavigation.d.ts.map +1 -1
  3. package/lib/__lib__/LegendQueryNavigation.js +17 -12
  4. package/lib/__lib__/LegendQueryNavigation.js.map +1 -1
  5. package/lib/__lib__/LegendQueryUserDataHelper.d.ts +25 -7
  6. package/lib/__lib__/LegendQueryUserDataHelper.d.ts.map +1 -1
  7. package/lib/__lib__/LegendQueryUserDataHelper.js +81 -6
  8. package/lib/__lib__/LegendQueryUserDataHelper.js.map +1 -1
  9. package/lib/__lib__/LegendQueryUserDataSpaceHelper.d.ts +21 -4
  10. package/lib/__lib__/LegendQueryUserDataSpaceHelper.d.ts.map +1 -1
  11. package/lib/__lib__/LegendQueryUserDataSpaceHelper.js +17 -0
  12. package/lib/__lib__/LegendQueryUserDataSpaceHelper.js.map +1 -1
  13. package/lib/application/LegendQueryApplicationConfig.d.ts +10 -0
  14. package/lib/application/LegendQueryApplicationConfig.d.ts.map +1 -1
  15. package/lib/application/LegendQueryApplicationConfig.js +16 -0
  16. package/lib/application/LegendQueryApplicationConfig.js.map +1 -1
  17. package/lib/components/Core_LegendQueryApplicationPlugin.d.ts.map +1 -1
  18. package/lib/components/Core_LegendQueryApplicationPlugin.js +7 -3
  19. package/lib/components/Core_LegendQueryApplicationPlugin.js.map +1 -1
  20. package/lib/components/LegendQueryWebApplication.d.ts.map +1 -1
  21. package/lib/components/LegendQueryWebApplication.js +2 -2
  22. package/lib/components/LegendQueryWebApplication.js.map +1 -1
  23. package/lib/components/QueryEditor.d.ts.map +1 -1
  24. package/lib/components/QueryEditor.js +5 -2
  25. package/lib/components/QueryEditor.js.map +1 -1
  26. package/lib/components/__test-utils__/QueryEditorComponentTestUtils.d.ts +8 -0
  27. package/lib/components/__test-utils__/QueryEditorComponentTestUtils.d.ts.map +1 -1
  28. package/lib/components/__test-utils__/QueryEditorComponentTestUtils.js +190 -8
  29. package/lib/components/__test-utils__/QueryEditorComponentTestUtils.js.map +1 -1
  30. package/lib/components/data-product/DataProductInfo.d.ts +28 -0
  31. package/lib/components/data-product/DataProductInfo.d.ts.map +1 -0
  32. package/lib/components/data-product/DataProductInfo.js +89 -0
  33. package/lib/components/data-product/DataProductInfo.js.map +1 -0
  34. package/lib/components/{data-space/DataSpaceQueryCreator.d.ts → data-product/LegendQueryDataProductQueryBuilder.d.ts} +3 -4
  35. package/lib/components/data-product/LegendQueryDataProductQueryBuilder.d.ts.map +1 -0
  36. package/lib/components/data-product/LegendQueryDataProductQueryBuilder.js +98 -0
  37. package/lib/components/data-product/LegendQueryDataProductQueryBuilder.js.map +1 -0
  38. package/lib/components/data-space/DataProductQueryCreator.d.ts +36 -0
  39. package/lib/components/data-space/DataProductQueryCreator.d.ts.map +1 -0
  40. package/lib/components/data-space/DataProductQueryCreator.js +76 -0
  41. package/lib/components/data-space/DataProductQueryCreator.js.map +1 -0
  42. package/lib/index.css +1 -1
  43. package/lib/index.d.ts +1 -1
  44. package/lib/index.d.ts.map +1 -1
  45. package/lib/index.js +1 -1
  46. package/lib/index.js.map +1 -1
  47. package/lib/light-mode.css +1 -1
  48. package/lib/package.json +2 -1
  49. package/lib/stores/QueryEditorStore.d.ts +46 -2
  50. package/lib/stores/QueryEditorStore.d.ts.map +1 -1
  51. package/lib/stores/QueryEditorStore.js +251 -5
  52. package/lib/stores/QueryEditorStore.js.map +1 -1
  53. package/lib/stores/data-product/query-builder/DataProductArtifactHelper.d.ts +21 -0
  54. package/lib/stores/data-product/query-builder/DataProductArtifactHelper.d.ts.map +1 -0
  55. package/lib/stores/data-product/query-builder/DataProductArtifactHelper.js +35 -0
  56. package/lib/stores/data-product/query-builder/DataProductArtifactHelper.js.map +1 -0
  57. package/lib/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.d.ts +11 -3
  58. package/lib/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.d.ts.map +1 -1
  59. package/lib/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.js +50 -8
  60. package/lib/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.js.map +1 -1
  61. package/lib/stores/data-space/DataProductQueryCreatorStore.d.ts +94 -0
  62. package/lib/stores/data-space/DataProductQueryCreatorStore.d.ts.map +1 -0
  63. package/lib/stores/data-space/DataProductQueryCreatorStore.js +388 -0
  64. package/lib/stores/data-space/DataProductQueryCreatorStore.js.map +1 -0
  65. package/lib/stores/data-space/DataProductSelectorState.d.ts +44 -0
  66. package/lib/stores/data-space/DataProductSelectorState.d.ts.map +1 -0
  67. package/lib/stores/data-space/DataProductSelectorState.js +111 -0
  68. package/lib/stores/data-space/DataProductSelectorState.js.map +1 -0
  69. package/lib/stores/data-space/DataSpaceTemplateQueryCreatorStore.d.ts.map +1 -1
  70. package/lib/stores/data-space/DataSpaceTemplateQueryCreatorStore.js +3 -0
  71. package/lib/stores/data-space/DataSpaceTemplateQueryCreatorStore.js.map +1 -1
  72. package/lib/stores/data-space/LegendQueryBareQueryBuilderState.d.ts +1 -1
  73. package/lib/stores/data-space/LegendQueryBareQueryBuilderState.d.ts.map +1 -1
  74. package/lib/stores/data-space/LegendQueryBareQueryBuilderState.js +1 -1
  75. package/lib/stores/data-space/LegendQueryBareQueryBuilderState.js.map +1 -1
  76. package/lib/stores/data-space/query-builder/LegendQueryDataSpaceQueryBuilderState.d.ts +4 -3
  77. package/lib/stores/data-space/query-builder/LegendQueryDataSpaceQueryBuilderState.d.ts.map +1 -1
  78. package/lib/stores/data-space/query-builder/LegendQueryDataSpaceQueryBuilderState.js +24 -29
  79. package/lib/stores/data-space/query-builder/LegendQueryDataSpaceQueryBuilderState.js.map +1 -1
  80. package/package.json +8 -7
  81. package/src/__lib__/LegendQueryNavigation.ts +76 -18
  82. package/src/__lib__/LegendQueryUserDataHelper.ts +177 -12
  83. package/src/__lib__/LegendQueryUserDataSpaceHelper.ts +54 -4
  84. package/src/application/LegendQueryApplicationConfig.ts +31 -0
  85. package/src/components/Core_LegendQueryApplicationPlugin.tsx +8 -2
  86. package/src/components/LegendQueryWebApplication.tsx +8 -4
  87. package/src/components/QueryEditor.tsx +13 -0
  88. package/src/components/__test-utils__/QueryEditorComponentTestUtils.tsx +418 -5
  89. package/src/components/data-product/DataProductInfo.tsx +297 -0
  90. package/src/components/data-product/LegendQueryDataProductQueryBuilder.tsx +268 -0
  91. package/src/components/data-space/DataProductQueryCreator.tsx +167 -0
  92. package/src/components/data-space/DataSpaceQuerySetup.tsx +1 -1
  93. package/src/index.ts +6 -0
  94. package/src/stores/QueryEditorStore.ts +485 -2
  95. package/src/stores/data-product/query-builder/DataProductArtifactHelper.ts +48 -0
  96. package/src/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.ts +77 -16
  97. package/src/stores/data-space/DataProductQueryCreatorStore.ts +765 -0
  98. package/src/stores/data-space/DataProductSelectorState.ts +164 -0
  99. package/src/stores/data-space/DataSpaceTemplateQueryCreatorStore.ts +10 -0
  100. package/src/stores/data-space/LegendQueryBareQueryBuilderState.ts +1 -1
  101. package/src/stores/data-space/query-builder/LegendQueryDataSpaceQueryBuilderState.ts +27 -54
  102. package/tsconfig.json +6 -2
  103. package/lib/components/data-space/DataSpaceQueryCreator.d.ts.map +0 -1
  104. package/lib/components/data-space/DataSpaceQueryCreator.js +0 -62
  105. package/lib/components/data-space/DataSpaceQueryCreator.js.map +0 -1
  106. package/lib/stores/data-space/DataSpaceQueryCreatorStore.d.ts +0 -92
  107. package/lib/stores/data-space/DataSpaceQueryCreatorStore.d.ts.map +0 -1
  108. package/lib/stores/data-space/DataSpaceQueryCreatorStore.js +0 -400
  109. package/lib/stores/data-space/DataSpaceQueryCreatorStore.js.map +0 -1
  110. package/src/components/data-space/DataSpaceQueryCreator.tsx +0 -119
  111. package/src/stores/data-space/DataSpaceQueryCreatorStore.ts +0 -697
@@ -42,13 +42,14 @@ import {
42
42
  } from '@finos/legend-shared';
43
43
  import {
44
44
  type LightQuery,
45
+ NativeModelExecutionContext,
45
46
  type RawLambda,
46
47
  type Runtime,
47
48
  type Service,
48
49
  type QueryGridConfig,
49
50
  type ValueSpecification,
50
51
  type GraphInitializationReport,
51
- type PackageableRuntime,
52
+ PackageableRuntime,
52
53
  type QueryInfo,
53
54
  GraphManagerState,
54
55
  Query,
@@ -75,6 +76,16 @@ import {
75
76
  QUERY_PROFILE_PATH,
76
77
  QueryDataSpaceExecutionContextInfo,
77
78
  QueryExplicitExecutionContextInfo,
79
+ QueryDataProductNativeExecutionContextInfo,
80
+ QueryDataProductModelAccessExecutionContextInfo,
81
+ ModelAccessPointGroup,
82
+ type DataProduct,
83
+ LakehouseRuntime,
84
+ V1_DATA_PRODUCT_ELEMENT_PROTOCOL_TYPE,
85
+ V1_DataProductArtifact,
86
+ V1_ModelAccessPointGroupInfo,
87
+ DataProductAccessType,
88
+ type DataProductAnalysisQueryResult,
78
89
  } from '@finos/legend-graph';
79
90
  import {
80
91
  generateExistingQueryEditorRoute,
@@ -86,7 +97,9 @@ import {
86
97
  type Entity,
87
98
  type ProjectGAVCoordinates,
88
99
  type EntitiesWithOrigin,
100
+ type DepotEntityWithOrigin,
89
101
  parseGACoordinates,
102
+ StoredFileGeneration,
90
103
  } from '@finos/legend-storage';
91
104
  import {
92
105
  type DepotServerClient,
@@ -95,6 +108,8 @@ import {
95
108
  LATEST_VERSION_ALIAS,
96
109
  VersionedProjectData,
97
110
  retrieveProjectEntitiesWithClassifier,
111
+ isSnapshotVersion,
112
+ SNAPSHOT_VERSION_ALIAS,
98
113
  } from '@finos/legend-server-depot';
99
114
  import {
100
115
  ActionAlertActionType,
@@ -116,6 +131,8 @@ import {
116
131
  QueryBuilderDataBrowserWorkflow,
117
132
  QueryBuilderActionConfig,
118
133
  QUERY_LOADER_DEFAULT_QUERY_SEARCH_LIMIT,
134
+ NativeModelDataProductExecutionState,
135
+ ModelAccessPointDataProductExecutionState,
119
136
  } from '@finos/legend-query-builder';
120
137
  import { LegendQueryUserDataHelper } from '../__lib__/LegendQueryUserDataHelper.js';
121
138
  import { LegendQueryTelemetryHelper } from '../__lib__/LegendQueryTelemetryHelper.js';
@@ -133,6 +150,13 @@ import {
133
150
  import { generateDataSpaceQueryCreatorRoute } from '../__lib__/DSL_DataSpace_LegendQueryNavigation.js';
134
151
  import { hasDataSpaceInfoBeenVisited } from '../__lib__/LegendQueryUserDataSpaceHelper.js';
135
152
  import { LegendQueryDataSpaceQueryBuilderState } from './data-space/query-builder/LegendQueryDataSpaceQueryBuilderState.js';
153
+ import { LegendQueryDataProductQueryBuilderState } from './data-product/query-builder/LegendQueryDataProductQueryBuilderState.js';
154
+ import { DataProductSelectorState } from './data-space/DataProductSelectorState.js';
155
+ import {
156
+ decorateEnvWithRealm,
157
+ LakehouseContractServerClient,
158
+ LakehouseEnvironmentType,
159
+ } from '@finos/legend-server-lakehouse';
136
160
 
137
161
  export interface QueryPersistConfiguration {
138
162
  defaultName?: string | undefined;
@@ -266,12 +290,21 @@ export class QueryCreatorState {
266
290
  }
267
291
  }
268
292
 
293
+ export class LegendQueryLakehouseState {
294
+ readonly contractServerClient: LakehouseContractServerClient;
295
+
296
+ constructor(contractServerClient: LakehouseContractServerClient) {
297
+ this.contractServerClient = contractServerClient;
298
+ }
299
+ }
300
+
269
301
  export abstract class QueryEditorStore {
270
302
  readonly applicationStore: LegendQueryApplicationStore;
271
303
  readonly depotServerClient: DepotServerClient;
272
304
  readonly pluginManager: LegendQueryPluginManager;
273
305
  readonly graphManagerState: GraphManagerState;
274
306
  readonly queryLoaderState: QueryLoaderState;
307
+ readonly lakehouseState?: LegendQueryLakehouseState | undefined;
275
308
 
276
309
  readonly initState = ActionState.create();
277
310
 
@@ -281,6 +314,7 @@ export abstract class QueryEditorStore {
281
314
  showRegisterServiceModal = false;
282
315
  showAppInfo = false;
283
316
  showDataspaceInfo = false;
317
+ showDataProductInfo = false;
284
318
  enableMinialGraphForDataSpaceLoadingPerformance = true;
285
319
 
286
320
  constructor(
@@ -294,6 +328,7 @@ export abstract class QueryEditorStore {
294
328
  showRegisterServiceModal: observable,
295
329
  showAppInfo: observable,
296
330
  showDataspaceInfo: observable,
331
+ showDataProductInfo: observable,
297
332
  queryBuilderState: observable,
298
333
  enableMinialGraphForDataSpaceLoadingPerformance: observable,
299
334
  isPerformingBlockingAction: computed,
@@ -301,6 +336,7 @@ export abstract class QueryEditorStore {
301
336
  setShowRegisterServiceModal: action,
302
337
  setShowAppInfo: action,
303
338
  setShowDataspaceInfo: action,
339
+ setShowDataProductInfo: action,
304
340
  setEnableMinialGraphForDataSpaceLoadingPerformance: action,
305
341
  initialize: flow,
306
342
  buildGraph: flow,
@@ -315,6 +351,15 @@ export abstract class QueryEditorStore {
315
351
  applicationStore.pluginManager,
316
352
  applicationStore.logService,
317
353
  );
354
+
355
+ // lakehouse
356
+ if (applicationStore.config.lakehouseContractUrl) {
357
+ const contractServerClient = new LakehouseContractServerClient({
358
+ baseUrl: applicationStore.config.lakehouseContractUrl,
359
+ });
360
+ contractServerClient.setTracerService(applicationStore.tracerService);
361
+ this.lakehouseState = new LegendQueryLakehouseState(contractServerClient);
362
+ }
318
363
  this.queryLoaderState = new QueryLoaderState(
319
364
  applicationStore,
320
365
  this.graphManagerState.graphManager,
@@ -402,6 +447,10 @@ export abstract class QueryEditorStore {
402
447
  this.showDataspaceInfo = val;
403
448
  }
404
449
 
450
+ setShowDataProductInfo(val: boolean): void {
451
+ this.showDataProductInfo = val;
452
+ }
453
+
405
454
  setShowRegisterServiceModal(val: boolean): void {
406
455
  this.showRegisterServiceModal = val;
407
456
  }
@@ -827,6 +876,394 @@ export abstract class QueryEditorStore {
827
876
  isLightGraphEnabled,
828
877
  };
829
878
  }
879
+
880
+ async fetchDataProductArtifact(
881
+ groupId: string,
882
+ artifactId: string,
883
+ versionId: string,
884
+ dataProductPath: string,
885
+ ): Promise<V1_DataProductArtifact> {
886
+ const project = StoreProjectData.serialization.fromJson(
887
+ await this.depotServerClient.getProject(groupId, artifactId),
888
+ );
889
+ const files = (
890
+ await this.depotServerClient.getGenerationFilesByType(
891
+ project,
892
+ versionId,
893
+ V1_DATA_PRODUCT_ELEMENT_PROTOCOL_TYPE,
894
+ )
895
+ ).map((rawFile) => StoredFileGeneration.serialization.fromJson(rawFile));
896
+ const fileContent = guaranteeNonNullable(
897
+ files.find((e) => e.path === dataProductPath)?.file.content,
898
+ `Artifact generation not found for data product: ${groupId}:${artifactId}:${versionId}/${dataProductPath}`,
899
+ );
900
+ const result = V1_DataProductArtifact.serialization.fromJson(
901
+ JSON.parse(fileContent) as PlainObject,
902
+ );
903
+ return result;
904
+ }
905
+
906
+ resolveDataProductMappingPath(
907
+ artifact: V1_DataProductArtifact,
908
+ executionContextId: string | undefined,
909
+ ): string {
910
+ // Try native execution contexts first
911
+ if (artifact.nativeModelAccess) {
912
+ const native = artifact.nativeModelAccess;
913
+ if (executionContextId) {
914
+ const matchingContext = native.nativeModelExecutionContexts.find(
915
+ (ctx) => ctx.key === executionContextId,
916
+ );
917
+ if (matchingContext) {
918
+ return matchingContext.mapping;
919
+ }
920
+ }
921
+ // Fall back to default execution context
922
+ const defaultContext = native.nativeModelExecutionContexts.find(
923
+ (ctx) => ctx.key === native.defaultExecutionContext,
924
+ );
925
+ if (defaultContext) {
926
+ return defaultContext.mapping;
927
+ }
928
+ // Fall back to first context
929
+ const firstContext = native.nativeModelExecutionContexts[0];
930
+ if (firstContext) {
931
+ return firstContext.mapping;
932
+ }
933
+ }
934
+
935
+ // Try model access point groups
936
+ const modelGroups = artifact.accessPointGroups.filter(
937
+ (g): g is V1_ModelAccessPointGroupInfo =>
938
+ g instanceof V1_ModelAccessPointGroupInfo,
939
+ );
940
+ if (executionContextId) {
941
+ const matchingGroup = modelGroups.find(
942
+ (g) => g.id === executionContextId,
943
+ );
944
+ if (matchingGroup) {
945
+ return matchingGroup.mappingGeneration.path;
946
+ }
947
+ }
948
+ // Fall back to first model access point group
949
+ const firstGroup = modelGroups[0];
950
+ if (firstGroup) {
951
+ return firstGroup.mappingGeneration.path;
952
+ }
953
+
954
+ throw new UnsupportedOperationError(
955
+ `Can't resolve mapping path for data product artifact`,
956
+ );
957
+ }
958
+
959
+ async buildGraphAndDataproductAnalyticsResult(
960
+ groupId: string,
961
+ artifactId: string,
962
+ versionId: string,
963
+ dataProductPath: string,
964
+ dataProductAccessType: DataProductAccessType,
965
+ accessPointId: string,
966
+ preFetchedArtifact?: V1_DataProductArtifact | undefined,
967
+ ): Promise<DataProductAnalysisQueryResult> {
968
+ this.initState.setMessage('Fetching data product analysis result...');
969
+ const project = StoreProjectData.serialization.fromJson(
970
+ await this.depotServerClient.getProject(groupId, artifactId),
971
+ );
972
+ const graph_buildReport = createGraphBuilderReport();
973
+ const stopWatch = new StopWatch();
974
+
975
+ // initialize system
976
+ stopWatch.record();
977
+ await this.graphManagerState.initializeSystem();
978
+ stopWatch.record(GRAPH_MANAGER_EVENT.INITIALIZE_GRAPH_SYSTEM__SUCCESS);
979
+
980
+ const dependency_buildReport = createGraphBuilderReport();
981
+ const dataProductAnalysisResult = preFetchedArtifact
982
+ ? await this.graphManagerState.graphManager.buildDataProductAnalysis(
983
+ preFetchedArtifact,
984
+ dataProductPath,
985
+ this.graphManagerState.graph,
986
+ accessPointId,
987
+ dataProductAccessType,
988
+ { groupId, artifactId, versionId },
989
+ graph_buildReport,
990
+ )
991
+ : await this.graphManagerState.graphManager.analyzeDataProductAndBuildMinimalGraph(
992
+ dataProductPath,
993
+ async () => {
994
+ const files = (
995
+ await this.depotServerClient.getGenerationFilesByType(
996
+ project,
997
+ versionId,
998
+ V1_DATA_PRODUCT_ELEMENT_PROTOCOL_TYPE,
999
+ )
1000
+ ).map((rawFile) =>
1001
+ StoredFileGeneration.serialization.fromJson(rawFile),
1002
+ );
1003
+ const fileContent = guaranteeNonNullable(
1004
+ files.find((e) => e.path === dataProductPath)?.file.content,
1005
+ `Artifact generation not found for data product: ${groupId}:${artifactId}:${versionId}/${dataProductPath}`,
1006
+ );
1007
+ return JSON.parse(fileContent) as PlainObject;
1008
+ },
1009
+ this.graphManagerState.graph,
1010
+ accessPointId,
1011
+ dataProductAccessType,
1012
+ { groupId, artifactId, versionId },
1013
+ undefined,
1014
+ graph_buildReport,
1015
+ );
1016
+
1017
+ // report
1018
+ stopWatch.record(GRAPH_MANAGER_EVENT.INITIALIZE_GRAPH__SUCCESS);
1019
+ const graphBuilderReportData = {
1020
+ timings:
1021
+ this.applicationStore.timeService.finalizeTimingsRecord(stopWatch),
1022
+ dependencies: dependency_buildReport,
1023
+ dependenciesCount:
1024
+ this.graphManagerState.graph.dependencyManager.numberOfDependencies,
1025
+ graph: graph_buildReport,
1026
+ isLightGraphEnabled: true,
1027
+ };
1028
+ this.logBuildGraphMetrics(graphBuilderReportData);
1029
+ this.applicationStore.logService.info(
1030
+ LogEvent.create(GRAPH_MANAGER_EVENT.INITIALIZE_GRAPH__SUCCESS),
1031
+ graphBuilderReportData,
1032
+ );
1033
+
1034
+ return dataProductAnalysisResult;
1035
+ }
1036
+
1037
+ /**
1038
+ * Resolves the execution state for a data product by looking up `accessId`
1039
+ * in both model access point groups (by `id`) and native execution contexts
1040
+ * (by `key`). Throws if no matching state is found.
1041
+ */
1042
+ resolveDataProductExecutionState(
1043
+ dataProduct: DataProduct,
1044
+ accessId: string | undefined,
1045
+ ): NativeModelExecutionContext | ModelAccessPointGroup {
1046
+ // Search model access point groups
1047
+ const modelGroups = dataProduct.accessPointGroups.filter(
1048
+ filterByType(ModelAccessPointGroup),
1049
+ );
1050
+ if (accessId) {
1051
+ const matchingGroup = modelGroups.find((g) => g.id === accessId);
1052
+ if (matchingGroup) {
1053
+ return matchingGroup;
1054
+ }
1055
+ // Search native execution contexts
1056
+ const matchingNative =
1057
+ dataProduct.nativeModelAccess?.nativeModelExecutionContexts.find(
1058
+ (ctx) => ctx.key === accessId,
1059
+ );
1060
+ if (matchingNative) {
1061
+ return matchingNative;
1062
+ }
1063
+ } else {
1064
+ // No accessId: fall back to defaults
1065
+ if (dataProduct.nativeModelAccess) {
1066
+ return dataProduct.nativeModelAccess.defaultExecutionContext;
1067
+ }
1068
+ if (modelGroups.length > 0) {
1069
+ return guaranteeNonNullable(modelGroups[0]);
1070
+ }
1071
+ }
1072
+ throw new UnsupportedOperationError(
1073
+ `Can't resolve execution state for data product '${dataProduct.path}'${accessId ? ` with access ID '${accessId}'` : ''}`,
1074
+ );
1075
+ }
1076
+
1077
+ /**
1078
+ * Resolves the user's lakehouse environment and warehouse, creates a
1079
+ * `LakehouseRuntime`, and wraps it in a `PackageableRuntime`.
1080
+ *
1081
+ * Resolution order:
1082
+ * 1. Check local storage (`LakehouseUserInfo`) for a previously persisted value.
1083
+ * 2. If not found, fetch from the lakehouse contract server via
1084
+ * `getUserEntitlementEnvs()` and persist the result to local storage.
1085
+ */
1086
+ async createLakehousePackageableRuntime(
1087
+ dataProductPath: string,
1088
+ gav: {
1089
+ groupId: string;
1090
+ artifactId: string;
1091
+ versionId: string;
1092
+ },
1093
+ ): Promise<PackageableRuntime> {
1094
+ // 1. Check local storage for persisted lakehouse user info
1095
+ const persistedInfo = LegendQueryUserDataHelper.getLakehouseUserInfo(
1096
+ this.applicationStore.userDataService,
1097
+ );
1098
+
1099
+ let userEnvironment: string | undefined = persistedInfo?.env;
1100
+ const userWarehouse: string | undefined =
1101
+ persistedInfo?.snowflakeWarehouse ?? 'LAKEHOUSE_CONSUMER_DEFAULT_WH';
1102
+ // 2. If no persisted environment, fetch from the server
1103
+ if (userEnvironment === undefined && this.lakehouseState) {
1104
+ try {
1105
+ const entitlementEnvs =
1106
+ await this.lakehouseState.contractServerClient.getUserEntitlementEnvs(
1107
+ this.applicationStore.identityService.currentUser,
1108
+ this.applicationStore.getAccessToken(),
1109
+ );
1110
+ userEnvironment = entitlementEnvs.users
1111
+ .map((e) => e.lakehouseEnvironment)
1112
+ .at(0);
1113
+ // Persist to local storage for future use
1114
+ LegendQueryUserDataHelper.persistLakehouseUserInfo(
1115
+ this.applicationStore.userDataService,
1116
+ {
1117
+ env: userEnvironment,
1118
+ snowflakeWarehouse: userWarehouse,
1119
+ },
1120
+ );
1121
+ } catch (error) {
1122
+ assertErrorThrown(error);
1123
+ this.applicationStore.logService.warn(
1124
+ LogEvent.create(LEGEND_QUERY_APP_EVENT.GENERIC_FAILURE),
1125
+ `Unable to fetch user lakehouse environment: ${error.message}`,
1126
+ );
1127
+ }
1128
+ }
1129
+
1130
+ if (userEnvironment === undefined) {
1131
+ throw new Error(
1132
+ `Can't query data product '${dataProductPath}': unable to resolve lakehouse user environment. ` +
1133
+ `Please ensure your lakehouse entitlements are configured.`,
1134
+ );
1135
+ }
1136
+ if (
1137
+ isSnapshotVersion(gav.versionId) ||
1138
+ gav.versionId === SNAPSHOT_VERSION_ALIAS
1139
+ ) {
1140
+ userEnvironment = decorateEnvWithRealm(
1141
+ userEnvironment,
1142
+ LakehouseEnvironmentType.PRODUCTION_PARALLEL,
1143
+ );
1144
+ }
1145
+ const lakehouseRuntime = new LakehouseRuntime(
1146
+ userEnvironment,
1147
+ userWarehouse,
1148
+ );
1149
+ const packageableRuntime = new PackageableRuntime(
1150
+ `${dataProductPath}_LakehouseRuntime`,
1151
+ );
1152
+ packageableRuntime.runtimeValue = lakehouseRuntime;
1153
+ return packageableRuntime;
1154
+ }
1155
+
1156
+ /**
1157
+ * Centralized method to build a data product query builder state.
1158
+ * Used by both the creator flow (new query from data product route/picker)
1159
+ * and the existing query flow (loading a saved data product query).
1160
+ *
1161
+ * This fetches the data product artifact, resolves the mapping path,
1162
+ * builds the minimal graph via `buildGraphAndDataproductAnalyticsResult`,
1163
+ * creates `LegendQueryDataProductQueryBuilderState`, and wires in
1164
+ * mapping coverage results.
1165
+ */
1166
+ async buildDataProductQueryBuilderState(
1167
+ groupId: string,
1168
+ artifactId: string,
1169
+ versionId: string,
1170
+ dataProductPath: string,
1171
+ artifact: V1_DataProductArtifact,
1172
+ accessId: string,
1173
+ dataProductAccessType: DataProductAccessType,
1174
+ onDataProductChange: (val: DepotEntityWithOrigin) => Promise<void>,
1175
+ productSelectorState?: DataProductSelectorState | undefined,
1176
+ ): Promise<LegendQueryDataProductQueryBuilderState> {
1177
+ // 3. Build minimal graph and get analysis result
1178
+ const dataProductAnalysisResult =
1179
+ await this.buildGraphAndDataproductAnalyticsResult(
1180
+ groupId,
1181
+ artifactId,
1182
+ versionId,
1183
+ dataProductPath,
1184
+ dataProductAccessType,
1185
+ accessId,
1186
+ artifact,
1187
+ );
1188
+ // 3.5. Create a LakehouseRuntime and add it to the graph
1189
+ const packageableRuntime = await this.createLakehousePackageableRuntime(
1190
+ dataProductPath,
1191
+ {
1192
+ groupId,
1193
+ artifactId,
1194
+ versionId,
1195
+ },
1196
+ );
1197
+ this.graphManagerState.graph.addElement(packageableRuntime, '_internal_');
1198
+ // 4. Get the data product from the built graph
1199
+ const dataProduct =
1200
+ this.graphManagerState.graph.getDataProduct(dataProductPath);
1201
+ // 5. Resolve execution state from accessId
1202
+ const resolvedState = this.resolveDataProductExecutionState(
1203
+ dataProduct,
1204
+ accessId,
1205
+ );
1206
+
1207
+ // 6. Create query builder state
1208
+ const projectInfo = { groupId, artifactId, versionId };
1209
+ const sourceInfo = {
1210
+ groupId,
1211
+ artifactId,
1212
+ versionId,
1213
+ dataProduct: dataProductPath,
1214
+ };
1215
+ const queryBuilderState = new LegendQueryDataProductQueryBuilderState(
1216
+ this.applicationStore,
1217
+ this.graphManagerState,
1218
+ QueryBuilderDataBrowserWorkflow.INSTANCE,
1219
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
1220
+ new QueryBuilderActionConfig_QueryApplication(this),
1221
+ dataProduct,
1222
+ artifact,
1223
+ resolvedState,
1224
+ this.depotServerClient,
1225
+ projectInfo,
1226
+ onDataProductChange,
1227
+ productSelectorState ??
1228
+ new DataProductSelectorState(
1229
+ this.depotServerClient,
1230
+ this.applicationStore,
1231
+ ),
1232
+ undefined,
1233
+ undefined,
1234
+ this.applicationStore.config.options.queryBuilderConfig,
1235
+ sourceInfo,
1236
+ );
1237
+ // Pass pre-resolved state to avoid double-resolution
1238
+ queryBuilderState.initWithDataProduct(dataProduct, resolvedState);
1239
+
1240
+ // 7. Wire in mapping coverage result
1241
+ const mappingCoverageResult =
1242
+ dataProductAnalysisResult.dataProductAnalysis.mappingToMappingCoverageResult?.get(
1243
+ dataProductAnalysisResult.targetMappingPath,
1244
+ );
1245
+ if (mappingCoverageResult) {
1246
+ queryBuilderState.explorerState.mappingModelCoverageAnalysisResult =
1247
+ mappingCoverageResult;
1248
+ }
1249
+
1250
+ // init
1251
+ const execValue = dataProductAnalysisResult.targetExecState;
1252
+ queryBuilderState.executionState =
1253
+ execValue instanceof NativeModelExecutionContext
1254
+ ? new NativeModelDataProductExecutionState(execValue, queryBuilderState)
1255
+ : new ModelAccessPointDataProductExecutionState(
1256
+ execValue,
1257
+ queryBuilderState,
1258
+ ).withAdhocRuntime();
1259
+ queryBuilderState.changeMapping(queryBuilderState.executionState.mapping);
1260
+ queryBuilderState.changeRuntime(
1261
+ new RuntimePointer(
1262
+ PackageableElementExplicitReference.create(packageableRuntime),
1263
+ ),
1264
+ );
1265
+ return queryBuilderState;
1266
+ }
830
1267
  }
831
1268
 
832
1269
  export class QueryBuilderActionConfig_QueryApplication extends QueryBuilderActionConfig {
@@ -1451,7 +1888,11 @@ export class ExistingQueryEditorStore extends QueryEditorStore {
1451
1888
  !(
1452
1889
  dataSpaceTaggedValue !== undefined ||
1453
1890
  queryInfo?.executionContext instanceof
1454
- QueryDataSpaceExecutionContextInfo
1891
+ QueryDataSpaceExecutionContextInfo ||
1892
+ queryInfo?.executionContext instanceof
1893
+ QueryDataProductNativeExecutionContextInfo ||
1894
+ queryInfo?.executionContext instanceof
1895
+ QueryDataProductModelAccessExecutionContextInfo
1455
1896
  )
1456
1897
  ) {
1457
1898
  yield flowResult(this.buildFullGraph());
@@ -1603,6 +2044,15 @@ export class ExistingQueryEditorStore extends QueryEditorStore {
1603
2044
  );
1604
2045
  }
1605
2046
  },
2047
+ new DataProductSelectorState(
2048
+ this.depotServerClient,
2049
+ this.applicationStore,
2050
+ ),
2051
+ () => {
2052
+ this.applicationStore.notificationService.notifyWarning(
2053
+ 'Switching data products is not supported from the existing query editor. Please open a new query instead.',
2054
+ );
2055
+ },
1606
2056
  dataSpaceAnalysisResult,
1607
2057
  undefined,
1608
2058
  undefined,
@@ -1667,6 +2117,39 @@ export class ExistingQueryEditorStore extends QueryEditorStore {
1667
2117
  : undefined,
1668
2118
  );
1669
2119
  return classQueryBuilderState;
2120
+ } else if (
2121
+ exec instanceof QueryDataProductNativeExecutionContextInfo ||
2122
+ exec instanceof QueryDataProductModelAccessExecutionContextInfo
2123
+ ) {
2124
+ const executionContextId =
2125
+ exec instanceof QueryDataProductNativeExecutionContextInfo
2126
+ ? exec.executionKey
2127
+ : exec.accessPointGroupId;
2128
+ const accessType =
2129
+ exec instanceof QueryDataProductNativeExecutionContextInfo
2130
+ ? DataProductAccessType.NATIVE
2131
+ : DataProductAccessType.MODEL;
2132
+ const artifact = await this.fetchDataProductArtifact(
2133
+ queryInfo.groupId,
2134
+ queryInfo.artifactId,
2135
+ queryInfo.versionId,
2136
+ exec.dataProductPath,
2137
+ );
2138
+ const queryBuilderState = await this.buildDataProductQueryBuilderState(
2139
+ queryInfo.groupId,
2140
+ queryInfo.artifactId,
2141
+ queryInfo.versionId,
2142
+ exec.dataProductPath,
2143
+ artifact,
2144
+ executionContextId,
2145
+ accessType,
2146
+ async () => {
2147
+ this.applicationStore.notificationService.notifyWarning(
2148
+ 'Switching data products is not supported from the existing query editor. Please open a new query instead.',
2149
+ );
2150
+ },
2151
+ );
2152
+ return queryBuilderState;
1670
2153
  }
1671
2154
  throw new UnsupportedOperationError(`Unsupported query execution context`);
1672
2155
  }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Copyright (c) 2026-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import {
18
+ DataProductAccessType,
19
+ V1_ModelAccessPointGroupInfo,
20
+ type V1_DataProductArtifact,
21
+ } from '@finos/legend-graph';
22
+ import { filterByType } from '@finos/legend-shared';
23
+
24
+ export const resolveDefaultDataProductAccessType = (
25
+ dataProductArtifact: V1_DataProductArtifact,
26
+ ): { type: DataProductAccessType; id: string } => {
27
+ const modelAcessGroup = dataProductArtifact.accessPointGroups.filter(
28
+ filterByType(V1_ModelAccessPointGroupInfo),
29
+ )[0];
30
+ if (modelAcessGroup) {
31
+ return {
32
+ type: DataProductAccessType.MODEL,
33
+ id: modelAcessGroup.id,
34
+ };
35
+ }
36
+
37
+ const native =
38
+ dataProductArtifact.nativeModelAccess?.nativeModelExecutionContexts[0];
39
+ if (native) {
40
+ return {
41
+ type: DataProductAccessType.NATIVE,
42
+ id: native.key,
43
+ };
44
+ }
45
+ throw new Error(
46
+ `Data Product not supported for querying on legend query ${dataProductArtifact.dataProduct.path}. Must contain a model access point or native model access.`,
47
+ );
48
+ };