@finos/legend-application-data-cube 0.1.21 → 0.2.1
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__/LegendDataCubeNavigation.d.ts +1 -1
- package/lib/__lib__/LegendDataCubeNavigation.d.ts.map +1 -1
- package/lib/components/LegendDataCubeWebApplication.d.ts.map +1 -1
- package/lib/components/LegendDataCubeWebApplication.js +1 -14
- package/lib/components/LegendDataCubeWebApplication.js.map +1 -1
- package/lib/components/query-builder/LegendDataCubeQueryBuilder.d.ts.map +1 -1
- package/lib/components/query-builder/LegendDataCubeQueryBuilder.js +24 -23
- package/lib/components/query-builder/LegendDataCubeQueryBuilder.js.map +1 -1
- package/lib/components/query-builder/source-builder/LegendQueryDataCubeSourceBuilder.d.ts.map +1 -1
- package/lib/components/query-builder/source-builder/LegendQueryDataCubeSourceBuilder.js +8 -1
- package/lib/components/query-builder/source-builder/LegendQueryDataCubeSourceBuilder.js.map +1 -1
- package/lib/index.css +1 -1
- package/lib/package.json +3 -2
- package/lib/stores/LegendDataCubeCacheManager.d.ts +34 -0
- package/lib/stores/LegendDataCubeCacheManager.d.ts.map +1 -0
- package/lib/stores/LegendDataCubeCacheManager.js +134 -0
- package/lib/stores/LegendDataCubeCacheManager.js.map +1 -0
- package/lib/stores/LegendDataCubeDataCubeEngine.d.ts +11 -3
- package/lib/stores/LegendDataCubeDataCubeEngine.d.ts.map +1 -1
- package/lib/stores/LegendDataCubeDataCubeEngine.js +152 -19
- package/lib/stores/LegendDataCubeDataCubeEngine.js.map +1 -1
- package/lib/stores/query-builder/LegendDataCubeNewQueryState.d.ts.map +1 -1
- package/lib/stores/query-builder/LegendDataCubeNewQueryState.js +10 -10
- package/lib/stores/query-builder/LegendDataCubeNewQueryState.js.map +1 -1
- package/lib/stores/query-builder/LegendDataCubeQueryBuilderStore.d.ts +0 -1
- package/lib/stores/query-builder/LegendDataCubeQueryBuilderStore.d.ts.map +1 -1
- package/lib/stores/query-builder/LegendDataCubeQueryBuilderStore.js +18 -9
- package/lib/stores/query-builder/LegendDataCubeQueryBuilderStore.js.map +1 -1
- package/lib/stores/query-builder/source-builder/AdhocQueryDataCubeSourceBuilderState.d.ts +1 -1
- package/lib/stores/query-builder/source-builder/AdhocQueryDataCubeSourceBuilderState.d.ts.map +1 -1
- package/lib/stores/query-builder/source-builder/AdhocQueryDataCubeSourceBuilderState.js +1 -1
- package/lib/stores/query-builder/source-builder/AdhocQueryDataCubeSourceBuilderState.js.map +1 -1
- package/lib/stores/query-builder/source-builder/LegendDataCubeSourceBuilderState.d.ts +4 -3
- package/lib/stores/query-builder/source-builder/LegendDataCubeSourceBuilderState.d.ts.map +1 -1
- package/lib/stores/query-builder/source-builder/LegendDataCubeSourceBuilderState.js +5 -2
- package/lib/stores/query-builder/source-builder/LegendDataCubeSourceBuilderState.js.map +1 -1
- package/lib/stores/query-builder/source-builder/LegendQueryDataCubeSourceBuilderState.d.ts +3 -2
- package/lib/stores/query-builder/source-builder/LegendQueryDataCubeSourceBuilderState.d.ts.map +1 -1
- package/lib/stores/query-builder/source-builder/LegendQueryDataCubeSourceBuilderState.js +6 -1
- package/lib/stores/query-builder/source-builder/LegendQueryDataCubeSourceBuilderState.js.map +1 -1
- package/package.json +13 -12
- package/src/__lib__/LegendDataCubeNavigation.ts +1 -1
- package/src/components/LegendDataCubeWebApplication.tsx +1 -25
- package/src/components/query-builder/LegendDataCubeQueryBuilder.tsx +27 -27
- package/src/components/query-builder/source-builder/LegendQueryDataCubeSourceBuilder.tsx +17 -1
- package/src/stores/DuckDBWASM.d.ts +22 -0
- package/src/stores/LegendDataCubeCacheManager.ts +170 -0
- package/src/stores/LegendDataCubeDataCubeEngine.ts +247 -26
- package/src/stores/query-builder/LegendDataCubeNewQueryState.tsx +12 -18
- package/src/stores/query-builder/LegendDataCubeQueryBuilderStore.tsx +26 -10
- package/src/stores/query-builder/source-builder/AdhocQueryDataCubeSourceBuilderState.ts +1 -1
- package/src/stores/query-builder/source-builder/LegendDataCubeSourceBuilderState.ts +8 -4
- package/src/stores/query-builder/source-builder/LegendQueryDataCubeSourceBuilderState.ts +11 -2
- package/tsconfig.json +2 -0
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import {
|
|
18
|
-
|
|
18
|
+
V1_Lambda,
|
|
19
19
|
type V1_ValueSpecification,
|
|
20
20
|
type V1_EngineServerClient,
|
|
21
21
|
V1_PureGraphManager,
|
|
@@ -44,6 +44,34 @@ import {
|
|
|
44
44
|
V1_PackageableType,
|
|
45
45
|
V1_deserializeRawValueSpecificationType,
|
|
46
46
|
V1_Protocol,
|
|
47
|
+
type V1_ExecutionPlan,
|
|
48
|
+
V1_deserializeExecutionPlan,
|
|
49
|
+
V1_SQLExecutionNode,
|
|
50
|
+
V1_SimpleExecutionPlan,
|
|
51
|
+
V1_Binary,
|
|
52
|
+
V1_ClassInstance,
|
|
53
|
+
V1_ClassInstanceType,
|
|
54
|
+
V1_Column,
|
|
55
|
+
V1_Database,
|
|
56
|
+
V1_Date,
|
|
57
|
+
V1_Double,
|
|
58
|
+
V1_DuckDBDatasourceSpecification,
|
|
59
|
+
V1_EngineRuntime,
|
|
60
|
+
V1_IdentifiedConnection,
|
|
61
|
+
V1_Integer,
|
|
62
|
+
V1_PackageableElementPointer,
|
|
63
|
+
V1_PackageableRuntime,
|
|
64
|
+
V1_PureModelContextData,
|
|
65
|
+
V1_RelationStoreAccessor,
|
|
66
|
+
type V1_RelationalDataType,
|
|
67
|
+
V1_RelationalDatabaseConnection,
|
|
68
|
+
V1_Schema,
|
|
69
|
+
V1_StoreConnections,
|
|
70
|
+
V1_Table,
|
|
71
|
+
V1_TestAuthenticationStrategy,
|
|
72
|
+
V1_VarChar,
|
|
73
|
+
PackageableElementPointerType,
|
|
74
|
+
DatabaseType,
|
|
47
75
|
} from '@finos/legend-graph';
|
|
48
76
|
import {
|
|
49
77
|
_elementPtr,
|
|
@@ -52,15 +80,13 @@ import {
|
|
|
52
80
|
type CompletionItem,
|
|
53
81
|
_function,
|
|
54
82
|
DataCubeFunction,
|
|
55
|
-
_deserializeLambda,
|
|
56
83
|
AdhocQueryDataCubeSource,
|
|
57
84
|
ADHOC_QUERY_DATA_CUBE_SOURCE_TYPE,
|
|
58
85
|
RawAdhocQueryDataCubeSource,
|
|
59
86
|
_lambda,
|
|
60
|
-
_serializeValueSpecification,
|
|
61
|
-
_deserializeValueSpecification,
|
|
62
87
|
_defaultPrimitiveTypeValue,
|
|
63
88
|
type DataCubeExecutionOptions,
|
|
89
|
+
CachedDataCubeSource,
|
|
64
90
|
} from '@finos/legend-data-cube';
|
|
65
91
|
import {
|
|
66
92
|
isNonNullable,
|
|
@@ -72,8 +98,12 @@ import {
|
|
|
72
98
|
HttpStatus,
|
|
73
99
|
at,
|
|
74
100
|
assertType,
|
|
101
|
+
guaranteeType,
|
|
102
|
+
guaranteeNonNullable,
|
|
103
|
+
filterByType,
|
|
75
104
|
} from '@finos/legend-shared';
|
|
76
105
|
import type { LegendDataCubeApplicationStore } from './LegendDataCubeBaseStore.js';
|
|
106
|
+
import { LegendDataCubeDataCubeCacheManager } from './LegendDataCubeCacheManager.js';
|
|
77
107
|
import { APPLICATION_EVENT } from '@finos/legend-application';
|
|
78
108
|
import {
|
|
79
109
|
LEGEND_QUERY_DATA_CUBE_SOURCE_TYPE,
|
|
@@ -91,6 +121,7 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
|
|
|
91
121
|
private readonly _depotServerClient: DepotServerClient;
|
|
92
122
|
private readonly _engineServerClient: V1_EngineServerClient;
|
|
93
123
|
private readonly _graphManager: V1_PureGraphManager;
|
|
124
|
+
private readonly _cacheManager: LegendDataCubeDataCubeCacheManager;
|
|
94
125
|
|
|
95
126
|
constructor(
|
|
96
127
|
application: LegendDataCubeApplicationStore,
|
|
@@ -104,6 +135,15 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
|
|
|
104
135
|
this._depotServerClient = depotServerClient;
|
|
105
136
|
this._engineServerClient = engineServerClient;
|
|
106
137
|
this._graphManager = graphManager;
|
|
138
|
+
this._cacheManager = new LegendDataCubeDataCubeCacheManager();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async initializeCacheManager() {
|
|
142
|
+
await this._cacheManager.initialize();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async disposeCacheManager() {
|
|
146
|
+
await this._cacheManager.dispose();
|
|
107
147
|
}
|
|
108
148
|
|
|
109
149
|
// ---------------------------------- IMPLEMENTATION ----------------------------------
|
|
@@ -125,7 +165,7 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
|
|
|
125
165
|
try {
|
|
126
166
|
source.columns = (
|
|
127
167
|
await this._getLambdaRelationType(
|
|
128
|
-
|
|
168
|
+
this.serializeValueSpecification(_lambda([], [source.query])),
|
|
129
169
|
source.model,
|
|
130
170
|
)
|
|
131
171
|
).columns;
|
|
@@ -155,14 +195,18 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
|
|
|
155
195
|
);
|
|
156
196
|
const source = new LegendQueryDataCubeSource();
|
|
157
197
|
source.info = queryInfo;
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
198
|
+
|
|
199
|
+
source.lambda = guaranteeType(
|
|
200
|
+
this.deserializeValueSpecification(
|
|
201
|
+
await this._engineServerClient.grammarToJSON_lambda(
|
|
202
|
+
queryInfo.content,
|
|
203
|
+
'',
|
|
204
|
+
undefined,
|
|
205
|
+
undefined,
|
|
206
|
+
false,
|
|
207
|
+
),
|
|
165
208
|
),
|
|
209
|
+
V1_Lambda,
|
|
166
210
|
);
|
|
167
211
|
source.mapping = executionContext.mapping;
|
|
168
212
|
source.runtime = executionContext.runtime;
|
|
@@ -181,18 +225,22 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
|
|
|
181
225
|
),
|
|
182
226
|
);
|
|
183
227
|
source.query = at(source.lambda.body, 0);
|
|
228
|
+
// use the default parameter values from the query
|
|
229
|
+
//
|
|
230
|
+
// TODO?: we should probably allow configuring the parameters?
|
|
231
|
+
// this would mean we need to create first-class support for parameters in DataCube component
|
|
184
232
|
const parameterValues = await Promise.all(
|
|
185
233
|
source.lambda.parameters.map(async (parameter) => {
|
|
186
234
|
if (parameter.genericType?.rawType instanceof V1_PackageableType) {
|
|
187
235
|
const paramValue = new V1_ParameterValue();
|
|
188
236
|
paramValue.name = parameter.name;
|
|
189
237
|
const type = parameter.genericType.rawType.fullPath;
|
|
190
|
-
const
|
|
238
|
+
const defaultValue = queryInfo.defaultParameterValues?.find(
|
|
191
239
|
(val) => val.name === parameter.name,
|
|
192
240
|
)?.content;
|
|
193
241
|
paramValue.value =
|
|
194
|
-
|
|
195
|
-
? await this.parseValueSpecification(
|
|
242
|
+
defaultValue !== undefined
|
|
243
|
+
? await this.parseValueSpecification(defaultValue)
|
|
196
244
|
: {
|
|
197
245
|
_type: V1_deserializeRawValueSpecificationType(type),
|
|
198
246
|
value: _defaultPrimitiveTypeValue(type),
|
|
@@ -206,7 +254,7 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
|
|
|
206
254
|
try {
|
|
207
255
|
source.columns = (
|
|
208
256
|
await this._getLambdaRelationType(
|
|
209
|
-
|
|
257
|
+
this.serializeValueSpecification(source.lambda),
|
|
210
258
|
source.model,
|
|
211
259
|
)
|
|
212
260
|
).columns;
|
|
@@ -230,7 +278,7 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
|
|
|
230
278
|
returnSourceInformation?: boolean | undefined,
|
|
231
279
|
) {
|
|
232
280
|
try {
|
|
233
|
-
return
|
|
281
|
+
return this.deserializeValueSpecification(
|
|
234
282
|
await this._engineServerClient.grammarToJSON_valueSpecification(
|
|
235
283
|
code,
|
|
236
284
|
'',
|
|
@@ -260,7 +308,7 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
|
|
|
260
308
|
pretty?: boolean | undefined,
|
|
261
309
|
) {
|
|
262
310
|
return this._graphManager.valueSpecificationToPureCode(
|
|
263
|
-
|
|
311
|
+
this.serializeValueSpecification(value),
|
|
264
312
|
pretty,
|
|
265
313
|
);
|
|
266
314
|
}
|
|
@@ -303,7 +351,7 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
|
|
|
303
351
|
) {
|
|
304
352
|
try {
|
|
305
353
|
return await this._getQueryRelationType(
|
|
306
|
-
|
|
354
|
+
this.serializeValueSpecification(query),
|
|
307
355
|
source,
|
|
308
356
|
);
|
|
309
357
|
} catch (error) {
|
|
@@ -369,6 +417,7 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
|
|
|
369
417
|
) {
|
|
370
418
|
const queryCodePromise = this.getValueSpecificationCode(query);
|
|
371
419
|
let result: ExecutionResult;
|
|
420
|
+
const startTime = performance.now();
|
|
372
421
|
if (source instanceof AdhocQueryDataCubeSource) {
|
|
373
422
|
result = await this._runQuery(query, source.model, undefined, options);
|
|
374
423
|
} else if (source instanceof LegendQueryDataCubeSource) {
|
|
@@ -379,6 +428,29 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
|
|
|
379
428
|
source.parameterValues,
|
|
380
429
|
options,
|
|
381
430
|
);
|
|
431
|
+
} else if (source instanceof CachedDataCubeSource) {
|
|
432
|
+
// get the execute plan to extract the generated SQL to run against cached DB
|
|
433
|
+
const executionPlan = await this.generateExecutionPlan(
|
|
434
|
+
query,
|
|
435
|
+
source.model,
|
|
436
|
+
[],
|
|
437
|
+
options,
|
|
438
|
+
);
|
|
439
|
+
const sql = guaranteeNonNullable(
|
|
440
|
+
executionPlan instanceof V1_SimpleExecutionPlan
|
|
441
|
+
? executionPlan.rootExecutionNode.executionNodes
|
|
442
|
+
.filter(filterByType(V1_SQLExecutionNode))
|
|
443
|
+
.at(-1)?.sqlQuery
|
|
444
|
+
: undefined,
|
|
445
|
+
`Can't process execution plan: failed to extract generated SQL`,
|
|
446
|
+
);
|
|
447
|
+
const endTime = performance.now();
|
|
448
|
+
return {
|
|
449
|
+
executedQuery: await queryCodePromise,
|
|
450
|
+
executedSQL: sql,
|
|
451
|
+
result: await this._cacheManager.runSQLQuery(sql),
|
|
452
|
+
executionTime: endTime - startTime,
|
|
453
|
+
};
|
|
382
454
|
} else {
|
|
383
455
|
throw new UnsupportedOperationError(
|
|
384
456
|
`Can't execute query with unsupported source`,
|
|
@@ -387,20 +459,21 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
|
|
|
387
459
|
assertType(
|
|
388
460
|
result,
|
|
389
461
|
TDSExecutionResult,
|
|
390
|
-
`Can't
|
|
462
|
+
`Can't process execution result: expected tabular data set format`,
|
|
391
463
|
);
|
|
464
|
+
const endTime = performance.now();
|
|
392
465
|
const queryCode = await queryCodePromise;
|
|
393
|
-
const sql =
|
|
466
|
+
const sql = guaranteeNonNullable(
|
|
394
467
|
result.activities?.[0] instanceof RelationalExecutionActivities
|
|
395
468
|
? result.activities[0].sql
|
|
396
|
-
: undefined
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
}
|
|
469
|
+
: undefined,
|
|
470
|
+
`Can't process execution result: failed to extract generated SQL`,
|
|
471
|
+
);
|
|
400
472
|
return {
|
|
401
473
|
result: result,
|
|
402
474
|
executedQuery: queryCode,
|
|
403
475
|
executedSQL: sql,
|
|
476
|
+
executionTime: endTime - startTime,
|
|
404
477
|
};
|
|
405
478
|
}
|
|
406
479
|
|
|
@@ -418,6 +491,11 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
|
|
|
418
491
|
_elementPtr(source.runtime),
|
|
419
492
|
].filter(isNonNullable),
|
|
420
493
|
);
|
|
494
|
+
} else if (source instanceof CachedDataCubeSource) {
|
|
495
|
+
return _function(
|
|
496
|
+
DataCubeFunction.FROM,
|
|
497
|
+
[_elementPtr(source.runtime)].filter(isNonNullable),
|
|
498
|
+
);
|
|
421
499
|
}
|
|
422
500
|
return undefined;
|
|
423
501
|
}
|
|
@@ -432,6 +510,8 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
|
|
|
432
510
|
return this._getLambdaRelationType(query, source.model);
|
|
433
511
|
} else if (source instanceof LegendQueryDataCubeSource) {
|
|
434
512
|
return this._getLambdaRelationType(query, source.model);
|
|
513
|
+
} else if (source instanceof CachedDataCubeSource) {
|
|
514
|
+
return this._getLambdaRelationType(query, serialize(source.model));
|
|
435
515
|
}
|
|
436
516
|
throw new UnsupportedOperationError(
|
|
437
517
|
`Can't get relation type for lambda with unsupported source`,
|
|
@@ -472,7 +552,7 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
|
|
|
472
552
|
(process.env.NODE_ENV === 'development'
|
|
473
553
|
? PureClientVersion.VX_X_X
|
|
474
554
|
: undefined),
|
|
475
|
-
function:
|
|
555
|
+
function: this.serializeValueSpecification(query),
|
|
476
556
|
model,
|
|
477
557
|
context: serialize(
|
|
478
558
|
V1_rawBaseExecutionContextModelSchema,
|
|
@@ -486,6 +566,147 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
|
|
|
486
566
|
);
|
|
487
567
|
}
|
|
488
568
|
|
|
569
|
+
private async generateExecutionPlan(
|
|
570
|
+
query: V1_Lambda,
|
|
571
|
+
model: V1_PureModelContext,
|
|
572
|
+
parameterValues?: V1_ParameterValue[] | undefined,
|
|
573
|
+
options?: DataCubeExecutionOptions | undefined,
|
|
574
|
+
): Promise<V1_ExecutionPlan> {
|
|
575
|
+
return V1_deserializeExecutionPlan(
|
|
576
|
+
await this._engineServerClient.generatePlan({
|
|
577
|
+
clientVersion:
|
|
578
|
+
options?.clientVersion ??
|
|
579
|
+
// eslint-disable-next-line no-process-env
|
|
580
|
+
(process.env.NODE_ENV === 'development'
|
|
581
|
+
? PureClientVersion.VX_X_X
|
|
582
|
+
: undefined),
|
|
583
|
+
function: this.serializeValueSpecification(query),
|
|
584
|
+
model: serialize(model),
|
|
585
|
+
context: serialize(
|
|
586
|
+
V1_rawBaseExecutionContextModelSchema,
|
|
587
|
+
new V1_RawBaseExecutionContext(),
|
|
588
|
+
),
|
|
589
|
+
parameterValues: (parameterValues ?? []).map((parameterValue) =>
|
|
590
|
+
serialize(V1_parameterValueModelSchema, parameterValue),
|
|
591
|
+
),
|
|
592
|
+
}),
|
|
593
|
+
);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// ---------------------------------- CACHING --------------------------------------
|
|
597
|
+
|
|
598
|
+
override async initializeCache(
|
|
599
|
+
source: DataCubeSource,
|
|
600
|
+
): Promise<CachedDataCubeSource | undefined> {
|
|
601
|
+
const cacheQuery = guaranteeNonNullable(
|
|
602
|
+
this.buildExecutionContext(source),
|
|
603
|
+
`Can't initialize cache: failed to build cache query`,
|
|
604
|
+
);
|
|
605
|
+
cacheQuery.parameters.unshift(source.query);
|
|
606
|
+
const result = await this.executeQuery(
|
|
607
|
+
_lambda([], [cacheQuery]),
|
|
608
|
+
source,
|
|
609
|
+
undefined,
|
|
610
|
+
);
|
|
611
|
+
const {
|
|
612
|
+
schema: schemaName,
|
|
613
|
+
table: tableName,
|
|
614
|
+
rowCount,
|
|
615
|
+
} = await this._cacheManager.cache(result.result);
|
|
616
|
+
|
|
617
|
+
// model
|
|
618
|
+
const pacakgePath = 'local';
|
|
619
|
+
|
|
620
|
+
const table = new V1_Table();
|
|
621
|
+
table.name = tableName;
|
|
622
|
+
table.columns = result.result.builder.columns.map((col) => {
|
|
623
|
+
const column = new V1_Column();
|
|
624
|
+
column.name = col.name;
|
|
625
|
+
column.type = this._getColumnType(col.type);
|
|
626
|
+
return column;
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
const schema = new V1_Schema();
|
|
630
|
+
schema.name = schemaName;
|
|
631
|
+
schema.tables = [table];
|
|
632
|
+
const database = new V1_Database();
|
|
633
|
+
database.name = 'db';
|
|
634
|
+
database.package = pacakgePath;
|
|
635
|
+
database.schemas = [schema];
|
|
636
|
+
|
|
637
|
+
const connection = new V1_RelationalDatabaseConnection();
|
|
638
|
+
connection.databaseType = DatabaseType.DuckDB;
|
|
639
|
+
connection.type = DatabaseType.DuckDB;
|
|
640
|
+
const dataSourceSpec = new V1_DuckDBDatasourceSpecification();
|
|
641
|
+
dataSourceSpec.path = '/tmpFile';
|
|
642
|
+
connection.store = database.path;
|
|
643
|
+
connection.datasourceSpecification = dataSourceSpec;
|
|
644
|
+
connection.authenticationStrategy = new V1_TestAuthenticationStrategy();
|
|
645
|
+
|
|
646
|
+
const runtime = new V1_EngineRuntime();
|
|
647
|
+
const storeConnections = new V1_StoreConnections();
|
|
648
|
+
storeConnections.store = new V1_PackageableElementPointer(
|
|
649
|
+
PackageableElementPointerType.STORE,
|
|
650
|
+
database.path,
|
|
651
|
+
);
|
|
652
|
+
const identifiedConnection = new V1_IdentifiedConnection();
|
|
653
|
+
identifiedConnection.connection = connection;
|
|
654
|
+
identifiedConnection.id = 'c0';
|
|
655
|
+
storeConnections.storeConnections = [identifiedConnection];
|
|
656
|
+
runtime.connections = [storeConnections];
|
|
657
|
+
|
|
658
|
+
const packageableRuntime = new V1_PackageableRuntime();
|
|
659
|
+
packageableRuntime.runtimeValue = runtime;
|
|
660
|
+
packageableRuntime.package = pacakgePath;
|
|
661
|
+
packageableRuntime.name = 'rt';
|
|
662
|
+
|
|
663
|
+
const model = new V1_PureModelContextData();
|
|
664
|
+
model.elements = [database, packageableRuntime];
|
|
665
|
+
|
|
666
|
+
// query
|
|
667
|
+
const query = new V1_ClassInstance();
|
|
668
|
+
query.type = V1_ClassInstanceType.RELATION_STORE_ACCESSOR;
|
|
669
|
+
const storeAccessor = new V1_RelationStoreAccessor();
|
|
670
|
+
storeAccessor.path = [database.path, schema.name, table.name];
|
|
671
|
+
query.value = storeAccessor;
|
|
672
|
+
|
|
673
|
+
const cachedSource = new CachedDataCubeSource();
|
|
674
|
+
cachedSource.columns = source.columns;
|
|
675
|
+
cachedSource.query = query;
|
|
676
|
+
cachedSource.model = model;
|
|
677
|
+
cachedSource.runtime = packageableRuntime.path;
|
|
678
|
+
cachedSource.db = database.path;
|
|
679
|
+
cachedSource.schema = schema.name;
|
|
680
|
+
cachedSource.table = table.name;
|
|
681
|
+
cachedSource.count = rowCount;
|
|
682
|
+
return cachedSource;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
override async disposeCache(source: CachedDataCubeSource) {
|
|
686
|
+
await this._cacheManager.disposeCache(source);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// TODO: need a better way to infer datatype from tds builder
|
|
690
|
+
private _getColumnType(type: string | undefined): V1_RelationalDataType {
|
|
691
|
+
if (type === undefined) {
|
|
692
|
+
throw Error('Unsupported data type');
|
|
693
|
+
}
|
|
694
|
+
switch (type) {
|
|
695
|
+
case 'string':
|
|
696
|
+
return new V1_VarChar();
|
|
697
|
+
case 'integer':
|
|
698
|
+
return new V1_Integer();
|
|
699
|
+
case 'date':
|
|
700
|
+
return new V1_Date();
|
|
701
|
+
case 'boolean':
|
|
702
|
+
return new V1_Binary();
|
|
703
|
+
case 'number':
|
|
704
|
+
return new V1_Double();
|
|
705
|
+
default:
|
|
706
|
+
return new V1_VarChar();
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
489
710
|
// ---------------------------------- APPLICATION ----------------------------------
|
|
490
711
|
|
|
491
712
|
override logDebug(message: string, ...data: unknown[]) {
|
|
@@ -29,9 +29,7 @@ import {
|
|
|
29
29
|
type LegendDataCubeSourceBuilderState,
|
|
30
30
|
} from './source-builder/LegendDataCubeSourceBuilderState.js';
|
|
31
31
|
import {
|
|
32
|
-
_selectFunction,
|
|
33
32
|
type DataCubeAlertService,
|
|
34
|
-
DataCubeQuery,
|
|
35
33
|
DEFAULT_TOOL_PANEL_WINDOW_CONFIG,
|
|
36
34
|
type DisplayState,
|
|
37
35
|
} from '@finos/legend-data-cube';
|
|
@@ -44,6 +42,8 @@ import {
|
|
|
44
42
|
} from './LegendDataCubeQueryBuilderStore.js';
|
|
45
43
|
import { generateQueryBuilderRoute } from '../../__lib__/LegendDataCubeNavigation.js';
|
|
46
44
|
|
|
45
|
+
const DEFAULT_SOURCE_TYPE = LegendDataCubeSourceBuilderType.LEGEND_QUERY;
|
|
46
|
+
|
|
47
47
|
export class LegendDataCubeNewQueryState {
|
|
48
48
|
private readonly _application: LegendDataCubeApplicationStore;
|
|
49
49
|
private readonly _store: LegendDataCubeQueryBuilderStore;
|
|
@@ -76,9 +76,7 @@ export class LegendDataCubeNewQueryState {
|
|
|
76
76
|
},
|
|
77
77
|
);
|
|
78
78
|
|
|
79
|
-
this.sourceBuilder = this.createSourceBuilder(
|
|
80
|
-
LegendDataCubeSourceBuilderType.LEGEND_QUERY,
|
|
81
|
-
);
|
|
79
|
+
this.sourceBuilder = this.createSourceBuilder(DEFAULT_SOURCE_TYPE);
|
|
82
80
|
}
|
|
83
81
|
|
|
84
82
|
changeSourceBuilder(
|
|
@@ -115,31 +113,27 @@ export class LegendDataCubeNewQueryState {
|
|
|
115
113
|
}
|
|
116
114
|
|
|
117
115
|
async finalize(sourceData?: PlainObject) {
|
|
118
|
-
if (!this.sourceBuilder.isValid
|
|
116
|
+
if (!sourceData && !this.sourceBuilder.isValid) {
|
|
119
117
|
throw new IllegalStateError(`Can't generate query: source is not valid`);
|
|
120
118
|
}
|
|
121
119
|
|
|
122
120
|
this.finalizeState.inProgress();
|
|
123
121
|
try {
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
const processedSource = await this._engine.processQuerySource(source);
|
|
127
|
-
query.source = source;
|
|
128
|
-
query.query = await this._engine.getValueSpecificationCode(
|
|
129
|
-
_selectFunction(processedSource.columns),
|
|
122
|
+
const query = await this._engine.generateBaseQuery(
|
|
123
|
+
sourceData ?? (await this.sourceBuilder.generateSourceData()),
|
|
130
124
|
);
|
|
125
|
+
if (query.configuration) {
|
|
126
|
+
this.sourceBuilder.finalizeConfiguration(query.configuration);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// reset
|
|
131
130
|
this._store.setBuilder(new LegendDataCubeQueryBuilderState(query));
|
|
132
131
|
// only update the route instead of reloading in case we are creating
|
|
133
132
|
// a new query when we are editing another query
|
|
134
133
|
this._application.navigationService.navigator.updateCurrentLocation(
|
|
135
134
|
generateQueryBuilderRoute(null),
|
|
136
135
|
);
|
|
137
|
-
|
|
138
|
-
// reset
|
|
139
|
-
this.changeSourceBuilder(
|
|
140
|
-
LegendDataCubeSourceBuilderType.LEGEND_QUERY,
|
|
141
|
-
true,
|
|
142
|
-
);
|
|
136
|
+
this.changeSourceBuilder(DEFAULT_SOURCE_TYPE, true);
|
|
143
137
|
this.display.close();
|
|
144
138
|
this.finalizeState.pass();
|
|
145
139
|
} catch (error) {
|
|
@@ -43,7 +43,10 @@ import {
|
|
|
43
43
|
} from '@finos/legend-shared';
|
|
44
44
|
import type { LegendDataCubeDataCubeEngine } from '../LegendDataCubeDataCubeEngine.js';
|
|
45
45
|
import { LegendDataCubeQuerySaver } from '../../components/query-builder/LegendDataCubeQuerySaver.js';
|
|
46
|
-
import {
|
|
46
|
+
import {
|
|
47
|
+
generateQueryBuilderRoute,
|
|
48
|
+
LEGEND_DATA_CUBE_ROUTE_PATTERN_TOKEN,
|
|
49
|
+
} from '../../__lib__/LegendDataCubeNavigation.js';
|
|
47
50
|
import { LegendDataCubeQueryLoaderState } from './LegendDataCubeQueryLoaderState.js';
|
|
48
51
|
import {
|
|
49
52
|
LegendDataCubeUserDataKey,
|
|
@@ -68,7 +71,6 @@ export class LegendDataCubeQueryBuilderState {
|
|
|
68
71
|
|
|
69
72
|
query: observable,
|
|
70
73
|
persistentQuery: observable,
|
|
71
|
-
setPersistentQuery: action,
|
|
72
74
|
});
|
|
73
75
|
|
|
74
76
|
this.query = query;
|
|
@@ -78,12 +80,6 @@ export class LegendDataCubeQueryBuilderState {
|
|
|
78
80
|
setDataCube(val: DataCubeAPI | undefined) {
|
|
79
81
|
this.dataCube = val;
|
|
80
82
|
}
|
|
81
|
-
|
|
82
|
-
setPersistentQuery(val: PersistentDataCubeQuery) {
|
|
83
|
-
this.persistentQuery = val;
|
|
84
|
-
this.query = DataCubeQuery.serialization.fromJson(val.content);
|
|
85
|
-
this.startTime = Date.now();
|
|
86
|
-
}
|
|
87
83
|
}
|
|
88
84
|
|
|
89
85
|
export class LegendDataCubeQueryBuilderStore {
|
|
@@ -154,9 +150,31 @@ export class LegendDataCubeQueryBuilderStore {
|
|
|
154
150
|
}
|
|
155
151
|
|
|
156
152
|
async loadQuery(queryId: string | undefined) {
|
|
153
|
+
// internalize the parameters and clean them from the URL
|
|
154
|
+
const sourceData =
|
|
155
|
+
this.application.navigationService.navigator.getCurrentLocationParameterValue(
|
|
156
|
+
LEGEND_DATA_CUBE_ROUTE_PATTERN_TOKEN.SOURCE_DATA,
|
|
157
|
+
);
|
|
158
|
+
if (sourceData && !queryId) {
|
|
159
|
+
this.application.navigationService.navigator.updateCurrentLocation(
|
|
160
|
+
generateQueryBuilderRoute(null),
|
|
161
|
+
);
|
|
162
|
+
// populate the new query state if source data is specified
|
|
163
|
+
try {
|
|
164
|
+
await this.newQueryState.finalize(JSON.parse(atob(sourceData)));
|
|
165
|
+
} catch (error) {
|
|
166
|
+
assertErrorThrown(error);
|
|
167
|
+
this.alertService.alertError(error, {
|
|
168
|
+
message: `Query Creation Failure: Can't materialize query source from source data. Error: ${error.message}`,
|
|
169
|
+
});
|
|
170
|
+
this.setBuilder(undefined);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
157
174
|
if (queryId !== this.builder?.persistentQuery?.id) {
|
|
158
175
|
if (!queryId) {
|
|
159
176
|
this.setBuilder(undefined);
|
|
177
|
+
this.loader.display.open();
|
|
160
178
|
return;
|
|
161
179
|
}
|
|
162
180
|
|
|
@@ -244,7 +262,6 @@ export class LegendDataCubeQueryBuilderStore {
|
|
|
244
262
|
this.application.navigationService.navigator.updateCurrentLocation(
|
|
245
263
|
generateQueryBuilderRoute(newQuery.id),
|
|
246
264
|
);
|
|
247
|
-
this.builder.setPersistentQuery(persistentQuery);
|
|
248
265
|
this.updateWindowTitle(persistentQuery);
|
|
249
266
|
|
|
250
267
|
this.saverDisplay.close();
|
|
@@ -291,7 +308,6 @@ export class LegendDataCubeQueryBuilderStore {
|
|
|
291
308
|
} else {
|
|
292
309
|
await this.baseStore.graphManager.updateDataCubeQuery(persistentQuery);
|
|
293
310
|
}
|
|
294
|
-
this.builder.setPersistentQuery(persistentQuery);
|
|
295
311
|
this.updateWindowTitle(persistentQuery);
|
|
296
312
|
|
|
297
313
|
this.saverDisplay.close();
|
|
@@ -29,7 +29,7 @@ export class AdhocQueryDataCubeSourceBuilderState extends LegendDataCubeSourceBu
|
|
|
29
29
|
return false;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
override
|
|
32
|
+
override generateSourceData(): Promise<PlainObject> {
|
|
33
33
|
throw new Error('Method not implemented.');
|
|
34
34
|
}
|
|
35
35
|
}
|
|
@@ -14,9 +14,10 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import {
|
|
17
|
+
import { type PlainObject } from '@finos/legend-shared';
|
|
18
18
|
import type { LegendDataCubeApplicationStore } from '../../LegendDataCubeBaseStore.js';
|
|
19
19
|
import type { LegendDataCubeDataCubeEngine } from '../../LegendDataCubeDataCubeEngine.js';
|
|
20
|
+
import type { DataCubeConfiguration } from '@finos/legend-data-cube';
|
|
20
21
|
|
|
21
22
|
export enum LegendDataCubeSourceBuilderType {
|
|
22
23
|
LEGEND_QUERY = 'Legend Query',
|
|
@@ -27,8 +28,6 @@ export abstract class LegendDataCubeSourceBuilderState {
|
|
|
27
28
|
protected readonly _application: LegendDataCubeApplicationStore;
|
|
28
29
|
protected readonly _engine: LegendDataCubeDataCubeEngine;
|
|
29
30
|
|
|
30
|
-
readonly buildState = ActionState.create();
|
|
31
|
-
|
|
32
31
|
constructor(
|
|
33
32
|
application: LegendDataCubeApplicationStore,
|
|
34
33
|
engine: LegendDataCubeDataCubeEngine,
|
|
@@ -39,5 +38,10 @@ export abstract class LegendDataCubeSourceBuilderState {
|
|
|
39
38
|
|
|
40
39
|
abstract get label(): LegendDataCubeSourceBuilderType;
|
|
41
40
|
abstract get isValid(): boolean;
|
|
42
|
-
abstract
|
|
41
|
+
abstract generateSourceData(): Promise<PlainObject>;
|
|
42
|
+
|
|
43
|
+
/* Modifies the configuration of the finalized DataCube query based on the source builder */
|
|
44
|
+
finalizeConfiguration(configuration: DataCubeConfiguration) {
|
|
45
|
+
// do nothing
|
|
46
|
+
}
|
|
43
47
|
}
|
|
@@ -39,7 +39,10 @@ import { RawLegendQueryDataCubeSource } from '../../model/LegendQueryDataCubeSou
|
|
|
39
39
|
import { APPLICATION_EVENT } from '@finos/legend-application';
|
|
40
40
|
import type { LegendDataCubeDataCubeEngine } from '../../LegendDataCubeDataCubeEngine.js';
|
|
41
41
|
import type { LegendDataCubeApplicationStore } from '../../LegendDataCubeBaseStore.js';
|
|
42
|
-
import type {
|
|
42
|
+
import type {
|
|
43
|
+
DataCubeAlertService,
|
|
44
|
+
DataCubeConfiguration,
|
|
45
|
+
} from '@finos/legend-data-cube';
|
|
43
46
|
|
|
44
47
|
export class LegendQueryDataCubeSourceBuilderState extends LegendDataCubeSourceBuilderState {
|
|
45
48
|
private readonly _engineServerClient: V1_EngineServerClient;
|
|
@@ -132,7 +135,7 @@ export class LegendQueryDataCubeSourceBuilderState extends LegendDataCubeSourceB
|
|
|
132
135
|
return Boolean(this.query);
|
|
133
136
|
}
|
|
134
137
|
|
|
135
|
-
override async
|
|
138
|
+
override async generateSourceData() {
|
|
136
139
|
if (!this.query) {
|
|
137
140
|
throw new IllegalStateError('Query is missing');
|
|
138
141
|
}
|
|
@@ -140,4 +143,10 @@ export class LegendQueryDataCubeSourceBuilderState extends LegendDataCubeSourceB
|
|
|
140
143
|
source.queryId = this.query.id;
|
|
141
144
|
return RawLegendQueryDataCubeSource.serialization.toJson(source);
|
|
142
145
|
}
|
|
146
|
+
|
|
147
|
+
override finalizeConfiguration(configuration: DataCubeConfiguration) {
|
|
148
|
+
if (this.query) {
|
|
149
|
+
configuration.name = this.query.name;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
143
152
|
}
|
package/tsconfig.json
CHANGED
|
@@ -60,7 +60,9 @@
|
|
|
60
60
|
"./src/application/LegendDataCubeApplicationConfig.ts",
|
|
61
61
|
"./src/application/LegendDataCubeApplicationPlugin.ts",
|
|
62
62
|
"./src/application/LegendDataCubePluginManager.ts",
|
|
63
|
+
"./src/stores/DuckDBWASM.d.ts",
|
|
63
64
|
"./src/stores/LegendDataCubeBaseStore.ts",
|
|
65
|
+
"./src/stores/LegendDataCubeCacheManager.ts",
|
|
64
66
|
"./src/stores/LegendDataCubeDataCubeEngine.ts",
|
|
65
67
|
"./src/stores/model/LegendQueryDataCubeSource.ts",
|
|
66
68
|
"./src/stores/query-builder/source-builder/AdhocQueryDataCubeSourceBuilderState.ts",
|