@finos/legend-application-query 13.8.7 → 13.8.9

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 (70) hide show
  1. package/lib/__lib__/LegendQueryNavigation.d.ts +16 -2
  2. package/lib/__lib__/LegendQueryNavigation.d.ts.map +1 -1
  3. package/lib/__lib__/LegendQueryNavigation.js +21 -2
  4. package/lib/__lib__/LegendQueryNavigation.js.map +1 -1
  5. package/lib/components/Core_LegendQueryApplicationPlugin.d.ts +2 -1
  6. package/lib/components/Core_LegendQueryApplicationPlugin.d.ts.map +1 -1
  7. package/lib/components/Core_LegendQueryApplicationPlugin.js +13 -0
  8. package/lib/components/Core_LegendQueryApplicationPlugin.js.map +1 -1
  9. package/lib/components/LegendQueryWebApplication.d.ts.map +1 -1
  10. package/lib/components/LegendQueryWebApplication.js +2 -1
  11. package/lib/components/LegendQueryWebApplication.js.map +1 -1
  12. package/lib/components/__test-utils__/QueryEditorComponentTestUtils.d.ts +14 -2
  13. package/lib/components/__test-utils__/QueryEditorComponentTestUtils.d.ts.map +1 -1
  14. package/lib/components/__test-utils__/QueryEditorComponentTestUtils.js +93 -7
  15. package/lib/components/__test-utils__/QueryEditorComponentTestUtils.js.map +1 -1
  16. package/lib/components/data-product/DataProductInfo.d.ts.map +1 -1
  17. package/lib/components/data-product/DataProductInfo.js +1 -1
  18. package/lib/components/data-product/DataProductInfo.js.map +1 -1
  19. package/lib/components/data-product/DataProductSampleQueryCreator.d.ts +19 -0
  20. package/lib/components/data-product/DataProductSampleQueryCreator.d.ts.map +1 -0
  21. package/lib/components/data-product/DataProductSampleQueryCreator.js +53 -0
  22. package/lib/components/data-product/DataProductSampleQueryCreator.js.map +1 -0
  23. package/lib/components/data-product/DataProductSampleQueryPanel.d.ts +23 -0
  24. package/lib/components/data-product/DataProductSampleQueryPanel.d.ts.map +1 -0
  25. package/lib/components/data-product/DataProductSampleQueryPanel.js +95 -0
  26. package/lib/components/data-product/DataProductSampleQueryPanel.js.map +1 -0
  27. package/lib/index.css +1 -1
  28. package/lib/light-mode.css +1 -1
  29. package/lib/package.json +1 -1
  30. package/lib/stores/BaseTemplateQueryCreatorStore.d.ts +68 -0
  31. package/lib/stores/BaseTemplateQueryCreatorStore.d.ts.map +1 -0
  32. package/lib/stores/BaseTemplateQueryCreatorStore.js +120 -0
  33. package/lib/stores/BaseTemplateQueryCreatorStore.js.map +1 -0
  34. package/lib/stores/QueryEditorStore.d.ts +1 -1
  35. package/lib/stores/QueryEditorStore.d.ts.map +1 -1
  36. package/lib/stores/QueryEditorStore.js +43 -29
  37. package/lib/stores/QueryEditorStore.js.map +1 -1
  38. package/lib/stores/data-product/DataProductSampleQueryCreatorStore.d.ts +37 -0
  39. package/lib/stores/data-product/DataProductSampleQueryCreatorStore.d.ts.map +1 -0
  40. package/lib/stores/data-product/DataProductSampleQueryCreatorStore.js +60 -0
  41. package/lib/stores/data-product/DataProductSampleQueryCreatorStore.js.map +1 -0
  42. package/lib/stores/data-product/query-builder/DataProductArtifactHelper.d.ts.map +1 -1
  43. package/lib/stores/data-product/query-builder/DataProductArtifactHelper.js +9 -8
  44. package/lib/stores/data-product/query-builder/DataProductArtifactHelper.js.map +1 -1
  45. package/lib/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.d.ts +12 -2
  46. package/lib/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.d.ts.map +1 -1
  47. package/lib/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.js +22 -2
  48. package/lib/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.js.map +1 -1
  49. package/lib/stores/data-space/DataProductQueryCreatorStore.js +1 -1
  50. package/lib/stores/data-space/DataProductQueryCreatorStore.js.map +1 -1
  51. package/lib/stores/data-space/DataSpaceTemplateQueryCreatorStore.d.ts +14 -18
  52. package/lib/stores/data-space/DataSpaceTemplateQueryCreatorStore.d.ts.map +1 -1
  53. package/lib/stores/data-space/DataSpaceTemplateQueryCreatorStore.js +15 -80
  54. package/lib/stores/data-space/DataSpaceTemplateQueryCreatorStore.js.map +1 -1
  55. package/package.json +13 -13
  56. package/src/__lib__/LegendQueryNavigation.ts +43 -5
  57. package/src/components/Core_LegendQueryApplicationPlugin.tsx +17 -0
  58. package/src/components/LegendQueryWebApplication.tsx +5 -0
  59. package/src/components/__test-utils__/QueryEditorComponentTestUtils.tsx +237 -5
  60. package/src/components/data-product/DataProductInfo.tsx +12 -10
  61. package/src/components/data-product/DataProductSampleQueryCreator.tsx +114 -0
  62. package/src/components/data-product/DataProductSampleQueryPanel.tsx +219 -0
  63. package/src/stores/BaseTemplateQueryCreatorStore.ts +203 -0
  64. package/src/stores/QueryEditorStore.ts +64 -44
  65. package/src/stores/data-product/DataProductSampleQueryCreatorStore.ts +135 -0
  66. package/src/stores/data-product/query-builder/DataProductArtifactHelper.ts +12 -8
  67. package/src/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.ts +36 -4
  68. package/src/stores/data-space/DataProductQueryCreatorStore.ts +1 -1
  69. package/src/stores/data-space/DataSpaceTemplateQueryCreatorStore.ts +31 -126
  70. package/tsconfig.json +4 -0
@@ -0,0 +1,203 @@
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
+ type Query,
19
+ type QuerySearchSpecification,
20
+ type RawLambda,
21
+ type ValueSpecification,
22
+ QueryProjectCoordinates,
23
+ extractElementNameFromPath,
24
+ } from '@finos/legend-graph';
25
+ import { type DepotServerClient } from '@finos/legend-server-depot';
26
+ import {
27
+ assertErrorThrown,
28
+ LogEvent,
29
+ uuid,
30
+ type GeneratorFn,
31
+ } from '@finos/legend-shared';
32
+ import type { QueryBuilderState } from '@finos/legend-query-builder';
33
+ import {
34
+ type ProjectGAVCoordinates,
35
+ parseGACoordinates,
36
+ } from '@finos/legend-storage';
37
+ import {
38
+ type QueryPersistConfiguration,
39
+ QueryEditorStore,
40
+ } from './QueryEditorStore.js';
41
+ import type { LegendQueryApplicationStore } from './LegendQueryBaseStore.js';
42
+ import { createQueryClassTaggedValue } from '@finos/legend-extension-dsl-data-space/application';
43
+ import { processQueryParameters } from '../components/utils/QueryParameterUtils.js';
44
+ import { LEGEND_QUERY_APP_EVENT } from '../__lib__/LegendQueryEvent.js';
45
+
46
+ /**
47
+ * Abstract base store for template/sample query creator flows.
48
+ */
49
+ export abstract class BaseTemplateQueryCreatorStore extends QueryEditorStore {
50
+ readonly groupId: string;
51
+ readonly artifactId: string;
52
+ readonly versionId: string;
53
+ readonly templateQueryId: string;
54
+ templateQueryTitle?: string;
55
+ urlQueryParamValues: Record<string, string> | undefined;
56
+
57
+ constructor(
58
+ applicationStore: LegendQueryApplicationStore,
59
+ depotServerClient: DepotServerClient,
60
+ groupId: string,
61
+ artifactId: string,
62
+ versionId: string,
63
+ templateQueryId: string,
64
+ urlQueryParamValues: Record<string, string> | undefined,
65
+ ) {
66
+ super(applicationStore, depotServerClient);
67
+ this.groupId = groupId;
68
+ this.artifactId = artifactId;
69
+ this.versionId = versionId;
70
+ this.templateQueryId = templateQueryId;
71
+ this.urlQueryParamValues = urlQueryParamValues;
72
+ }
73
+
74
+ getProjectInfo(): ProjectGAVCoordinates {
75
+ return {
76
+ groupId: this.groupId,
77
+ artifactId: this.artifactId,
78
+ versionId: this.versionId,
79
+ };
80
+ }
81
+
82
+ override *buildGraph(): GeneratorFn<void> {
83
+ // do nothing — graph is built inside initializeQueryBuilderState
84
+ }
85
+
86
+ /**
87
+ * Returns the entity path (DataSpace path or DataProduct path) used for
88
+ * display names in persist configuration.
89
+ */
90
+ abstract getEntityPath(): string;
91
+
92
+ /**
93
+ * Returns the tagged values to attach to the search specification.
94
+ */
95
+ abstract getSearchTaggedValues(): {
96
+ profile: string;
97
+ tag: string;
98
+ value: string;
99
+ }[];
100
+
101
+ /**
102
+ * Returns the tagged values to attach to the persisted query
103
+ */
104
+ abstract getQueryDecoratorTaggedValues():
105
+ | { profile: string; tag: string; value: string }[]
106
+ | undefined;
107
+
108
+ /**
109
+ * Resolves URL query parameters into a default parameter values map.
110
+ * Shared by both DataSpace and DataProduct template/sample query flows.
111
+ */
112
+ async resolveDefaultParameters(
113
+ query: RawLambda,
114
+ ): Promise<Map<string, ValueSpecification> | undefined> {
115
+ const processedQueryParamValues = processQueryParameters(
116
+ query,
117
+ undefined,
118
+ this.urlQueryParamValues,
119
+ this.graphManagerState,
120
+ );
121
+ if (processedQueryParamValues?.size) {
122
+ try {
123
+ return await this.graphManagerState.graphManager.pureCodeToValueSpecifications(
124
+ processedQueryParamValues,
125
+ this.graphManagerState.graph,
126
+ );
127
+ } catch (error) {
128
+ assertErrorThrown(error);
129
+ this.applicationStore.logService.error(
130
+ LogEvent.create(LEGEND_QUERY_APP_EVENT.GENERIC_FAILURE),
131
+ `Error resolving preset query param values: ${error.message}`,
132
+ );
133
+ }
134
+ }
135
+ return undefined;
136
+ }
137
+
138
+ getPersistConfiguration(
139
+ lambda: RawLambda,
140
+ options?: { update: boolean | undefined },
141
+ ): QueryPersistConfiguration {
142
+ const entityPath = this.getEntityPath();
143
+ return {
144
+ defaultName: options?.update
145
+ ? `${extractElementNameFromPath(entityPath)}`
146
+ : `New Query for ${extractElementNameFromPath(entityPath)}[${this.templateQueryId}]`,
147
+ decorator: (query: Query): void => {
148
+ query.id = uuid();
149
+ query.groupId = this.groupId;
150
+ query.artifactId = this.artifactId;
151
+ query.versionId = this.versionId;
152
+ const decoratorTaggedValues = this.getQueryDecoratorTaggedValues();
153
+ if (decoratorTaggedValues) {
154
+ const taggedValues = decoratorTaggedValues.map((tv) => ({
155
+ profile: tv.profile,
156
+ tag: tv.tag,
157
+ value: tv.value,
158
+ }));
159
+ if (this.queryBuilderState?.sourceClass) {
160
+ taggedValues.push(
161
+ createQueryClassTaggedValue(
162
+ this.queryBuilderState.sourceClass.path,
163
+ ),
164
+ );
165
+ }
166
+ query.taggedValues = taggedValues;
167
+ } else if (this.queryBuilderState?.sourceClass) {
168
+ // Subclass handles tagged values directly (e.g., DataSpace only sets class tag)
169
+ query.taggedValues = [
170
+ createQueryClassTaggedValue(
171
+ this.queryBuilderState.sourceClass.path,
172
+ ),
173
+ ];
174
+ }
175
+ },
176
+ };
177
+ }
178
+
179
+ override decorateSearchSpecification(
180
+ val: QuerySearchSpecification,
181
+ ): QuerySearchSpecification {
182
+ const currentProjectCoordinates = new QueryProjectCoordinates();
183
+ currentProjectCoordinates.groupId = this.groupId;
184
+ currentProjectCoordinates.artifactId = this.artifactId;
185
+ val.projectCoordinates = [
186
+ currentProjectCoordinates,
187
+ ...Array.from(
188
+ this.graphManagerState.graph.dependencyManager.projectDependencyModelsIndex.keys(),
189
+ ).map((dependencyKey) => {
190
+ const { groupId, artifactId } = parseGACoordinates(dependencyKey);
191
+ const coordinates = new QueryProjectCoordinates();
192
+ coordinates.groupId = groupId;
193
+ coordinates.artifactId = artifactId;
194
+ return coordinates;
195
+ }),
196
+ ];
197
+ val.taggedValues = this.getSearchTaggedValues();
198
+ val.combineTaggedValuesCondition = true;
199
+ return val;
200
+ }
201
+
202
+ abstract override initializeQueryBuilderState(): Promise<QueryBuilderState>;
203
+ }
@@ -42,7 +42,7 @@ import {
42
42
  } from '@finos/legend-shared';
43
43
  import {
44
44
  type LightQuery,
45
- NativeModelExecutionContext,
45
+ type NativeModelExecutionContext,
46
46
  type RawLambda,
47
47
  type Runtime,
48
48
  type Service,
@@ -83,6 +83,7 @@ import {
83
83
  V1_ModelAccessPointGroupInfo,
84
84
  DataProductAccessType,
85
85
  type DataProductAnalysisQueryResult,
86
+ V1_AccessPointGroupInfo,
86
87
  } from '@finos/legend-graph';
87
88
  import {
88
89
  generateExistingQueryEditorRoute,
@@ -128,7 +129,6 @@ import {
128
129
  QueryBuilderDataBrowserWorkflow,
129
130
  QueryBuilderActionConfig,
130
131
  QUERY_LOADER_DEFAULT_QUERY_SEARCH_LIMIT,
131
- NativeModelDataProductExecutionState,
132
132
  ModelAccessPointDataProductExecutionState,
133
133
  } from '@finos/legend-query-builder';
134
134
  import { LegendQueryUserDataHelper } from '../__lib__/LegendQueryUserDataHelper.js';
@@ -1050,19 +1050,30 @@ export abstract class QueryEditorStore {
1050
1050
  const modelGroups = dataProduct.accessPointGroups.filter(
1051
1051
  filterByType(ModelAccessPointGroup),
1052
1052
  );
1053
- if (!modelGroups.length) {
1054
- throw new UnsupportedOperationError(
1055
- `Only Data Product with Model Access Points are currently supported in Query. ${dataProduct.path} does not have any Model Access Point Groups.`,
1056
- );
1057
- }
1058
1053
  if (accessId) {
1059
1054
  const matchingGroup = modelGroups.find((g) => g.id === accessId);
1060
1055
  if (matchingGroup) {
1061
1056
  return matchingGroup;
1062
1057
  }
1063
1058
  }
1064
- throw new UnsupportedOperationError(
1065
- `Can't resolve execution state for data product '${dataProduct.path}'${accessId ? ` with access ID '${accessId}'` : ''}`,
1059
+ // Search native model execution contexts
1060
+ const nativeAccess = dataProduct.nativeModelAccess;
1061
+ if (nativeAccess && accessId) {
1062
+ const matchingContext = nativeAccess.nativeModelExecutionContexts.find(
1063
+ (ctx) => ctx.key === accessId,
1064
+ );
1065
+ if (matchingContext) {
1066
+ return matchingContext;
1067
+ }
1068
+ }
1069
+ // Fall back: prioritize first model access point group over native default
1070
+ const firstGroup = modelGroups[0];
1071
+ if (firstGroup) {
1072
+ return firstGroup;
1073
+ }
1074
+ return guaranteeNonNullable(
1075
+ modelGroups[0] ?? nativeAccess?.defaultExecutionContext,
1076
+ `Can't resolve execution state for data product '${dataProduct.path}'${accessId ? ` with access ID '${accessId}'` : ''}. Data product must have model access point groups or native model access.`,
1066
1077
  );
1067
1078
  }
1068
1079
 
@@ -1089,7 +1100,7 @@ export abstract class QueryEditorStore {
1089
1100
  );
1090
1101
 
1091
1102
  let userEnvironment: string | undefined = persistedInfo?.env;
1092
- const userWarehouse: string | undefined =
1103
+ const userWarehouse: string =
1093
1104
  persistedInfo?.snowflakeWarehouse ?? 'LAKEHOUSE_CONSUMER_DEFAULT_WH';
1094
1105
  // 2. If no persisted environment, fetch from the server
1095
1106
  if (userEnvironment === undefined && this.lakehouseState) {
@@ -1180,16 +1191,23 @@ export abstract class QueryEditorStore {
1180
1191
  accessId,
1181
1192
  artifact,
1182
1193
  );
1183
- // 3.5. Create a LakehouseRuntime and add it to the graph
1184
- const packageableRuntime = await this.createLakehousePackageableRuntime(
1185
- dataProductPath,
1186
- {
1187
- groupId,
1188
- artifactId,
1189
- versionId,
1190
- },
1194
+ // 3.5. Create LakehouseRuntime only if the data product has at least one
1195
+ // model access point group.
1196
+ const hasAPGs = artifact.accessPointGroups.some(
1197
+ (g) => g instanceof V1_AccessPointGroupInfo,
1191
1198
  );
1192
- this.graphManagerState.graph.addElement(packageableRuntime, '_internal_');
1199
+ let packageableRuntime: PackageableRuntime | undefined;
1200
+ if (hasAPGs) {
1201
+ packageableRuntime = await this.createLakehousePackageableRuntime(
1202
+ dataProductPath,
1203
+ {
1204
+ groupId,
1205
+ artifactId,
1206
+ versionId,
1207
+ },
1208
+ );
1209
+ this.graphManagerState.graph.addElement(packageableRuntime, '_internal_');
1210
+ }
1193
1211
  // 4. Get the data product from the built graph
1194
1212
  const dataProduct =
1195
1213
  this.graphManagerState.graph.getDataProduct(dataProductPath);
@@ -1219,6 +1237,7 @@ export abstract class QueryEditorStore {
1219
1237
  this.depotServerClient,
1220
1238
  projectInfo,
1221
1239
  onDataProductChange,
1240
+ (path, gav) => this.createLakehousePackageableRuntime(path, gav),
1222
1241
  productSelectorState ??
1223
1242
  new DataProductSelectorState(
1224
1243
  this.depotServerClient,
@@ -1226,38 +1245,39 @@ export abstract class QueryEditorStore {
1226
1245
  ),
1227
1246
  onLegacyDataSpaceChange,
1228
1247
  undefined,
1229
- undefined,
1230
1248
  this.applicationStore.config.options.queryBuilderConfig,
1231
1249
  sourceInfo,
1232
1250
  );
1233
- // Pass pre-resolved state to avoid double-resolution
1234
- queryBuilderState.initWithDataProduct(dataProduct, resolvedState);
1235
1251
 
1236
- // 7. Wire in mapping coverage result
1237
- const mappingCoverageResult =
1238
- dataProductAnalysisResult.dataProductAnalysis.mappingToMappingCoverageResult?.get(
1239
- dataProductAnalysisResult.targetMappingPath,
1240
- );
1241
- if (mappingCoverageResult) {
1242
- queryBuilderState.explorerState.mappingModelCoverageAnalysisResult =
1243
- mappingCoverageResult;
1252
+ if (
1253
+ dataProductAnalysisResult.dataProductAnalysis
1254
+ .mappingToMappingCoverageResult
1255
+ ) {
1256
+ queryBuilderState.mappingToMappingCoverageResult =
1257
+ dataProductAnalysisResult.dataProductAnalysis.mappingToMappingCoverageResult;
1244
1258
  }
1245
1259
 
1246
- // init
1247
- const execValue = dataProductAnalysisResult.targetExecState;
1248
- queryBuilderState.executionState =
1249
- execValue instanceof NativeModelExecutionContext
1250
- ? new NativeModelDataProductExecutionState(execValue, queryBuilderState)
1251
- : new ModelAccessPointDataProductExecutionState(
1252
- execValue,
1253
- queryBuilderState,
1254
- ).withAdhocRuntime();
1255
- queryBuilderState.changeMapping(queryBuilderState.executionState.mapping);
1256
- queryBuilderState.changeRuntime(
1257
- new RuntimePointer(
1258
- PackageableElementExplicitReference.create(packageableRuntime),
1259
- ),
1260
+ // Pass pre-resolved state to avoid double-resolution
1261
+ queryBuilderState.initWithDataProduct(
1262
+ dataProduct,
1263
+ undefined,
1264
+ resolvedState,
1260
1265
  );
1266
+
1267
+ // 8. Wire in lakehouse runtime and adhoc-runtime flag for MODEL mode
1268
+ if (
1269
+ queryBuilderState.executionState instanceof
1270
+ ModelAccessPointDataProductExecutionState
1271
+ ) {
1272
+ queryBuilderState.executionState.withAdhocRuntime();
1273
+ if (packageableRuntime) {
1274
+ queryBuilderState.changeRuntime(
1275
+ new RuntimePointer(
1276
+ PackageableElementExplicitReference.create(packageableRuntime),
1277
+ ),
1278
+ );
1279
+ }
1280
+ }
1261
1281
  return queryBuilderState;
1262
1282
  }
1263
1283
  }
@@ -0,0 +1,135 @@
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 { DataProductAccessType } from '@finos/legend-graph';
18
+ import { type DepotServerClient } from '@finos/legend-server-depot';
19
+ import { IllegalStateError, guaranteeNonNullable } from '@finos/legend-shared';
20
+ import type { QueryBuilderState } from '@finos/legend-query-builder';
21
+ import type { LegendQueryApplicationStore } from '../LegendQueryBaseStore.js';
22
+ import { generateDataProductSampleQueryRoute } from '../../__lib__/LegendQueryNavigation.js';
23
+ import { DataProductSelectorState } from '../data-space/DataProductSelectorState.js';
24
+ import { createQueryDataProductTaggedValue } from '../../components/data-product/QueryDataProductUtil.js';
25
+ import { BaseTemplateQueryCreatorStore } from '../BaseTemplateQueryCreatorStore.js';
26
+
27
+ export class DataProductSampleQueryCreatorStore extends BaseTemplateQueryCreatorStore {
28
+ readonly dataProductPath: string;
29
+
30
+ constructor(
31
+ applicationStore: LegendQueryApplicationStore,
32
+ depotServerClient: DepotServerClient,
33
+ groupId: string,
34
+ artifactId: string,
35
+ versionId: string,
36
+ dataProductPath: string,
37
+ sampleQueryId: string,
38
+ urlQueryParamValues: Record<string, string> | undefined,
39
+ ) {
40
+ super(
41
+ applicationStore,
42
+ depotServerClient,
43
+ groupId,
44
+ artifactId,
45
+ versionId,
46
+ sampleQueryId,
47
+ urlQueryParamValues,
48
+ );
49
+ this.dataProductPath = dataProductPath;
50
+ }
51
+
52
+ override getEditorRoute(): string {
53
+ return generateDataProductSampleQueryRoute(
54
+ this.groupId,
55
+ this.artifactId,
56
+ this.versionId,
57
+ this.dataProductPath,
58
+ this.templateQueryId,
59
+ );
60
+ }
61
+
62
+ override getEntityPath(): string {
63
+ return this.dataProductPath;
64
+ }
65
+
66
+ override getSearchTaggedValues(): {
67
+ profile: string;
68
+ tag: string;
69
+ value: string;
70
+ }[] {
71
+ return [createQueryDataProductTaggedValue(this.dataProductPath)];
72
+ }
73
+
74
+ override getQueryDecoratorTaggedValues():
75
+ | { profile: string; tag: string; value: string }[]
76
+ | undefined {
77
+ return [createQueryDataProductTaggedValue(this.dataProductPath)];
78
+ }
79
+
80
+ async initializeQueryBuilderState(): Promise<QueryBuilderState> {
81
+ const artifact = await this.fetchDataProductArtifact(
82
+ this.groupId,
83
+ this.artifactId,
84
+ this.versionId,
85
+ this.dataProductPath,
86
+ );
87
+
88
+ const nativeModelAccess = guaranteeNonNullable(
89
+ artifact.nativeModelAccess,
90
+ `Data product '${this.dataProductPath}' does not have native model access`,
91
+ );
92
+ const sampleQuery = nativeModelAccess.sampleQueries?.find(
93
+ (sq) => sq.info.id === this.templateQueryId,
94
+ );
95
+ if (!sampleQuery) {
96
+ throw new IllegalStateError(
97
+ `Can't find sample query with id '${this.templateQueryId}' in data product '${this.dataProductPath}'`,
98
+ );
99
+ }
100
+ this.templateQueryTitle = sampleQuery.title;
101
+
102
+ const accessId =
103
+ sampleQuery.info.executionContextKey ??
104
+ nativeModelAccess.defaultExecutionContext;
105
+
106
+ const queryBuilderState = await this.buildDataProductQueryBuilderState(
107
+ this.groupId,
108
+ this.artifactId,
109
+ this.versionId,
110
+ this.dataProductPath,
111
+ artifact,
112
+ accessId,
113
+ DataProductAccessType.NATIVE,
114
+ async () => {
115
+ this.applicationStore.notificationService.notifyWarning(
116
+ `Can't switch data product while visiting a sample query`,
117
+ );
118
+ },
119
+ undefined,
120
+ new DataProductSelectorState(
121
+ this.depotServerClient,
122
+ this.applicationStore,
123
+ ),
124
+ );
125
+
126
+ const query = await this.graphManagerState.graphManager.pureCodeToLambda(
127
+ sampleQuery.info.query,
128
+ );
129
+
130
+ const defaultParameters = await this.resolveDefaultParameters(query);
131
+ queryBuilderState.initializeWithQuery(query, defaultParameters);
132
+
133
+ return queryBuilderState;
134
+ }
135
+ }
@@ -34,14 +34,18 @@ export const resolveDefaultDataProductAccessType = (
34
34
  };
35
35
  }
36
36
 
37
- // const native =
38
- // dataProductArtifact.nativeModelAccess?.nativeModelExecutionContexts[0];
39
- // if (native) {
40
- // return {
41
- // type: DataProductAccessType.NATIVE,
42
- // id: native.key,
43
- // };
44
- // }
37
+ // start on ModelAPG if it exists, then fallback to native access
38
+ const nativeAccess = dataProductArtifact.nativeModelAccess;
39
+ if (nativeAccess) {
40
+ const defaultKey = nativeAccess.defaultExecutionContext;
41
+ const native =
42
+ nativeAccess.nativeModelExecutionContexts.find(
43
+ (ctx) => ctx.key === defaultKey,
44
+ ) ?? nativeAccess.nativeModelExecutionContexts[0];
45
+ if (native) {
46
+ return { type: DataProductAccessType.NATIVE, id: native.key };
47
+ }
48
+ }
45
49
  throw new Error(
46
50
  `Data Product not supported for querying on legend query ${dataProductArtifact.dataProduct.path}. Must contain a model access point or native model access.`,
47
51
  );
@@ -36,6 +36,7 @@ import type {
36
36
  } from '@finos/legend-storage';
37
37
  import {
38
38
  LegendSDLC,
39
+ type PackageableRuntime,
39
40
  type Class,
40
41
  type DataProduct,
41
42
  type GraphManagerState,
@@ -62,6 +63,10 @@ export class LegendQueryDataProductQueryBuilderState extends DataProductQueryBui
62
63
  | ((val: ResolvedDataSpaceEntityWithOrigin) => void)
63
64
  | undefined;
64
65
  productSelectorState: DataProductSelectorState;
66
+ createLakehousePackageableRuntime: (
67
+ dataProductPath: string,
68
+ gav: { groupId: string; artifactId: string; versionId: string },
69
+ ) => Promise<PackageableRuntime>;
65
70
 
66
71
  constructor(
67
72
  applicationStore: LegendQueryApplicationStore,
@@ -74,13 +79,14 @@ export class LegendQueryDataProductQueryBuilderState extends DataProductQueryBui
74
79
  depotServerClient: DepotServerClient,
75
80
  project: ProjectGAVCoordinates,
76
81
  onDataProductChange: (val: DepotEntityWithOrigin) => Promise<void>,
82
+ createLakehousePackageableRuntime: (
83
+ dataProductPath: string,
84
+ gav: { groupId: string; artifactId: string; versionId: string },
85
+ ) => Promise<PackageableRuntime>,
77
86
  productSelectorState: DataProductSelectorState,
78
87
  onLegacyDataSpaceChange?:
79
88
  | ((val: ResolvedDataSpaceEntityWithOrigin) => void)
80
89
  | undefined,
81
- onExecutionContextChange?:
82
- | ((val: NativeModelExecutionContext) => void)
83
- | undefined,
84
90
  onClassChange?: ((val: Class) => void) | undefined,
85
91
  config?: QueryBuilderConfig | undefined,
86
92
  sourceInfo?: QueryableSourceInfo | undefined,
@@ -95,7 +101,6 @@ export class LegendQueryDataProductQueryBuilderState extends DataProductQueryBui
95
101
  executionState,
96
102
  undefined,
97
103
  onDataProductChange,
98
- onExecutionContextChange,
99
104
  onClassChange,
100
105
  config,
101
106
  sourceInfo,
@@ -104,6 +109,7 @@ export class LegendQueryDataProductQueryBuilderState extends DataProductQueryBui
104
109
  this.depotServerClient = depotServerClient;
105
110
  this.productSelectorState = productSelectorState;
106
111
  this.onLegacyDataSpaceChange = onLegacyDataSpaceChange;
112
+ this.createLakehousePackageableRuntime = createLakehousePackageableRuntime;
107
113
  }
108
114
 
109
115
  override handleDataProductChange(val: DepotEntityWithOrigin): void {
@@ -117,6 +123,32 @@ export class LegendQueryDataProductQueryBuilderState extends DataProductQueryBui
117
123
  }
118
124
  }
119
125
 
126
+ override async prepareAccessForExecution(): Promise<void> {
127
+ const origin = this.graphManagerState.graph.origin;
128
+ if (
129
+ this.executionState instanceof
130
+ ModelAccessPointDataProductExecutionState &&
131
+ origin instanceof LegendSDLC
132
+ ) {
133
+ const packageableRuntime = await this.createLakehousePackageableRuntime(
134
+ this.dataProduct.path,
135
+ {
136
+ groupId: origin.groupId,
137
+ artifactId: origin.artifactId,
138
+ versionId: origin.versionId,
139
+ },
140
+ );
141
+ this.graphManagerState.graph.addElement(packageableRuntime, '_internal_');
142
+
143
+ if (!this.executionState.adhocRuntime) {
144
+ this.executionState.withAdhocRuntime();
145
+ }
146
+
147
+ this.executionState.changeSelectedRuntime(packageableRuntime);
148
+ }
149
+ await super.prepareAccessForExecution();
150
+ }
151
+
120
152
  override get dataProductOptions(): DataProductOption[] {
121
153
  const graphOptions = super.dataProductOptions;
122
154
  const depotOptions: DataProductOption[] = [
@@ -155,7 +155,7 @@ export class QueryableDataProduct extends LegendQueryableElement {
155
155
  ) {
156
156
  super(groupId, artifactId, versionId);
157
157
  this.dataProductPath = dataProductPath;
158
- this.dataProductType = dataProductType;
158
+ this.dataProductType = dataProductType.toLowerCase();
159
159
  this.id = id;
160
160
  }
161
161