@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.
- package/lib/__lib__/LegendQueryNavigation.d.ts +16 -2
- package/lib/__lib__/LegendQueryNavigation.d.ts.map +1 -1
- package/lib/__lib__/LegendQueryNavigation.js +21 -2
- package/lib/__lib__/LegendQueryNavigation.js.map +1 -1
- package/lib/components/Core_LegendQueryApplicationPlugin.d.ts +2 -1
- package/lib/components/Core_LegendQueryApplicationPlugin.d.ts.map +1 -1
- package/lib/components/Core_LegendQueryApplicationPlugin.js +13 -0
- package/lib/components/Core_LegendQueryApplicationPlugin.js.map +1 -1
- package/lib/components/LegendQueryWebApplication.d.ts.map +1 -1
- package/lib/components/LegendQueryWebApplication.js +2 -1
- package/lib/components/LegendQueryWebApplication.js.map +1 -1
- package/lib/components/__test-utils__/QueryEditorComponentTestUtils.d.ts +14 -2
- package/lib/components/__test-utils__/QueryEditorComponentTestUtils.d.ts.map +1 -1
- package/lib/components/__test-utils__/QueryEditorComponentTestUtils.js +93 -7
- package/lib/components/__test-utils__/QueryEditorComponentTestUtils.js.map +1 -1
- package/lib/components/data-product/DataProductInfo.d.ts.map +1 -1
- package/lib/components/data-product/DataProductInfo.js +1 -1
- package/lib/components/data-product/DataProductInfo.js.map +1 -1
- package/lib/components/data-product/DataProductSampleQueryCreator.d.ts +19 -0
- package/lib/components/data-product/DataProductSampleQueryCreator.d.ts.map +1 -0
- package/lib/components/data-product/DataProductSampleQueryCreator.js +53 -0
- package/lib/components/data-product/DataProductSampleQueryCreator.js.map +1 -0
- package/lib/components/data-product/DataProductSampleQueryPanel.d.ts +23 -0
- package/lib/components/data-product/DataProductSampleQueryPanel.d.ts.map +1 -0
- package/lib/components/data-product/DataProductSampleQueryPanel.js +95 -0
- package/lib/components/data-product/DataProductSampleQueryPanel.js.map +1 -0
- package/lib/index.css +1 -1
- package/lib/light-mode.css +1 -1
- package/lib/package.json +1 -1
- package/lib/stores/BaseTemplateQueryCreatorStore.d.ts +68 -0
- package/lib/stores/BaseTemplateQueryCreatorStore.d.ts.map +1 -0
- package/lib/stores/BaseTemplateQueryCreatorStore.js +120 -0
- package/lib/stores/BaseTemplateQueryCreatorStore.js.map +1 -0
- package/lib/stores/QueryEditorStore.d.ts +1 -1
- package/lib/stores/QueryEditorStore.d.ts.map +1 -1
- package/lib/stores/QueryEditorStore.js +43 -29
- package/lib/stores/QueryEditorStore.js.map +1 -1
- package/lib/stores/data-product/DataProductSampleQueryCreatorStore.d.ts +37 -0
- package/lib/stores/data-product/DataProductSampleQueryCreatorStore.d.ts.map +1 -0
- package/lib/stores/data-product/DataProductSampleQueryCreatorStore.js +60 -0
- package/lib/stores/data-product/DataProductSampleQueryCreatorStore.js.map +1 -0
- package/lib/stores/data-product/query-builder/DataProductArtifactHelper.d.ts.map +1 -1
- package/lib/stores/data-product/query-builder/DataProductArtifactHelper.js +9 -8
- package/lib/stores/data-product/query-builder/DataProductArtifactHelper.js.map +1 -1
- package/lib/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.d.ts +12 -2
- package/lib/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.d.ts.map +1 -1
- package/lib/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.js +22 -2
- package/lib/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.js.map +1 -1
- package/lib/stores/data-space/DataProductQueryCreatorStore.js +1 -1
- package/lib/stores/data-space/DataProductQueryCreatorStore.js.map +1 -1
- package/lib/stores/data-space/DataSpaceTemplateQueryCreatorStore.d.ts +14 -18
- package/lib/stores/data-space/DataSpaceTemplateQueryCreatorStore.d.ts.map +1 -1
- package/lib/stores/data-space/DataSpaceTemplateQueryCreatorStore.js +15 -80
- package/lib/stores/data-space/DataSpaceTemplateQueryCreatorStore.js.map +1 -1
- package/package.json +13 -13
- package/src/__lib__/LegendQueryNavigation.ts +43 -5
- package/src/components/Core_LegendQueryApplicationPlugin.tsx +17 -0
- package/src/components/LegendQueryWebApplication.tsx +5 -0
- package/src/components/__test-utils__/QueryEditorComponentTestUtils.tsx +237 -5
- package/src/components/data-product/DataProductInfo.tsx +12 -10
- package/src/components/data-product/DataProductSampleQueryCreator.tsx +114 -0
- package/src/components/data-product/DataProductSampleQueryPanel.tsx +219 -0
- package/src/stores/BaseTemplateQueryCreatorStore.ts +203 -0
- package/src/stores/QueryEditorStore.ts +64 -44
- package/src/stores/data-product/DataProductSampleQueryCreatorStore.ts +135 -0
- package/src/stores/data-product/query-builder/DataProductArtifactHelper.ts +12 -8
- package/src/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.ts +36 -4
- package/src/stores/data-space/DataProductQueryCreatorStore.ts +1 -1
- package/src/stores/data-space/DataSpaceTemplateQueryCreatorStore.ts +31 -126
- 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
|
-
|
|
1065
|
-
|
|
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
|
|
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
|
|
1184
|
-
|
|
1185
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
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
|
-
//
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
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
|
-
//
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
|