@finos/legend-application-query 13.8.55 → 13.8.57
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/README.md +7 -0
- package/docs/data-space-analytics-and-entry-points.md +644 -0
- package/lib/__lib__/LegendQueryNavigation.d.ts +0 -13
- package/lib/__lib__/LegendQueryNavigation.d.ts.map +1 -1
- package/lib/__lib__/LegendQueryNavigation.js +0 -13
- package/lib/__lib__/LegendQueryNavigation.js.map +1 -1
- package/lib/components/Core_LegendQueryApplicationPlugin.d.ts +1 -2
- package/lib/components/Core_LegendQueryApplicationPlugin.d.ts.map +1 -1
- package/lib/components/Core_LegendQueryApplicationPlugin.js +0 -13
- package/lib/components/Core_LegendQueryApplicationPlugin.js.map +1 -1
- package/lib/components/LegendQueryWebApplication.d.ts.map +1 -1
- package/lib/components/LegendQueryWebApplication.js +1 -2
- package/lib/components/LegendQueryWebApplication.js.map +1 -1
- package/lib/components/__test-utils__/QueryEditorComponentTestUtils.d.ts +1 -17
- package/lib/components/__test-utils__/QueryEditorComponentTestUtils.d.ts.map +1 -1
- package/lib/components/__test-utils__/QueryEditorComponentTestUtils.js +2 -175
- package/lib/components/__test-utils__/QueryEditorComponentTestUtils.js.map +1 -1
- package/lib/index.css +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/light-mode.css +1 -1
- package/lib/package.json +1 -1
- package/lib/stores/QueryEditorStore.d.ts +4 -4
- package/lib/stores/QueryEditorStore.d.ts.map +1 -1
- package/lib/stores/QueryEditorStore.js +9 -53
- package/lib/stores/QueryEditorStore.js.map +1 -1
- package/lib/stores/data-product/query-builder/DataProductArtifactHelper.d.ts.map +1 -1
- package/lib/stores/data-product/query-builder/DataProductArtifactHelper.js +1 -10
- package/lib/stores/data-product/query-builder/DataProductArtifactHelper.js.map +1 -1
- package/lib/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.d.ts +3 -2
- package/lib/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.d.ts.map +1 -1
- package/lib/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.js +21 -19
- package/lib/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.js.map +1 -1
- package/package.json +8 -8
- package/src/__lib__/LegendQueryNavigation.ts +0 -45
- package/src/components/Core_LegendQueryApplicationPlugin.tsx +0 -17
- package/src/components/LegendQueryWebApplication.tsx +0 -5
- package/src/components/__test-utils__/QueryEditorComponentTestUtils.tsx +0 -430
- package/src/index.ts +0 -1
- package/src/stores/QueryEditorStore.ts +10 -68
- package/src/stores/data-product/query-builder/DataProductArtifactHelper.ts +1 -13
- package/src/stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.ts +33 -43
- package/tsconfig.json +0 -3
- package/lib/components/data-product/DataProductSampleQueryCreator.d.ts +0 -19
- package/lib/components/data-product/DataProductSampleQueryCreator.d.ts.map +0 -1
- package/lib/components/data-product/DataProductSampleQueryCreator.js +0 -53
- package/lib/components/data-product/DataProductSampleQueryCreator.js.map +0 -1
- package/lib/components/data-product/DataProductSampleQueryPanel.d.ts +0 -23
- package/lib/components/data-product/DataProductSampleQueryPanel.d.ts.map +0 -1
- package/lib/components/data-product/DataProductSampleQueryPanel.js +0 -95
- package/lib/components/data-product/DataProductSampleQueryPanel.js.map +0 -1
- package/lib/stores/data-product/DataProductSampleQueryCreatorStore.d.ts +0 -39
- package/lib/stores/data-product/DataProductSampleQueryCreatorStore.d.ts.map +0 -1
- package/lib/stores/data-product/DataProductSampleQueryCreatorStore.js +0 -71
- package/lib/stores/data-product/DataProductSampleQueryCreatorStore.js.map +0 -1
- package/src/components/data-product/DataProductSampleQueryCreator.tsx +0 -114
- package/src/components/data-product/DataProductSampleQueryPanel.tsx +0 -219
- package/src/stores/data-product/DataProductSampleQueryCreatorStore.ts +0 -152
package/README.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
1
|
# @finos/legend-application-query
|
|
2
2
|
|
|
3
3
|
Legend Query core
|
|
4
|
+
|
|
5
|
+
## Documentation
|
|
6
|
+
|
|
7
|
+
- [Data Space Analytics, the Minimal Graph, and Entry Points](./docs/data-space-analytics-and-entry-points.md) —
|
|
8
|
+
why data space analytics exists, how the minimal graph is cached and built,
|
|
9
|
+
every entry point into the query editor, and the saved-query types each one
|
|
10
|
+
produces.
|
|
@@ -0,0 +1,644 @@
|
|
|
1
|
+
# Legend Query — Data Space Analytics, the Minimal Graph, and Entry Points
|
|
2
|
+
|
|
3
|
+
> Technical reference for `@finos/legend-application-query`.
|
|
4
|
+
>
|
|
5
|
+
> Audience: engineers working on Legend Query, the Data Space DSL extension
|
|
6
|
+
> (`@finos/legend-extension-dsl-data-space`), or the query builder
|
|
7
|
+
> (`@finos/legend-query-builder`).
|
|
8
|
+
|
|
9
|
+
This document explains:
|
|
10
|
+
|
|
11
|
+
1. [Why data space analytics exists](#1-why-data-space-analytics-exists) — the cost model that motivates it.
|
|
12
|
+
2. [The minimal graph](#2-the-minimal-graph) — what is cached, how it is keyed, and when it is used.
|
|
13
|
+
3. [Entry points into Legend Query](#3-entry-points-into-legend-query) — every route that can open the query editor, and how each one builds its graph.
|
|
14
|
+
4. [Saved query types](#4-saved-query-types) — how each entry point persists a query, and how the editor reconstitutes it.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 1. Why data space analytics exists
|
|
19
|
+
|
|
20
|
+
### 1.1 The cost of a full graph
|
|
21
|
+
|
|
22
|
+
Legend Query's query builder operates on a **PURE graph** — a fully resolved,
|
|
23
|
+
in-memory metamodel. Historically, opening the editor meant:
|
|
24
|
+
|
|
25
|
+
1. Fetch **every entity** of the project version from the depot server.
|
|
26
|
+
2. Fetch **every entity of every dependency** (transitively).
|
|
27
|
+
3. Deserialize the protocol models (`V1_*`) and run the graph builder, which
|
|
28
|
+
resolves every reference (property types, association ends, mapping source
|
|
29
|
+
classes, store/connection pointers, …) into real metamodel objects.
|
|
30
|
+
|
|
31
|
+
For a large enterprise project with deep dependency trees, this dominates
|
|
32
|
+
time-to-first-interaction. And most of it is wasted work: to build a query
|
|
33
|
+
against a data space, the user needs the **classes reachable from one mapping**
|
|
34
|
+
plus the mapping/runtime pointers — not the whole model, not the persistence
|
|
35
|
+
pipelines, not the other 40 mappings in the project.
|
|
36
|
+
|
|
37
|
+
### 1.2 The insight
|
|
38
|
+
|
|
39
|
+
A data space is a curated, published surface over a project:
|
|
40
|
+
|
|
41
|
+
- a fixed set of **execution contexts**, each pinning a `mapping` + `defaultRuntime`
|
|
42
|
+
- a documented model
|
|
43
|
+
- a set of executables (templates, services, functions)
|
|
44
|
+
|
|
45
|
+
All of that is **known at project build time**. It does not depend on who opens
|
|
46
|
+
it or what they intend to query. So it can be computed once, in the engine, at
|
|
47
|
+
publish time — and stored alongside the project version in the depot server as
|
|
48
|
+
a **file generation artifact**.
|
|
49
|
+
|
|
50
|
+
Legend Query then reads that artifact instead of recomputing it. That is
|
|
51
|
+
"data space analytics".
|
|
52
|
+
|
|
53
|
+
### 1.3 What analytics buys us
|
|
54
|
+
|
|
55
|
+
| Without analytics | With analytics |
|
|
56
|
+
| ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
|
|
57
|
+
| Fetch all project + dependency entities | Fetch one (small) set of artifact files, scoped to the data space |
|
|
58
|
+
| Build the full graph | Build a graph containing only the classes the mapping covers |
|
|
59
|
+
| Run mapping model coverage analysis against the engine (a network round trip per mapping) | Read the pre-computed coverage result out of the artifact |
|
|
60
|
+
| Compute element documentation, diagrams, executables client-side | Read them out of the artifact |
|
|
61
|
+
|
|
62
|
+
The artifacts are produced by the engine's artifact-generation extension keyed
|
|
63
|
+
`dataSpace-analytics`, and retrieved through
|
|
64
|
+
[`DataSpaceAnalysisHelper.ts`](../../legend-extension-dsl-data-space/src/graph-manager/action/analytics/DataSpaceAnalysisHelper.ts):
|
|
65
|
+
|
|
66
|
+
- `retrieveAnalyticsResultCache(...)` → the single legacy `AnalyticsResult.json` blob
|
|
67
|
+
- `retrieveDataspaceArtifactsCache(...)` → the **partitioned** artifact set (see below)
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 2. The minimal graph
|
|
72
|
+
|
|
73
|
+
### 2.1 Artifact layout
|
|
74
|
+
|
|
75
|
+
The engine emits the analytics for a data space as **several files**, not one.
|
|
76
|
+
This partitioning is what makes the minimal graph possible.
|
|
77
|
+
|
|
78
|
+
| Artifact | Type | Contents |
|
|
79
|
+
| ---------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
80
|
+
| `AnalyticsResult.json` | `V1_DataSpaceAnalysisResult` | Data space metadata: title, description, tagged values, stereotypes, support info, **execution contexts** (name → mapping, defaultRuntime, compatibleRuntimes, datasets, mappingProvider), element docs, diagrams, executables |
|
|
81
|
+
| `MappingAnalysisCoveragePartition` | one per mapping | `V1_MappingModelCoverageAnalysisResult` — the _coverage_ (which classes/properties the mapping maps, and how) |
|
|
82
|
+
| `MappingModelCoveragePartition` | one per mapping | `model`: a **`V1_PureModelContextData`** containing exactly the model elements the mapping covers |
|
|
83
|
+
|
|
84
|
+
Defined in
|
|
85
|
+
[`V1_DataSpaceArtifacts.ts`](../../legend-graph/src/graph-manager/protocol/pure/v1/engine/artifactGeneration/V1_DataSpaceArtifacts.ts).
|
|
86
|
+
|
|
87
|
+
The split matters for two reasons:
|
|
88
|
+
|
|
89
|
+
- **Size.** The data space entity itself is _excluded_ from `AnalyticsResult.json`
|
|
90
|
+
(Legend Query reconstructs a synthetic `V1_DataSpace` from the analysis result
|
|
91
|
+
instead — see `buildDataSpaceAnalytics`). Coverage models are the bulk of the
|
|
92
|
+
payload, and they are only fetched per-mapping.
|
|
93
|
+
- **Granularity.** The user picks one execution context at a time, which pins
|
|
94
|
+
one mapping. Only that mapping's `MappingModelCoveragePartition` is needed to
|
|
95
|
+
build a graph the query builder can work against.
|
|
96
|
+
|
|
97
|
+
> A developer-only diagnostic route,
|
|
98
|
+
> `/dev/dataspace-inspector` ([`DataSpaceArtifactInspector.tsx`](../src/components/DataSpaceArtifactInspector.tsx)),
|
|
99
|
+
> exists to inspect the sizes of these artifacts for a given GAV + data space.
|
|
100
|
+
|
|
101
|
+
### 2.2 "Cached minimal graph based on mapped classes"
|
|
102
|
+
|
|
103
|
+
The `MappingModelCoveragePartition.model` PMCD **is** the minimal graph seed.
|
|
104
|
+
It contains the model elements the mapping actually covers — the closure of
|
|
105
|
+
classes (and the enumerations, associations, and types they reach) reported by
|
|
106
|
+
mapping model coverage analysis, not the project's whole model.
|
|
107
|
+
|
|
108
|
+
Building the graph from it (in
|
|
109
|
+
[`V1_DSL_DataSpace_PureGraphManagerExtension.buildDataSpaceAnalytics`](../../legend-extension-dsl-data-space/src/graph-manager/protocol/pure/v1/V1_DSL_DataSpace_PureGraphManagerExtension.ts)):
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
graphEntities =
|
|
113
|
+
pmcd.elements // the mapped model closure
|
|
114
|
+
+ stub V1_Mapping per exec context // name/package only — no mapping body
|
|
115
|
+
+ stub V1_PackageableRuntime // name/package + empty V1_EngineRuntime
|
|
116
|
+
+ stub V1_DataProduct // for mappingProvider-backed contexts
|
|
117
|
+
+ synthetic V1_DataSpace // rebuilt from the analysis result
|
|
118
|
+
- anything already in the graph // i.e. system elements
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
then `graphManager.buildGraph(graph, graphEntities, …, { origin: LegendSDLC(gav) })`.
|
|
122
|
+
|
|
123
|
+
The mappings and runtimes are deliberately **stubs**: the query builder only
|
|
124
|
+
needs them as resolvable `PackageableElementReference` targets for the execution
|
|
125
|
+
context and for `RuntimePointer`. The real mapping body and connection details
|
|
126
|
+
are never needed client-side — execution is delegated to the engine, which
|
|
127
|
+
resolves them from the GAV origin stamped on the graph.
|
|
128
|
+
|
|
129
|
+
Two optional enrichments run afterwards, each independently failure-tolerant:
|
|
130
|
+
|
|
131
|
+
- `processFunctionForMinimalGraph(...)` — fetches only entities classified
|
|
132
|
+
`CORE_PURE_PATH.FUNCTION` for the project + dependencies, so the explorer can
|
|
133
|
+
offer usable functions. Populates `functionInfos` / dependency function infos.
|
|
134
|
+
- `processRuntimeInfo(...)` — fetches entities classified `CORE_PURE_PATH.RUNTIME`
|
|
135
|
+
to enrich the default runtime's info.
|
|
136
|
+
|
|
137
|
+
Both are wrapped in `try { … } catch { /* do nothing */ }`: losing function
|
|
138
|
+
suggestions is preferable to failing the editor load.
|
|
139
|
+
|
|
140
|
+
### 2.3 The decision flow
|
|
141
|
+
|
|
142
|
+
`QueryEditorStore.buildGraphAndDataspaceAnalyticsResult(...)`
|
|
143
|
+
([`QueryEditorStore.ts`](../src/stores/QueryEditorStore.ts)) is the single
|
|
144
|
+
entry point for every data-space-backed flow. It returns
|
|
145
|
+
`{ dataSpaceAnalysisResult, isLightGraphEnabled }`.
|
|
146
|
+
|
|
147
|
+
```mermaid
|
|
148
|
+
flowchart TD
|
|
149
|
+
A[buildGraphAndDataspaceAnalyticsResult] --> B{minimal graph enabled?}
|
|
150
|
+
B -- no --> F[buildFullGraph]
|
|
151
|
+
B -- yes --> C[analyzeDataSpaceCoverage]
|
|
152
|
+
C --> D{artifacts present AND<br/>every exec context's mapping<br/>has a MappingModelCoveragePartition?}
|
|
153
|
+
D -- no --> E[throw GraphBuilderError] --> F
|
|
154
|
+
D -- yes --> G[build minimal graph from PMCD]
|
|
155
|
+
G --> H{resolved mapping has<br/>coverage entities?}
|
|
156
|
+
H -- no --> F
|
|
157
|
+
H -- yes --> I[isLightGraphEnabled = true]
|
|
158
|
+
F --> J[retrieveDataSpaceAnalysisFromCache<br/>legacy AnalyticsResult.json]
|
|
159
|
+
J --> K[isLightGraphEnabled = false]
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Two gates control whether the minimal path is even attempted:
|
|
163
|
+
|
|
164
|
+
- `applicationStore.config.options.TEMPORARY__enableMinimalGraph` — deployment-level config flag.
|
|
165
|
+
- `QueryEditorStore.enableMinialGraphForDataSpaceLoadingPerformance` — an
|
|
166
|
+
observable, per-session toggle. The editor UI exposes it, so a user can force
|
|
167
|
+
a full graph build when the light graph is insufficient
|
|
168
|
+
(see [`QueryEditor.tsx`](../src/components/QueryEditor.tsx)).
|
|
169
|
+
|
|
170
|
+
**The all-or-nothing check.** In `analyzeDataSpaceCoverage`, the minimal path is
|
|
171
|
+
taken only if _every_ execution context in the analysis result has a
|
|
172
|
+
corresponding `MappingModelCoveragePartition`:
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
cachedAnalysisResult?.executionContexts.every(
|
|
176
|
+
(e) =>
|
|
177
|
+
mappingModelCoveragePartition.find((p) => p.mapping === e.mapping)
|
|
178
|
+
?.model !== undefined,
|
|
179
|
+
);
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
This is conservative on purpose: the user can switch execution contexts inside
|
|
183
|
+
the editor, and a partially-covered data space would strand them on a context
|
|
184
|
+
that cannot be built. If the check fails, a `GraphBuilderError` is thrown and
|
|
185
|
+
caught by the caller, which falls back to the full graph.
|
|
186
|
+
|
|
187
|
+
**Failure is always safe.** Every failure mode — missing artifacts, deserialization
|
|
188
|
+
error, incomplete coverage, missing PMCD for the resolved mapping — sets
|
|
189
|
+
`buildFullGraph = true`, discards the graph (`createNewGraph()`), and runs the
|
|
190
|
+
full build. The minimal graph is a pure optimization; correctness never depends
|
|
191
|
+
on it.
|
|
192
|
+
|
|
193
|
+
### 2.4 Switching execution context inside the editor
|
|
194
|
+
|
|
195
|
+
Once the editor is open on a light graph, the graph only contains the classes
|
|
196
|
+
of the _initially resolved_ mapping. Switching execution context therefore
|
|
197
|
+
requires rebuilding.
|
|
198
|
+
|
|
199
|
+
That rebuild lives in
|
|
200
|
+
[`Core_LegendQueryApplicationPlugin.tsx`](../src/components/Core_LegendQueryApplicationPlugin.tsx)
|
|
201
|
+
and mirrors the logic in `buildDataSpaceAnalytics`: it creates a fresh graph,
|
|
202
|
+
seeds it with `mappingModelCoverageAnalysisResult.entities` for the newly
|
|
203
|
+
selected mapping plus the same stub mappings/runtimes/data space entity, and
|
|
204
|
+
rebuilds with the SDLC origin. If anything throws, it falls back to
|
|
205
|
+
`editorStore.buildFullGraph()`.
|
|
206
|
+
|
|
207
|
+
This is why `isLightGraphEnabled` is threaded onto the query builder state
|
|
208
|
+
(`LegendQueryDataSpaceQueryBuilderState`): the state has to know whether a
|
|
209
|
+
context switch requires a graph rebuild or is already fully covered.
|
|
210
|
+
|
|
211
|
+
### 2.5 Minimal graphs for data products
|
|
212
|
+
|
|
213
|
+
Data products (`V1_DataProductArtifact`) follow the same principle with a
|
|
214
|
+
different artifact. `AbstractPureGraphManager.analyzeDataProductAndBuildMinimalGraph`
|
|
215
|
+
(implemented in
|
|
216
|
+
[`V1_PureGraphManager.ts`](../../legend-graph/src/graph-manager/protocol/pure/v1/V1_PureGraphManager.ts))
|
|
217
|
+
fetches the data product artifact from the depot and dispatches on access type:
|
|
218
|
+
|
|
219
|
+
- `MODEL` → `buildModelAccessDataProductAnalysis`
|
|
220
|
+
- `NATIVE` → `buildNativeAccessDataProductAnalysis`
|
|
221
|
+
- `LAKEHOUSE` → `buildLakehouseAccessDataProductAnalysis`
|
|
222
|
+
|
|
223
|
+
Each builds a graph containing only what that access path needs. When the
|
|
224
|
+
artifact has already been fetched (the common case — the store fetches it to
|
|
225
|
+
resolve the mapping path first), `buildDataProductAnalysis` is called directly
|
|
226
|
+
to avoid a second round trip.
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## 3. Entry points into Legend Query
|
|
231
|
+
|
|
232
|
+
An "entry point" is a route that constructs a concrete `QueryEditorStore`
|
|
233
|
+
subclass. Routes are declared in
|
|
234
|
+
[`LegendQueryNavigation.ts`](../src/__lib__/LegendQueryNavigation.ts) and
|
|
235
|
+
[`DSL_DataSpace_LegendQueryNavigation.ts`](../src/__lib__/DSL_DataSpace_LegendQueryNavigation.ts),
|
|
236
|
+
and wired in [`LegendQueryWebApplication.tsx`](../src/components/LegendQueryWebApplication.tsx).
|
|
237
|
+
|
|
238
|
+
Every store implements the same two hooks:
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
abstract initializeQueryBuilderState(stopWatch?): Promise<QueryBuilderState>;
|
|
242
|
+
abstract getPersistConfiguration(lambda, options?): QueryPersistConfiguration | undefined;
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
`initializeQueryBuilderState` decides _what kind of query builder_ the user
|
|
246
|
+
gets. `getPersistConfiguration` decides _how a saved query is stamped_.
|
|
247
|
+
|
|
248
|
+
Each creator store also tags its query builder `sourceInfo` with a
|
|
249
|
+
`sourceType` (`LegendQuerySourceType` in
|
|
250
|
+
[`LegendQuerySourceInfo.ts`](../src/__lib__/LegendQuerySourceInfo.ts)):
|
|
251
|
+
`mapping`, `service`, `data-space`, `data-space.template`, `data-product`,
|
|
252
|
+
`data-product.sample`, `ingest`, or `unselected` for the bare editor. These
|
|
253
|
+
values are reported on `query-editor.initialize-query-creator.success` /
|
|
254
|
+
`.failure`, along with whether the most recently visited data space or data
|
|
255
|
+
product was reopened — so the entry points below map one-to-one onto the
|
|
256
|
+
telemetry.
|
|
257
|
+
|
|
258
|
+
### 3.1 Mapping / Runtime (the "manual" flow)
|
|
259
|
+
|
|
260
|
+
| | |
|
|
261
|
+
| ------------- | --------------------------------------------------------------------------------------- |
|
|
262
|
+
| Route | `/create/manual/:gav/:mappingPath/:runtimePath` |
|
|
263
|
+
| Store | `MappingQueryCreatorStore` ([`QueryEditorStore.ts`](../src/stores/QueryEditorStore.ts)) |
|
|
264
|
+
| Builder state | `MappingQueryBuilderState` |
|
|
265
|
+
| Graph | **Full graph.** No analytics, no minimal graph. |
|
|
266
|
+
|
|
267
|
+
The rawest entry point: the user picks a mapping and a runtime directly. There
|
|
268
|
+
is no curated surface to derive a minimal model from, so the full project graph
|
|
269
|
+
is built. Changing mapping or runtime rewrites the URL (`updateCurrentLocation`)
|
|
270
|
+
so the flow stays deep-linkable.
|
|
271
|
+
|
|
272
|
+
Query search is scoped to the current project **and its dependencies** via
|
|
273
|
+
`decorateSearchSpecification`.
|
|
274
|
+
|
|
275
|
+
### 3.2 Service
|
|
276
|
+
|
|
277
|
+
| | |
|
|
278
|
+
| ------------- | ------------------------------------------------------------------- |
|
|
279
|
+
| Route | `/create-from-service/:gav/:servicePath` (+ optional execution key) |
|
|
280
|
+
| Store | `ServiceQueryCreatorStore` |
|
|
281
|
+
| Builder state | `ServiceQueryBuilderState` |
|
|
282
|
+
| Graph | **Full graph.** |
|
|
283
|
+
|
|
284
|
+
Opens the editor seeded with an existing service's execution lambda. The store
|
|
285
|
+
asserts the service execution is a `PureExecution`, then calls
|
|
286
|
+
`initializeWithQuery(service.execution.func)` — which routes unsupported query
|
|
287
|
+
shapes into the query builder's "unsupported" handling rather than crashing.
|
|
288
|
+
|
|
289
|
+
For multi-execution services, the execution key selects the execution context;
|
|
290
|
+
changing it rewrites the URL.
|
|
291
|
+
|
|
292
|
+
Related setup flows that funnel into this: `/setup/clone-service-query`,
|
|
293
|
+
`/setup/load-project-service-query`, `/setup/update-existing-service-query`,
|
|
294
|
+
`/setup/productionize-query`.
|
|
295
|
+
|
|
296
|
+
### 3.3 Data space
|
|
297
|
+
|
|
298
|
+
| | |
|
|
299
|
+
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
300
|
+
| Route | `/extensions/dataspace/:gav/:dataSpacePath/:executionContext?` (query params: `runtimePath`, `class`) |
|
|
301
|
+
| Store | `DataProductQueryCreatorStore` with a `QueryableLegacyDataProduct` ([`DataProductQueryCreatorStore.ts`](../src/stores/data-space/DataProductQueryCreatorStore.ts)) |
|
|
302
|
+
| Builder state | `LegendQueryDataSpaceQueryBuilderState` |
|
|
303
|
+
| Graph | **Minimal graph** via `buildGraphAndDataspaceAnalyticsResult` |
|
|
304
|
+
|
|
305
|
+
> **Naming caveat.** The store and queryable-element classes on this path are
|
|
306
|
+
> named `DataProductQueryCreatorStore` / `QueryableLegacyDataProduct`, dating
|
|
307
|
+
> from a period when data spaces were surfaced to users as "data products".
|
|
308
|
+
> That framing was reverted in
|
|
309
|
+
> [#5494](https://github.com/finos/legend-studio/pull/5494): the UI, command
|
|
310
|
+
> palette, and info panels for this path all say **Data Space** again, and
|
|
311
|
+
> "Data Product" now refers exclusively to the distinct element type in §3.4.
|
|
312
|
+
> The class names were left alone, so **read `DataProduct` in an identifier on
|
|
313
|
+
> this path as a historical artifact, not as a claim about which element type
|
|
314
|
+
> is being queried.** The discriminant that actually matters is the queryable
|
|
315
|
+
> element (`QueryableLegacyDataProduct` vs `QueryableDataProduct`) and the
|
|
316
|
+
> resulting builder state.
|
|
317
|
+
|
|
318
|
+
This is the flow section 2 describes. The store:
|
|
319
|
+
|
|
320
|
+
1. Calls `buildGraphAndDataspaceAnalyticsResult(gav, executionContext, dataSpacePath)`.
|
|
321
|
+
2. Resolves the data space out of the (minimal) graph via `getDataSpace(...)`.
|
|
322
|
+
3. Resolves the execution context via `resolveExecutionContext(...)` — by name if
|
|
323
|
+
given, otherwise the data space's default, otherwise the first.
|
|
324
|
+
4. Validates `mappingProvider`-backed contexts actually resolve to a mapping
|
|
325
|
+
(a context can source its mapping from a Data Product access point group —
|
|
326
|
+
a real cross-element reference, not a naming artifact; if that group is gone,
|
|
327
|
+
this is a hard error rather than a silent empty editor).
|
|
328
|
+
5. Attaches **fallback Lakehouse runtimes** (`attachDataSpaceFallbackRuntimes`)
|
|
329
|
+
— see below.
|
|
330
|
+
6. Constructs `LegendQueryDataSpaceQueryBuilderState`, hands it the
|
|
331
|
+
`mappingModelCoverageAnalysisResult` for the resolved mapping, and pins the
|
|
332
|
+
mapping plus — when the context has one — a `RuntimePointer` to its default
|
|
333
|
+
runtime.
|
|
334
|
+
|
|
335
|
+
**Execution contexts without a runtime.** `defaultRuntime` on a data space
|
|
336
|
+
execution context is optional. When a context sources its mapping from a Data
|
|
337
|
+
Product (`mappingProvider` is set) **and** declares no `defaultRuntime` **and**
|
|
338
|
+
the analytics report no compatible runtimes, `attachDataSpaceFallbackRuntimes`
|
|
339
|
+
fills the gap: it creates one shared `LakehouseRuntime` —
|
|
340
|
+
`_internal_::LakehouseRuntime`, via `createOrGetDataSpaceLakehouseFallbackRuntime`
|
|
341
|
+
— and assigns it as that context's `defaultRuntime`. Environment and warehouse
|
|
342
|
+
come from `resolveLakehouseEnvAndWarehouse`: the user's persisted Lakehouse
|
|
343
|
+
settings, else their entitlement environment from the contract server, with the
|
|
344
|
+
warehouse defaulting to `LAKEHOUSE_CONSUMER_DEFAULT_WH`. Snapshot versions are
|
|
345
|
+
resolved separately (`isSnapshot`).
|
|
346
|
+
|
|
347
|
+
The builder state exposes the result as `injectedLakehouseRuntime`. When set:
|
|
348
|
+
|
|
349
|
+
- the runtime selector is **locked** to that one runtime, labelled
|
|
350
|
+
`environment / warehouse`, and **Lakehouse Runtime Configuration** appears in
|
|
351
|
+
the setup panel's settings menu — the same modal data products use;
|
|
352
|
+
- `floatingExecutionElements` returns the runtime, so it rides along with the
|
|
353
|
+
SDLC pointer as a `V1_PureModelContextCombination` (the engine has never seen
|
|
354
|
+
an `_internal_` element);
|
|
355
|
+
- `buildExecutionContextExpression` emits `->with(dataProduct)->from(runtime)`
|
|
356
|
+
instead of `->from(mapping, runtime)`, because the mapping comes from the
|
|
357
|
+
Data Product, not from the project.
|
|
358
|
+
|
|
359
|
+
Contexts that are _not_ Data Product-backed and have no runtime simply get no
|
|
360
|
+
runtime pinned; nothing is injected.
|
|
361
|
+
|
|
362
|
+
The store also records visits in user data
|
|
363
|
+
(`LegendQueryUserDataHelper.getRecentlyVisitedDataSpaces`) so the setup screen
|
|
364
|
+
can offer recents, and so `onInitializeFailure` can evict stale entries.
|
|
365
|
+
|
|
366
|
+
`DataProductQueryCreatorStore` is shared with the data product flow (3.4) —
|
|
367
|
+
`LegendQueryableElement` is the abstraction over "the thing being queried":
|
|
368
|
+
|
|
369
|
+
```
|
|
370
|
+
LegendQueryableElement (gav + path + execContext)
|
|
371
|
+
├── QueryableLegacyDataProduct → dataSpacePath + executionContext (+ runtimePath, classPath)
|
|
372
|
+
└── QueryableDataProduct → dataProductPath + dataProductType + id
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
When the store is constructed with **no** queryable element, it builds a
|
|
376
|
+
`LegendQueryBareQueryBuilderState` — the empty-state editor with a
|
|
377
|
+
data space / data product selector.
|
|
378
|
+
|
|
379
|
+
**Template queries.** Route
|
|
380
|
+
`/extensions/dataspace/:gav/:dataSpacePath/template/:templateQueryId` →
|
|
381
|
+
`DataSpaceTemplateQueryCreatorStore` (extends `BaseTemplateQueryCreatorStore`).
|
|
382
|
+
It also uses `buildGraphAndDataspaceAnalyticsResult`, but overrides `buildGraph`
|
|
383
|
+
to a no-op — the graph is built inside `initializeQueryBuilderState`, since the
|
|
384
|
+
template id is needed to resolve which execution context (and therefore which
|
|
385
|
+
mapping) to cover. `analyzeDataSpaceCoverage` accepts `templateQueryId` for
|
|
386
|
+
exactly this: `retrieveExecutionContextFromTemplateQueryId(...)`.
|
|
387
|
+
|
|
388
|
+
### 3.4 Data products (native / model access / lakehouse)
|
|
389
|
+
|
|
390
|
+
| | |
|
|
391
|
+
| ------------- | --------------------------------------------------------------- |
|
|
392
|
+
| Route | `/data-product/:accessType/:gav/:dataProductPath/:accessId` |
|
|
393
|
+
| Store | `DataProductQueryCreatorStore` with a `QueryableDataProduct` |
|
|
394
|
+
| Builder state | `LegendQueryDataProductQueryBuilderState` |
|
|
395
|
+
| Graph | **Minimal graph** via `buildGraphAndDataproductAnalyticsResult` |
|
|
396
|
+
|
|
397
|
+
`accessType` is a `DataProductAccessType`:
|
|
398
|
+
|
|
399
|
+
| Access type | `accessId` means | Execution state |
|
|
400
|
+
| ----------- | ---------------------------- | ------------------------------------------- |
|
|
401
|
+
| `NATIVE` | native execution context key | `NativeModelDataProductExecutionState` |
|
|
402
|
+
| `MODEL` | model access point group id | `ModelAccessPointDataProductExecutionState` |
|
|
403
|
+
| `LAKEHOUSE` | lakehouse access point id | `LakehouseDataProductExecutionState` |
|
|
404
|
+
|
|
405
|
+
`QueryEditorStore.buildDataProductQueryBuilderState(...)` does the assembly:
|
|
406
|
+
|
|
407
|
+
1. Fetch the `V1_DataProductArtifact` (`fetchDataProductArtifact`).
|
|
408
|
+
2. Build the minimal graph + analysis (`buildGraphAndDataproductAnalyticsResult`).
|
|
409
|
+
3. Resolve the data product from the graph and the execution state from `accessId`.
|
|
410
|
+
4. For `MODEL` and `LAKEHOUSE`, synthesize an **adhoc Lakehouse runtime**
|
|
411
|
+
(`createLakehousePackageableRuntime`) from the user's lakehouse environment +
|
|
412
|
+
consumer warehouse, and register it on the graph under `INTERNAL_ELEMENT_PATH`
|
|
413
|
+
(`'_internal_'`).
|
|
414
|
+
These access paths have no modelled `PackageableRuntime` to point at.
|
|
415
|
+
5. Call `withAdhocRuntime()` on the execution state and select that runtime, so
|
|
416
|
+
the user can execute without picking one.
|
|
417
|
+
|
|
418
|
+
The data product dropdown (`DataProductSelectorState`) lists data products from
|
|
419
|
+
the Lakehouse contract server's lite API, restricted to the **production**
|
|
420
|
+
environment (`getAllLiteDataProducts(PRODUCTION)`), and keeps only those with an
|
|
421
|
+
SDLC deployment origin. It falls back to a depot classifier search only when no
|
|
422
|
+
contract server client is configured. Data spaces in the same dropdown still
|
|
423
|
+
come from depot.
|
|
424
|
+
|
|
425
|
+
**Sample queries.** Route
|
|
426
|
+
`/data-product/native/sample-query/:gav/:dataProductPath/:sampleQueryId` →
|
|
427
|
+
`DataProductSampleQueryCreatorStore` (also a `BaseTemplateQueryCreatorStore`).
|
|
428
|
+
|
|
429
|
+
**Which "About" panel you get.** Since
|
|
430
|
+
[#5494](https://github.com/finos/legend-studio/pull/5494), the editor exposes
|
|
431
|
+
two separate info actions in
|
|
432
|
+
[`Core_LegendQueryApplicationPlugin.tsx`](../src/components/Core_LegendQueryApplicationPlugin.tsx),
|
|
433
|
+
and each keys strictly off the **builder state type** — not the store type:
|
|
434
|
+
|
|
435
|
+
| Action key | Enabled when | Opens |
|
|
436
|
+
| ------------------- | ------------------------------------------------------------ | ------------------------------ |
|
|
437
|
+
| `about-dataspace` | `queryBuilderState instanceof DataSpaceQueryBuilderState` | `setShowDataspaceInfo(true)` |
|
|
438
|
+
| `about-dataproduct` | `queryBuilderState instanceof DataProductQueryBuilderState` | `setShowDataProductInfo(true)` |
|
|
439
|
+
| `about-ingest` | `queryBuilderState instanceof IngestLegendQueryBuilderState` | `setShowIngestInfo(true)` |
|
|
440
|
+
|
|
441
|
+
This replaced a single `About Data Product` action whose predicate also tested
|
|
442
|
+
the store type (`ExistingQueryEditorStore`, `DataSpaceTemplateQueryCreatorStore`,
|
|
443
|
+
`DataProductQueryCreatorStore`). Because `DataProductQueryCreatorStore` backs
|
|
444
|
+
both §3.3 and §3.4, that store-based test could not tell the two apart — which
|
|
445
|
+
is precisely why the predicate now looks only at the builder state.
|
|
446
|
+
|
|
447
|
+
**Export actions unavailable for data products and ingest.** The same builder
|
|
448
|
+
state test gates the export menu. For `DataProductQueryBuilderState` and
|
|
449
|
+
`IngestLegendQueryBuilderState`, four actions are disabled with the tooltip
|
|
450
|
+
_"Not supported for Data Product or Ingest queries"_:
|
|
451
|
+
|
|
452
|
+
| Menu label | Key | Contributed by |
|
|
453
|
+
| ---------------------- | -------------------------------- | ------------------------------------------ |
|
|
454
|
+
| Curated Template Query | `promote-as-template-query` | `Core_LegendQueryApplicationPlugin` |
|
|
455
|
+
| Legend DataCube | `legend-datacube-query` | `Core_LegendQueryApplicationPlugin` |
|
|
456
|
+
| Productionized Query | `export-as-productionized-query` | `DSL_Service_LegendQueryApplicationPlugin` |
|
|
457
|
+
| DEV Service | `export-as-dev-service` | `DSL_Service_LegendQueryApplicationPlugin` |
|
|
458
|
+
|
|
459
|
+
Menu items supply the message through `getDisableMessage(queryBuilderState)`
|
|
460
|
+
(added alongside the static `disableMessage`), so the same item can say
|
|
461
|
+
_"Requires saved query"_ in one context and _"Not supported…"_ in another.
|
|
462
|
+
File-format exports (CSV etc.) are unaffected.
|
|
463
|
+
|
|
464
|
+
### 3.5 Ingest definitions
|
|
465
|
+
|
|
466
|
+
| | |
|
|
467
|
+
| ------------- | ----------------------------------------------------------------------------------------------------------- |
|
|
468
|
+
| Route | `/ingest/:gav/:ingestDefinitionPath/:dataSet` |
|
|
469
|
+
| Store | `IngestQueryCreatorStore` ([`IngestQueryCreatorStore.ts`](../src/stores/ingest/IngestQueryCreatorStore.ts)) |
|
|
470
|
+
| Builder state | `IngestLegendQueryBuilderState` |
|
|
471
|
+
| Graph | **Targeted graph** — not analytics-driven |
|
|
472
|
+
|
|
473
|
+
Ingest takes a third approach. There is no analytics artifact; instead
|
|
474
|
+
`buildGraph` is overridden to:
|
|
475
|
+
|
|
476
|
+
1. Fetch **every** ingest definition entity in the project version, by
|
|
477
|
+
classifier (`fetchIngestEntitiesByClassifier`), and cache the payloads in
|
|
478
|
+
`_ingestEntitiesByPath`. This is cheap and lets the source dropdown list
|
|
479
|
+
every ingest.
|
|
480
|
+
2. Build **only the requested one** into the graph (`swapIngestInGraph`).
|
|
481
|
+
|
|
482
|
+
Swapping ingest definitions in the editor removes the current one from the graph
|
|
483
|
+
and builds the requested entity in its place, on demand — the other entities are
|
|
484
|
+
already in memory as protocol payloads.
|
|
485
|
+
|
|
486
|
+
Like model-access data products, ingest needs an adhoc Lakehouse runtime, added
|
|
487
|
+
as `_internal_` and auto-selected.
|
|
488
|
+
|
|
489
|
+
> `IngestDefinition` is currently self-contained as an entity. Once materialized
|
|
490
|
+
> views can reference other elements (mappings, classes, runtimes), this flow
|
|
491
|
+
> will need to fetch dependent entities or fall back to a full build. This is
|
|
492
|
+
> noted as a TODO on `IngestQueryCreatorStore.buildGraph`.
|
|
493
|
+
|
|
494
|
+
### 3.6 Existing query
|
|
495
|
+
|
|
496
|
+
| | |
|
|
497
|
+
| ------------- | -------------------------------------------------------------------- |
|
|
498
|
+
| Route | `/edit/:queryId` (and `/edit/:queryId/cube` for the DataCube viewer) |
|
|
499
|
+
| Store | `ExistingQueryEditorStore` |
|
|
500
|
+
| Builder state | Whichever the saved query's execution context implies |
|
|
501
|
+
| Graph | Depends on the saved query — see [§4](#4-saved-query-types) |
|
|
502
|
+
|
|
503
|
+
This is the reverse direction: given a persisted query, reconstruct the entry
|
|
504
|
+
point it was created from. Covered next.
|
|
505
|
+
|
|
506
|
+
---
|
|
507
|
+
|
|
508
|
+
## 4. Saved query types
|
|
509
|
+
|
|
510
|
+
### 4.1 The persisted shape
|
|
511
|
+
|
|
512
|
+
A saved query (`Query`, in
|
|
513
|
+
[`Query.ts`](../../legend-graph/src/graph-manager/action/query/Query.ts)) carries:
|
|
514
|
+
|
|
515
|
+
- **GAV** (`groupId`, `artifactId`, `versionId`, `originalVersionId`)
|
|
516
|
+
- **`content`** — the query lambda as PURE text (compact and stable across releases)
|
|
517
|
+
- **`executionContext: QueryExecutionContext`** — _what the query runs against_
|
|
518
|
+
- `taggedValues` / `stereotypes` — untyped metadata used for search and classification
|
|
519
|
+
- `defaultParameterValues`, `gridConfig`, ownership and timestamps
|
|
520
|
+
|
|
521
|
+
`mapping` and `runtime` are **deprecated** fields, superseded by
|
|
522
|
+
`QueryExecutionContext`. They are still read when reconstituting older queries.
|
|
523
|
+
|
|
524
|
+
### 4.2 The execution context hierarchy
|
|
525
|
+
|
|
526
|
+
```
|
|
527
|
+
QueryExecutionContext
|
|
528
|
+
├── QueryExplicitExecutionContext mapping, runtime
|
|
529
|
+
├── QueryDataSpaceExecutionContext dataSpacePath, executionKey
|
|
530
|
+
├── QueryDataProductExecutionContext (abstract) dataProductPath
|
|
531
|
+
│ ├── QueryDataProductNativeExecutionContext executionKey
|
|
532
|
+
│ ├── QueryDataProductModelAccessExecutionContext accessPointGroupId
|
|
533
|
+
│ └── QueryDataProductLakehouseExecutionContext accessPointId, accessGroupId
|
|
534
|
+
└── QueryIngestExecutionContext ingestDefinitionPath, dataSet
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
`QueryInfo` (the lightweight read model returned by `getQueryInfo`) mirrors this
|
|
538
|
+
with a parallel `QueryExecutionContextInfo` hierarchy — same discriminants,
|
|
539
|
+
paths as strings rather than references.
|
|
540
|
+
|
|
541
|
+
### 4.3 Where the execution context comes from
|
|
542
|
+
|
|
543
|
+
Each query builder state produces its own via `getQueryExecutionContext()`,
|
|
544
|
+
called from `QueryEditorStore.buildQueryForPersistence`:
|
|
545
|
+
|
|
546
|
+
| Builder state | Produces |
|
|
547
|
+
| ------------------------------- | ----------------------------------------------------------------------------- |
|
|
548
|
+
| `QueryBuilderState` (base) | `QueryExplicitExecutionContext` — mapping + `RuntimePointer` |
|
|
549
|
+
| `DataSpaceQueryBuilderState` | `QueryDataSpaceExecutionContext` — `dataSpace.path` + `executionContext.name` |
|
|
550
|
+
| `DataProductQueryBuilderState` | one of the three data product contexts, by `executionState` type |
|
|
551
|
+
| `IngestLegendQueryBuilderState` | `QueryIngestExecutionContext` — ingest path + current `dataSet` |
|
|
552
|
+
|
|
553
|
+
Note the level of indirection this creates. A data space query does **not**
|
|
554
|
+
persist a mapping and runtime; it persists _"this data space, this execution
|
|
555
|
+
context"_. Reopening it re-resolves the mapping and runtime from the data space
|
|
556
|
+
at the pinned version. If the data space owner repoints an execution context to
|
|
557
|
+
a different mapping in a later version, queries saved against it follow.
|
|
558
|
+
|
|
559
|
+
### 4.4 Tagged values
|
|
560
|
+
|
|
561
|
+
Distinct from the typed execution context, queries are also stamped with tagged
|
|
562
|
+
values on the `meta::pure::profiles::query` profile:
|
|
563
|
+
|
|
564
|
+
| Tag | Constant | Set by |
|
|
565
|
+
| ------------- | -------------------------------- | -------------------------------------- |
|
|
566
|
+
| `dataSpace` | `QUERY_PROFILE_TAG_DATA_SPACE` | legacy data space flow |
|
|
567
|
+
| `dataProduct` | `QUERY_PROFILE_TAG_DATA_PRODUCT` | data product flow |
|
|
568
|
+
| `class` | `QUERY_PROFILE_TAG_CLASS` | any flow with a resolved `sourceClass` |
|
|
569
|
+
|
|
570
|
+
These are **search and classification** metadata — they are what
|
|
571
|
+
`decorateSearchSpecification` filters on so a data space's query list shows only
|
|
572
|
+
its own queries. The `dataSpace` vs `dataProduct` split is load-bearing and
|
|
573
|
+
tracks the element type, not the historical naming: a query created against a
|
|
574
|
+
Data Product must carry `dataProduct`, or reopening it would mis-classify it as
|
|
575
|
+
a Data Space.
|
|
576
|
+
|
|
577
|
+
### 4.5 Reconstituting a saved query
|
|
578
|
+
|
|
579
|
+
`ExistingQueryEditorStore` does this in two phases.
|
|
580
|
+
|
|
581
|
+
**Phase 1 — `buildGraph()`** decides _how much graph to build_, from the
|
|
582
|
+
execution context type alone:
|
|
583
|
+
|
|
584
|
+
```ts
|
|
585
|
+
if (!(dataSpaceTaggedValue || exec is DataSpace | DataProductNative
|
|
586
|
+
| DataProductModelAccess | DataProductLakehouse | Ingest)) {
|
|
587
|
+
buildFullGraph(); // explicit mapping/runtime queries
|
|
588
|
+
} else if (exec is Ingest) {
|
|
589
|
+
buildIngestGraph(...); // fetch all ingests, build the one referenced
|
|
590
|
+
}
|
|
591
|
+
// otherwise: defer — the graph is built inside initQueryBuildStateFromQuery
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
Data space and data product queries build **nothing** here; their graph is built
|
|
595
|
+
lazily in phase 2, because the analytics call needs the execution key to know
|
|
596
|
+
which mapping to cover.
|
|
597
|
+
|
|
598
|
+
**Phase 2 — `initQueryBuildStateFromQuery(queryInfo)`** dispatches on the
|
|
599
|
+
execution context and rebuilds the matching entry point:
|
|
600
|
+
|
|
601
|
+
| Saved context | Reconstruction |
|
|
602
|
+
| --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
603
|
+
| `QueryDataSpaceExecutionContextInfo` | `buildGraphAndDataspaceAnalyticsResult(...)` with the saved `executionKey` → `attachDataSpaceFallbackRuntimes` (§3.3) → `resolveExecutionContext` → `LegendQueryDataSpaceQueryBuilderState`; mapping pinned from the resolved context, runtime pinned only if the context has one (possibly the injected Lakehouse fallback) |
|
|
604
|
+
| `QueryExplicitExecutionContextInfo` | `ClassQueryBuilderState` over the full graph; mapping and runtime resolved directly by path |
|
|
605
|
+
| `QueryDataProduct*ExecutionContextInfo` | `fetchDataProductArtifact(...)` → `buildDataProductQueryBuilderState(...)` with the access type and id derived from the context subtype |
|
|
606
|
+
| `QueryIngestExecutionContextInfo` | Resolve the ingest from the graph built in phase 1, create the adhoc lakehouse runtime, `changeAccessorOwner` + `changeAccessor({ tableName: dataSet })` |
|
|
607
|
+
| anything else | `UnsupportedOperationError` |
|
|
608
|
+
|
|
609
|
+
**Legacy resolution.** `resolveExecutionContext(dataSpace, executionKey, mapping, runtime)`
|
|
610
|
+
handles queries saved before execution keys were reliable. If no key is present
|
|
611
|
+
it falls back to the data space default; and if the query's deprecated
|
|
612
|
+
`mapping`/`runtime` disagree with the default context, it searches the execution
|
|
613
|
+
contexts for one whose mapping matches — disambiguating by runtime when several
|
|
614
|
+
match. This is why the deprecated fields are still read.
|
|
615
|
+
|
|
616
|
+
**Constrained editing.** Reopened queries deliberately disable data space and
|
|
617
|
+
data product switching (`'Switching data products is not supported from the
|
|
618
|
+
existing query editor. Please open a new query instead.'`). Switching would
|
|
619
|
+
invalidate the persisted execution context; the user is pushed toward a new
|
|
620
|
+
query instead. Switching _execution context within the same data space_ is
|
|
621
|
+
allowed, and — when the graph is light — triggers the rebuild described in §2.4,
|
|
622
|
+
gated behind a save prompt if the query has unsaved changes.
|
|
623
|
+
|
|
624
|
+
---
|
|
625
|
+
|
|
626
|
+
## 5. Summary
|
|
627
|
+
|
|
628
|
+
| Entry point | Store | Graph strategy | Persisted execution context |
|
|
629
|
+
| --------------------------- | ----------------------------------------------------------------- | ---------------------------------- | --------------------------------------------- |
|
|
630
|
+
| Mapping + runtime | `MappingQueryCreatorStore` | Full | `QueryExplicitExecutionContext` |
|
|
631
|
+
| Service | `ServiceQueryCreatorStore` | Full | `QueryExplicitExecutionContext` |
|
|
632
|
+
| Data space | `DataProductQueryCreatorStore` (via `QueryableLegacyDataProduct`) | Minimal (analytics artifacts) | `QueryDataSpaceExecutionContext` |
|
|
633
|
+
| Data space template | `DataSpaceTemplateQueryCreatorStore` | Minimal (resolved via template id) | `QueryDataSpaceExecutionContext` |
|
|
634
|
+
| Data product — native | `DataProductQueryCreatorStore` (via `QueryableDataProduct`) | Minimal (data product artifact) | `QueryDataProductNativeExecutionContext` |
|
|
635
|
+
| Data product — model access | `DataProductQueryCreatorStore` | Minimal + adhoc lakehouse runtime | `QueryDataProductModelAccessExecutionContext` |
|
|
636
|
+
| Data product — lakehouse | `DataProductQueryCreatorStore` | Minimal + adhoc lakehouse runtime | `QueryDataProductLakehouseExecutionContext` |
|
|
637
|
+
| Ingest definition | `IngestQueryCreatorStore` | Targeted (one ingest entity) | `QueryIngestExecutionContext` |
|
|
638
|
+
| Existing query | `ExistingQueryEditorStore` | Derived from the saved context | unchanged (round-trips) |
|
|
639
|
+
|
|
640
|
+
The through-line: **the more curated the entry point, the less graph Legend
|
|
641
|
+
Query has to build.** A raw mapping gives no signal, so everything is loaded. A
|
|
642
|
+
data space publishes exactly which mapping and which model elements matter, so
|
|
643
|
+
only those are loaded. Data products and ingest definitions narrow it further to
|
|
644
|
+
a single access path.
|