@finos/legend-application-query 13.8.8 → 13.8.10
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 +91 -5
- package/lib/components/__test-utils__/QueryEditorComponentTestUtils.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 +2 -2
- package/lib/stores/QueryEditorStore.d.ts.map +1 -1
- package/lib/stores/QueryEditorStore.js +64 -30
- 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 -0
- 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 +40 -6
- 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 +227 -3
- 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 +105 -51
- package/src/stores/data-product/DataProductSampleQueryCreatorStore.ts +135 -0
- package/src/stores/data-product/query-builder/DataProductArtifactHelper.ts +13 -0
- package/src/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.ts +70 -7
- 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,8 @@ import {
|
|
|
83
83
|
V1_ModelAccessPointGroupInfo,
|
|
84
84
|
DataProductAccessType,
|
|
85
85
|
type DataProductAnalysisQueryResult,
|
|
86
|
+
LakehouseAccessPoint,
|
|
87
|
+
type Accessor,
|
|
86
88
|
} from '@finos/legend-graph';
|
|
87
89
|
import {
|
|
88
90
|
generateExistingQueryEditorRoute,
|
|
@@ -128,8 +130,9 @@ import {
|
|
|
128
130
|
QueryBuilderDataBrowserWorkflow,
|
|
129
131
|
QueryBuilderActionConfig,
|
|
130
132
|
QUERY_LOADER_DEFAULT_QUERY_SEARCH_LIMIT,
|
|
131
|
-
NativeModelDataProductExecutionState,
|
|
132
133
|
ModelAccessPointDataProductExecutionState,
|
|
134
|
+
LakehouseDataProductExecutionState,
|
|
135
|
+
resolveDataProductAccessor,
|
|
133
136
|
} from '@finos/legend-query-builder';
|
|
134
137
|
import { LegendQueryUserDataHelper } from '../__lib__/LegendQueryUserDataHelper.js';
|
|
135
138
|
import { LegendQueryTelemetryHelper } from '../__lib__/LegendQueryTelemetryHelper.js';
|
|
@@ -1045,24 +1048,53 @@ export abstract class QueryEditorStore {
|
|
|
1045
1048
|
resolveDataProductExecutionState(
|
|
1046
1049
|
dataProduct: DataProduct,
|
|
1047
1050
|
accessId: string | undefined,
|
|
1048
|
-
):
|
|
1051
|
+
):
|
|
1052
|
+
| NativeModelExecutionContext
|
|
1053
|
+
| ModelAccessPointGroup
|
|
1054
|
+
| LakehouseAccessPoint {
|
|
1049
1055
|
// Search model access point groups
|
|
1050
1056
|
const modelGroups = dataProduct.accessPointGroups.filter(
|
|
1051
1057
|
filterByType(ModelAccessPointGroup),
|
|
1052
1058
|
);
|
|
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
1059
|
if (accessId) {
|
|
1059
1060
|
const matchingGroup = modelGroups.find((g) => g.id === accessId);
|
|
1060
1061
|
if (matchingGroup) {
|
|
1061
1062
|
return matchingGroup;
|
|
1062
1063
|
}
|
|
1063
1064
|
}
|
|
1064
|
-
|
|
1065
|
-
|
|
1065
|
+
// Search native model execution contexts
|
|
1066
|
+
const nativeAccess = dataProduct.nativeModelAccess;
|
|
1067
|
+
if (nativeAccess && accessId) {
|
|
1068
|
+
const matchingContext = nativeAccess.nativeModelExecutionContexts.find(
|
|
1069
|
+
(ctx) => ctx.key === accessId,
|
|
1070
|
+
);
|
|
1071
|
+
if (matchingContext) {
|
|
1072
|
+
return matchingContext;
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
// Fall back: prioritize first model access point group over native default
|
|
1077
|
+
const firstGroup = modelGroups[0];
|
|
1078
|
+
if (firstGroup) {
|
|
1079
|
+
return firstGroup;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
// Search lakehouse access points
|
|
1083
|
+
const lakehouseAccessPoints = dataProduct.accessPointGroups
|
|
1084
|
+
.flatMap((group) => group.accessPoints)
|
|
1085
|
+
.filter(filterByType(LakehouseAccessPoint));
|
|
1086
|
+
if (accessId) {
|
|
1087
|
+
const matchingLakehouseAP = lakehouseAccessPoints.find(
|
|
1088
|
+
(ap) => ap.id === accessId,
|
|
1089
|
+
);
|
|
1090
|
+
if (matchingLakehouseAP) {
|
|
1091
|
+
return matchingLakehouseAP;
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
return guaranteeNonNullable(
|
|
1096
|
+
modelGroups[0] ?? nativeAccess?.defaultExecutionContext,
|
|
1097
|
+
`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
1098
|
);
|
|
1067
1099
|
}
|
|
1068
1100
|
|
|
@@ -1089,7 +1121,7 @@ export abstract class QueryEditorStore {
|
|
|
1089
1121
|
);
|
|
1090
1122
|
|
|
1091
1123
|
let userEnvironment: string | undefined = persistedInfo?.env;
|
|
1092
|
-
const userWarehouse: string
|
|
1124
|
+
const userWarehouse: string =
|
|
1093
1125
|
persistedInfo?.snowflakeWarehouse ?? 'LAKEHOUSE_CONSUMER_DEFAULT_WH';
|
|
1094
1126
|
// 2. If no persisted environment, fetch from the server
|
|
1095
1127
|
if (userEnvironment === undefined && this.lakehouseState) {
|
|
@@ -1180,16 +1212,6 @@ export abstract class QueryEditorStore {
|
|
|
1180
1212
|
accessId,
|
|
1181
1213
|
artifact,
|
|
1182
1214
|
);
|
|
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
|
-
},
|
|
1191
|
-
);
|
|
1192
|
-
this.graphManagerState.graph.addElement(packageableRuntime, '_internal_');
|
|
1193
1215
|
// 4. Get the data product from the built graph
|
|
1194
1216
|
const dataProduct =
|
|
1195
1217
|
this.graphManagerState.graph.getDataProduct(dataProductPath);
|
|
@@ -1199,6 +1221,23 @@ export abstract class QueryEditorStore {
|
|
|
1199
1221
|
accessId,
|
|
1200
1222
|
);
|
|
1201
1223
|
|
|
1224
|
+
// 5.5. Create LakehouseRuntime if the resolved state is a model access
|
|
1225
|
+
// point group or a lakehouse access point
|
|
1226
|
+
let packageableRuntime: PackageableRuntime | undefined;
|
|
1227
|
+
if (
|
|
1228
|
+
resolvedState instanceof ModelAccessPointGroup ||
|
|
1229
|
+
resolvedState instanceof LakehouseAccessPoint
|
|
1230
|
+
) {
|
|
1231
|
+
packageableRuntime = await this.createLakehousePackageableRuntime(
|
|
1232
|
+
dataProductPath,
|
|
1233
|
+
{
|
|
1234
|
+
groupId,
|
|
1235
|
+
artifactId,
|
|
1236
|
+
versionId,
|
|
1237
|
+
},
|
|
1238
|
+
);
|
|
1239
|
+
this.graphManagerState.graph.addElement(packageableRuntime, '_internal_');
|
|
1240
|
+
}
|
|
1202
1241
|
// 6. Create query builder state
|
|
1203
1242
|
const projectInfo = { groupId, artifactId, versionId };
|
|
1204
1243
|
const sourceInfo = {
|
|
@@ -1219,6 +1258,7 @@ export abstract class QueryEditorStore {
|
|
|
1219
1258
|
this.depotServerClient,
|
|
1220
1259
|
projectInfo,
|
|
1221
1260
|
onDataProductChange,
|
|
1261
|
+
(path, gav) => this.createLakehousePackageableRuntime(path, gav),
|
|
1222
1262
|
productSelectorState ??
|
|
1223
1263
|
new DataProductSelectorState(
|
|
1224
1264
|
this.depotServerClient,
|
|
@@ -1226,44 +1266,58 @@ export abstract class QueryEditorStore {
|
|
|
1226
1266
|
),
|
|
1227
1267
|
onLegacyDataSpaceChange,
|
|
1228
1268
|
undefined,
|
|
1229
|
-
undefined,
|
|
1230
1269
|
this.applicationStore.config.options.queryBuilderConfig,
|
|
1231
1270
|
sourceInfo,
|
|
1232
1271
|
);
|
|
1233
|
-
// Pass pre-resolved state to avoid double-resolution
|
|
1234
|
-
queryBuilderState.initWithDataProduct(
|
|
1235
|
-
dataProduct,
|
|
1236
|
-
undefined,
|
|
1237
|
-
resolvedState,
|
|
1238
|
-
);
|
|
1239
1272
|
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1273
|
+
if (
|
|
1274
|
+
dataProductAnalysisResult.dataProductAnalysis
|
|
1275
|
+
.mappingToMappingCoverageResult
|
|
1276
|
+
) {
|
|
1277
|
+
queryBuilderState.mappingToMappingCoverageResult =
|
|
1278
|
+
dataProductAnalysisResult.dataProductAnalysis.mappingToMappingCoverageResult;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
let accessor: Accessor | undefined;
|
|
1282
|
+
if (resolvedState instanceof LakehouseAccessPoint) {
|
|
1283
|
+
accessor = resolveDataProductAccessor(
|
|
1284
|
+
dataProduct,
|
|
1285
|
+
resolvedState,
|
|
1286
|
+
this.graphManagerState.graph,
|
|
1287
|
+
artifact,
|
|
1288
|
+
undefined,
|
|
1244
1289
|
);
|
|
1245
|
-
if (mappingCoverageResult) {
|
|
1246
|
-
queryBuilderState.explorerState.mappingModelCoverageAnalysisResult =
|
|
1247
|
-
mappingCoverageResult;
|
|
1248
1290
|
}
|
|
1291
|
+
// Pass pre-resolved state to avoid double-resolution
|
|
1292
|
+
queryBuilderState.initWithDataProduct(dataProduct, accessor, resolvedState);
|
|
1249
1293
|
|
|
1250
|
-
//
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1294
|
+
// 8. Wire in lakehouse runtime and adhoc-runtime flag for MODEL or LAKEHOUSE mode
|
|
1295
|
+
if (
|
|
1296
|
+
queryBuilderState.executionState instanceof
|
|
1297
|
+
ModelAccessPointDataProductExecutionState
|
|
1298
|
+
) {
|
|
1299
|
+
queryBuilderState.executionState.withAdhocRuntime();
|
|
1300
|
+
if (packageableRuntime) {
|
|
1301
|
+
queryBuilderState.changeRuntime(
|
|
1302
|
+
new RuntimePointer(
|
|
1303
|
+
PackageableElementExplicitReference.create(packageableRuntime),
|
|
1304
|
+
),
|
|
1305
|
+
);
|
|
1306
|
+
}
|
|
1307
|
+
} else if (
|
|
1308
|
+
queryBuilderState.executionState instanceof
|
|
1309
|
+
LakehouseDataProductExecutionState
|
|
1310
|
+
) {
|
|
1311
|
+
queryBuilderState.executionState.withAdhocRuntime();
|
|
1312
|
+
if (packageableRuntime) {
|
|
1313
|
+
queryBuilderState.executionState.selectedRuntime = packageableRuntime;
|
|
1314
|
+
queryBuilderState.changeRuntime(
|
|
1315
|
+
new RuntimePointer(
|
|
1316
|
+
PackageableElementExplicitReference.create(packageableRuntime),
|
|
1317
|
+
),
|
|
1318
|
+
);
|
|
1319
|
+
}
|
|
1261
1320
|
}
|
|
1262
|
-
queryBuilderState.changeRuntime(
|
|
1263
|
-
new RuntimePointer(
|
|
1264
|
-
PackageableElementExplicitReference.create(packageableRuntime),
|
|
1265
|
-
),
|
|
1266
|
-
);
|
|
1267
1321
|
return queryBuilderState;
|
|
1268
1322
|
}
|
|
1269
1323
|
}
|
|
@@ -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
|
+
}
|
|
@@ -33,6 +33,19 @@ export const resolveDefaultDataProductAccessType = (
|
|
|
33
33
|
id: modelAcessGroup.id,
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
|
+
|
|
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
|
+
}
|
|
36
49
|
throw new Error(
|
|
37
50
|
`Data Product not supported for querying on legend query ${dataProductArtifact.dataProduct.path}. Must contain a model access point or native model access.`,
|
|
38
51
|
);
|