@finos/legend-application-data-cube 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/lib/__lib__/LegendDataCubeNavigation.d.ts +1 -1
  2. package/lib/__lib__/LegendDataCubeNavigation.d.ts.map +1 -1
  3. package/lib/components/LegendDataCubeWebApplication.d.ts.map +1 -1
  4. package/lib/components/LegendDataCubeWebApplication.js +1 -14
  5. package/lib/components/LegendDataCubeWebApplication.js.map +1 -1
  6. package/lib/components/query-builder/LegendDataCubeQueryBuilder.d.ts.map +1 -1
  7. package/lib/components/query-builder/LegendDataCubeQueryBuilder.js +23 -23
  8. package/lib/components/query-builder/LegendDataCubeQueryBuilder.js.map +1 -1
  9. package/lib/components/query-builder/source-builder/LegendQueryDataCubeSourceBuilder.d.ts.map +1 -1
  10. package/lib/components/query-builder/source-builder/LegendQueryDataCubeSourceBuilder.js +8 -1
  11. package/lib/components/query-builder/source-builder/LegendQueryDataCubeSourceBuilder.js.map +1 -1
  12. package/lib/index.css +1 -1
  13. package/lib/package.json +2 -2
  14. package/lib/stores/LegendDataCubeCacheManager.d.ts +15 -6
  15. package/lib/stores/LegendDataCubeCacheManager.d.ts.map +1 -1
  16. package/lib/stores/LegendDataCubeCacheManager.js +68 -41
  17. package/lib/stores/LegendDataCubeCacheManager.js.map +1 -1
  18. package/lib/stores/LegendDataCubeDataCubeEngine.d.ts +5 -7
  19. package/lib/stores/LegendDataCubeDataCubeEngine.d.ts.map +1 -1
  20. package/lib/stores/LegendDataCubeDataCubeEngine.js +80 -105
  21. package/lib/stores/LegendDataCubeDataCubeEngine.js.map +1 -1
  22. package/lib/stores/query-builder/LegendDataCubeNewQueryState.d.ts.map +1 -1
  23. package/lib/stores/query-builder/LegendDataCubeNewQueryState.js +10 -10
  24. package/lib/stores/query-builder/LegendDataCubeNewQueryState.js.map +1 -1
  25. package/lib/stores/query-builder/LegendDataCubeQueryBuilderStore.d.ts +0 -1
  26. package/lib/stores/query-builder/LegendDataCubeQueryBuilderStore.d.ts.map +1 -1
  27. package/lib/stores/query-builder/LegendDataCubeQueryBuilderStore.js +18 -9
  28. package/lib/stores/query-builder/LegendDataCubeQueryBuilderStore.js.map +1 -1
  29. package/lib/stores/query-builder/source-builder/AdhocQueryDataCubeSourceBuilderState.d.ts +1 -1
  30. package/lib/stores/query-builder/source-builder/AdhocQueryDataCubeSourceBuilderState.d.ts.map +1 -1
  31. package/lib/stores/query-builder/source-builder/AdhocQueryDataCubeSourceBuilderState.js +1 -1
  32. package/lib/stores/query-builder/source-builder/AdhocQueryDataCubeSourceBuilderState.js.map +1 -1
  33. package/lib/stores/query-builder/source-builder/LegendDataCubeSourceBuilderState.d.ts +4 -3
  34. package/lib/stores/query-builder/source-builder/LegendDataCubeSourceBuilderState.d.ts.map +1 -1
  35. package/lib/stores/query-builder/source-builder/LegendDataCubeSourceBuilderState.js +5 -2
  36. package/lib/stores/query-builder/source-builder/LegendDataCubeSourceBuilderState.js.map +1 -1
  37. package/lib/stores/query-builder/source-builder/LegendQueryDataCubeSourceBuilderState.d.ts +3 -2
  38. package/lib/stores/query-builder/source-builder/LegendQueryDataCubeSourceBuilderState.d.ts.map +1 -1
  39. package/lib/stores/query-builder/source-builder/LegendQueryDataCubeSourceBuilderState.js +6 -1
  40. package/lib/stores/query-builder/source-builder/LegendQueryDataCubeSourceBuilderState.js.map +1 -1
  41. package/package.json +11 -11
  42. package/src/__lib__/LegendDataCubeNavigation.ts +1 -1
  43. package/src/components/LegendDataCubeWebApplication.tsx +1 -25
  44. package/src/components/query-builder/LegendDataCubeQueryBuilder.tsx +26 -27
  45. package/src/components/query-builder/source-builder/LegendQueryDataCubeSourceBuilder.tsx +17 -1
  46. package/src/stores/LegendDataCubeCacheManager.ts +82 -44
  47. package/src/stores/LegendDataCubeDataCubeEngine.ts +116 -142
  48. package/src/stores/query-builder/LegendDataCubeNewQueryState.tsx +12 -18
  49. package/src/stores/query-builder/LegendDataCubeQueryBuilderStore.tsx +26 -10
  50. package/src/stores/query-builder/source-builder/AdhocQueryDataCubeSourceBuilderState.ts +1 -1
  51. package/src/stores/query-builder/source-builder/LegendDataCubeSourceBuilderState.ts +8 -4
  52. package/src/stores/query-builder/source-builder/LegendQueryDataCubeSourceBuilderState.ts +11 -2
@@ -16,7 +16,7 @@
16
16
 
17
17
  import {
18
18
  V1_Lambda,
19
- V1_ValueSpecification,
19
+ type V1_ValueSpecification,
20
20
  type V1_EngineServerClient,
21
21
  V1_PureGraphManager,
22
22
  type V1_PureModelContext,
@@ -70,7 +70,8 @@ import {
70
70
  V1_Table,
71
71
  V1_TestAuthenticationStrategy,
72
72
  V1_VarChar,
73
- type TDSBuilder,
73
+ PackageableElementPointerType,
74
+ DatabaseType,
74
75
  } from '@finos/legend-graph';
75
76
  import {
76
77
  _elementPtr,
@@ -79,17 +80,13 @@ import {
79
80
  type CompletionItem,
80
81
  _function,
81
82
  DataCubeFunction,
82
- _deserializeLambda,
83
83
  AdhocQueryDataCubeSource,
84
84
  ADHOC_QUERY_DATA_CUBE_SOURCE_TYPE,
85
85
  RawAdhocQueryDataCubeSource,
86
86
  _lambda,
87
- _serializeValueSpecification,
88
- _deserializeValueSpecification,
89
87
  _defaultPrimitiveTypeValue,
90
88
  type DataCubeExecutionOptions,
91
89
  CachedDataCubeSource,
92
- type DataCubeQuerySnapshot,
93
90
  } from '@finos/legend-data-cube';
94
91
  import {
95
92
  isNonNullable,
@@ -102,10 +99,11 @@ import {
102
99
  at,
103
100
  assertType,
104
101
  guaranteeType,
105
- assertNonNullable,
102
+ guaranteeNonNullable,
103
+ filterByType,
106
104
  } from '@finos/legend-shared';
107
105
  import type { LegendDataCubeApplicationStore } from './LegendDataCubeBaseStore.js';
108
- import { LegendDataCubeDataCubeCacheEngine } from './LegendDataCubeCacheManager.js';
106
+ import { LegendDataCubeDataCubeCacheManager } from './LegendDataCubeCacheManager.js';
109
107
  import { APPLICATION_EVENT } from '@finos/legend-application';
110
108
  import {
111
109
  LEGEND_QUERY_DATA_CUBE_SOURCE_TYPE,
@@ -123,7 +121,7 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
123
121
  private readonly _depotServerClient: DepotServerClient;
124
122
  private readonly _engineServerClient: V1_EngineServerClient;
125
123
  private readonly _graphManager: V1_PureGraphManager;
126
- private readonly _cacheManager: LegendDataCubeDataCubeCacheEngine;
124
+ private readonly _cacheManager: LegendDataCubeDataCubeCacheManager;
127
125
 
128
126
  constructor(
129
127
  application: LegendDataCubeApplicationStore,
@@ -137,7 +135,15 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
137
135
  this._depotServerClient = depotServerClient;
138
136
  this._engineServerClient = engineServerClient;
139
137
  this._graphManager = graphManager;
140
- this._cacheManager = new LegendDataCubeDataCubeCacheEngine();
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();
141
147
  }
142
148
 
143
149
  // ---------------------------------- IMPLEMENTATION ----------------------------------
@@ -159,7 +165,7 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
159
165
  try {
160
166
  source.columns = (
161
167
  await this._getLambdaRelationType(
162
- _serializeValueSpecification(_lambda([], [source.query])),
168
+ this.serializeValueSpecification(_lambda([], [source.query])),
163
169
  source.model,
164
170
  )
165
171
  ).columns;
@@ -189,14 +195,18 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
189
195
  );
190
196
  const source = new LegendQueryDataCubeSource();
191
197
  source.info = queryInfo;
192
- source.lambda = _deserializeLambda(
193
- await this._engineServerClient.grammarToJSON_lambda(
194
- queryInfo.content,
195
- '',
196
- undefined,
197
- undefined,
198
- false,
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
+ ),
199
208
  ),
209
+ V1_Lambda,
200
210
  );
201
211
  source.mapping = executionContext.mapping;
202
212
  source.runtime = executionContext.runtime;
@@ -215,18 +225,22 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
215
225
  ),
216
226
  );
217
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
218
232
  const parameterValues = await Promise.all(
219
233
  source.lambda.parameters.map(async (parameter) => {
220
234
  if (parameter.genericType?.rawType instanceof V1_PackageableType) {
221
235
  const paramValue = new V1_ParameterValue();
222
236
  paramValue.name = parameter.name;
223
237
  const type = parameter.genericType.rawType.fullPath;
224
- const defauleValue = queryInfo.defaultParameterValues?.find(
238
+ const defaultValue = queryInfo.defaultParameterValues?.find(
225
239
  (val) => val.name === parameter.name,
226
240
  )?.content;
227
241
  paramValue.value =
228
- defauleValue !== undefined
229
- ? await this.parseValueSpecification(defauleValue)
242
+ defaultValue !== undefined
243
+ ? await this.parseValueSpecification(defaultValue)
230
244
  : {
231
245
  _type: V1_deserializeRawValueSpecificationType(type),
232
246
  value: _defaultPrimitiveTypeValue(type),
@@ -240,7 +254,7 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
240
254
  try {
241
255
  source.columns = (
242
256
  await this._getLambdaRelationType(
243
- _serializeValueSpecification(source.lambda),
257
+ this.serializeValueSpecification(source.lambda),
244
258
  source.model,
245
259
  )
246
260
  ).columns;
@@ -264,7 +278,7 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
264
278
  returnSourceInformation?: boolean | undefined,
265
279
  ) {
266
280
  try {
267
- return _deserializeValueSpecification(
281
+ return this.deserializeValueSpecification(
268
282
  await this._engineServerClient.grammarToJSON_valueSpecification(
269
283
  code,
270
284
  '',
@@ -294,7 +308,7 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
294
308
  pretty?: boolean | undefined,
295
309
  ) {
296
310
  return this._graphManager.valueSpecificationToPureCode(
297
- _serializeValueSpecification(value),
311
+ this.serializeValueSpecification(value),
298
312
  pretty,
299
313
  );
300
314
  }
@@ -337,7 +351,7 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
337
351
  ) {
338
352
  try {
339
353
  return await this._getQueryRelationType(
340
- _serializeValueSpecification(query),
354
+ this.serializeValueSpecification(query),
341
355
  source,
342
356
  );
343
357
  } catch (error) {
@@ -415,32 +429,26 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
415
429
  options,
416
430
  );
417
431
  } else if (source instanceof CachedDataCubeSource) {
418
- //execute plan
432
+ // get the execute plan to extract the generated SQL to run against cached DB
419
433
  const executionPlan = await this.generateExecutionPlan(
420
434
  query,
421
435
  source.model,
422
436
  [],
423
437
  options,
424
438
  );
425
- let sql;
426
- if (executionPlan instanceof V1_SimpleExecutionPlan) {
427
- sql = executionPlan.rootExecutionNode.executionNodes
428
- .filter((node) => node instanceof V1_SQLExecutionNode)
429
- .map((x) =>
430
- guaranteeType(
431
- x,
432
- V1_SQLExecutionNode,
433
- `Can't generate sql for the query`,
434
- ),
435
- )
436
- .at(-1)?.sqlQuery;
437
- }
438
- assertNonNullable(sql, `Can't generate sql for the query`);
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
+ );
439
447
  const endTime = performance.now();
440
448
  return {
441
449
  executedQuery: await queryCodePromise,
442
450
  executedSQL: sql,
443
- result: await this._cacheManager.runQuery(sql),
451
+ result: await this._cacheManager.runSQLQuery(sql),
444
452
  executionTime: endTime - startTime,
445
453
  };
446
454
  } else {
@@ -451,17 +459,16 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
451
459
  assertType(
452
460
  result,
453
461
  TDSExecutionResult,
454
- `Can't extract execution result: expected tabular data set format`,
462
+ `Can't process execution result: expected tabular data set format`,
455
463
  );
456
464
  const endTime = performance.now();
457
465
  const queryCode = await queryCodePromise;
458
- const sql =
466
+ const sql = guaranteeNonNullable(
459
467
  result.activities?.[0] instanceof RelationalExecutionActivities
460
468
  ? result.activities[0].sql
461
- : undefined;
462
- if (!sql) {
463
- throw new Error(`Can't generate SQL for query`);
464
- }
469
+ : undefined,
470
+ `Can't process execution result: failed to extract generated SQL`,
471
+ );
465
472
  return {
466
473
  result: result,
467
474
  executedQuery: queryCode,
@@ -493,16 +500,6 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
493
500
  return undefined;
494
501
  }
495
502
 
496
- override processInitialSnapshot(
497
- source: DataCubeSource,
498
- snapshot: DataCubeQuerySnapshot,
499
- ): DataCubeQuerySnapshot {
500
- if (source instanceof LegendQueryDataCubeSource) {
501
- snapshot.data.configuration.name = source.info.name;
502
- }
503
- return snapshot;
504
- }
505
-
506
503
  // ---------------------------------- UTILITIES ----------------------------------
507
504
 
508
505
  private async _getQueryRelationType(
@@ -555,7 +552,7 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
555
552
  (process.env.NODE_ENV === 'development'
556
553
  ? PureClientVersion.VX_X_X
557
554
  : undefined),
558
- function: _serializeValueSpecification(query),
555
+ function: this.serializeValueSpecification(query),
559
556
  model,
560
557
  context: serialize(
561
558
  V1_rawBaseExecutionContextModelSchema,
@@ -577,13 +574,8 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
577
574
  ): Promise<V1_ExecutionPlan> {
578
575
  return V1_deserializeExecutionPlan(
579
576
  await this._engineServerClient.generatePlan({
580
- clientVersion:
581
- options?.clientVersion ??
582
- // eslint-disable-next-line no-process-env
583
- (process.env.NODE_ENV === 'development'
584
- ? PureClientVersion.VX_X_X
585
- : undefined),
586
- function: _serializeValueSpecification(query),
577
+ clientVersion: PureClientVersion.VX_X_X,
578
+ function: this.serializeValueSpecification(query),
587
579
  model: serialize(model),
588
580
  context: serialize(
589
581
  V1_rawBaseExecutionContextModelSchema,
@@ -601,110 +593,92 @@ export class LegendDataCubeDataCubeEngine extends DataCubeEngine {
601
593
  override async initializeCache(
602
594
  source: DataCubeSource,
603
595
  ): Promise<CachedDataCubeSource | undefined> {
604
- if (source instanceof LegendQueryDataCubeSource) {
605
- const fromQuery = this.buildExecutionContext(source);
606
- fromQuery?.parameters.unshift(source.query);
607
- const valSpec = guaranteeType(
608
- fromQuery,
609
- V1_ValueSpecification,
610
- 'Query is not a valueSpecification',
611
- );
612
- const queryLambda = new V1_Lambda();
613
- queryLambda.body = [valSpec];
614
- const resultQuery = await this.executeQuery(
615
- queryLambda,
616
- source,
617
- undefined,
618
- );
619
- const result = resultQuery.result;
620
- await this._cacheManager.initializeDuckDb(result);
621
- return this._synthesizeCachedSource(source, result.builder);
622
- }
623
- return undefined;
624
- }
625
-
626
- override async clearCache() {
627
- await this._cacheManager.clearDuckDb();
628
- }
629
-
630
- // --------------------------------- CACHING UTILITY -------------------------------
631
-
632
- private _synthesizeCachedSource(
633
- source: LegendQueryDataCubeSource,
634
- builder: TDSBuilder,
635
- ) {
636
- const cachedSource = new CachedDataCubeSource();
637
- cachedSource.columns = source.columns;
638
- cachedSource.query = this._synthesizeQuery([
639
- 'local::duckdb::cachedStore',
640
- 'main',
641
- 'cached_tbl',
642
- ]);
643
- cachedSource.model = this._synthesizeModel(builder);
644
- cachedSource.runtime = 'local::duckdb::runtime';
645
- return cachedSource;
646
- }
596
+ const cacheQuery = guaranteeNonNullable(
597
+ this.buildExecutionContext(source),
598
+ `Can't initialize cache: failed to build cache query`,
599
+ );
600
+ cacheQuery.parameters.unshift(source.query);
601
+ const result = await this.executeQuery(
602
+ _lambda([], [cacheQuery]),
603
+ source,
604
+ undefined,
605
+ );
606
+ const {
607
+ schema: schemaName,
608
+ table: tableName,
609
+ rowCount,
610
+ } = await this._cacheManager.cache(result.result);
647
611
 
648
- private _synthesizeQuery(databaseAccessor: string[]) {
649
- const classInstance = new V1_ClassInstance();
650
- classInstance.type = V1_ClassInstanceType.RELATION_STORE_ACCESSOR;
651
- const storeAccessor = new V1_RelationStoreAccessor();
652
- storeAccessor.path = databaseAccessor;
653
- classInstance.value = storeAccessor;
654
- return classInstance;
655
- }
612
+ // model
613
+ const pacakgePath = 'local';
656
614
 
657
- private _synthesizeModel(builder: TDSBuilder) {
658
- // synthesize table
659
615
  const table = new V1_Table();
660
- table.name = 'cached_tbl';
661
- table.columns = builder.columns.map((col) => {
616
+ table.name = tableName;
617
+ table.columns = result.result.builder.columns.map((col) => {
662
618
  const column = new V1_Column();
663
619
  column.name = col.name;
664
620
  column.type = this._getColumnType(col.type);
665
621
  return column;
666
622
  });
667
- // synthesize schema
623
+
668
624
  const schema = new V1_Schema();
669
- schema.name = 'main';
625
+ schema.name = schemaName;
670
626
  schema.tables = [table];
671
- // synthesize database
672
627
  const database = new V1_Database();
673
- database.name = 'cachedStore';
674
- database.package = 'local::duckdb';
628
+ database.name = 'db';
629
+ database.package = pacakgePath;
675
630
  database.schemas = [schema];
676
631
 
677
- // build connection
678
632
  const connection = new V1_RelationalDatabaseConnection();
679
- connection.databaseType = 'DuckDB';
680
- connection.type = 'DuckDB';
633
+ connection.databaseType = DatabaseType.DuckDB;
634
+ connection.type = DatabaseType.DuckDB;
681
635
  const dataSourceSpec = new V1_DuckDBDatasourceSpecification();
682
- dataSourceSpec.path = '/temp/path';
683
- connection.store = 'local::duckdb::cachedStore';
636
+ dataSourceSpec.path = '/tmpFile';
637
+ connection.store = database.path;
684
638
  connection.datasourceSpecification = dataSourceSpec;
685
639
  connection.authenticationStrategy = new V1_TestAuthenticationStrategy();
686
640
 
687
- // build runtime
688
641
  const runtime = new V1_EngineRuntime();
689
642
  const storeConnections = new V1_StoreConnections();
690
643
  storeConnections.store = new V1_PackageableElementPointer(
691
- 'STORE',
692
- `${database.package}::${database.name}`,
644
+ PackageableElementPointerType.STORE,
645
+ database.path,
693
646
  );
694
- const idConnection = new V1_IdentifiedConnection();
695
- idConnection.connection = connection;
696
- idConnection.id = 'local_duckdb_connection';
697
- storeConnections.storeConnections = [idConnection];
647
+ const identifiedConnection = new V1_IdentifiedConnection();
648
+ identifiedConnection.connection = connection;
649
+ identifiedConnection.id = 'c0';
650
+ storeConnections.storeConnections = [identifiedConnection];
698
651
  runtime.connections = [storeConnections];
699
652
 
700
653
  const packageableRuntime = new V1_PackageableRuntime();
701
654
  packageableRuntime.runtimeValue = runtime;
702
- packageableRuntime.package = 'local::duckdb';
703
- packageableRuntime.name = 'runtime';
655
+ packageableRuntime.package = pacakgePath;
656
+ packageableRuntime.name = 'rt';
657
+
658
+ const model = new V1_PureModelContextData();
659
+ model.elements = [database, packageableRuntime];
660
+
661
+ // query
662
+ const query = new V1_ClassInstance();
663
+ query.type = V1_ClassInstanceType.RELATION_STORE_ACCESSOR;
664
+ const storeAccessor = new V1_RelationStoreAccessor();
665
+ storeAccessor.path = [database.path, schema.name, table.name];
666
+ query.value = storeAccessor;
667
+
668
+ const cachedSource = new CachedDataCubeSource();
669
+ cachedSource.columns = source.columns;
670
+ cachedSource.query = query;
671
+ cachedSource.model = model;
672
+ cachedSource.runtime = packageableRuntime.path;
673
+ cachedSource.db = database.path;
674
+ cachedSource.schema = schema.name;
675
+ cachedSource.table = table.name;
676
+ cachedSource.count = rowCount;
677
+ return cachedSource;
678
+ }
704
679
 
705
- const pmcd = new V1_PureModelContextData();
706
- pmcd.elements = [database, packageableRuntime];
707
- return pmcd;
680
+ override async disposeCache(source: CachedDataCubeSource) {
681
+ await this._cacheManager.disposeCache(source);
708
682
  }
709
683
 
710
684
  // TODO: need a better way to infer datatype from tds builder
@@ -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 && !sourceData) {
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 source = sourceData ?? (await this.sourceBuilder.build());
125
- const query = new DataCubeQuery();
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 { generateQueryBuilderRoute } from '../../__lib__/LegendDataCubeNavigation.js';
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 build(): Promise<PlainObject> {
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 { ActionState, type PlainObject } from '@finos/legend-shared';
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 build(): Promise<PlainObject>;
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 { DataCubeAlertService } from '@finos/legend-data-cube';
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 build() {
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
  }