@finos/legend-application-repl 1.0.31 → 1.0.33

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 (48) hide show
  1. package/lib/application/LegendREPLNavigation.d.ts +20 -0
  2. package/lib/application/LegendREPLNavigation.d.ts.map +1 -0
  3. package/lib/application/LegendREPLNavigation.js +20 -0
  4. package/lib/application/LegendREPLNavigation.js.map +1 -0
  5. package/lib/components/LegendREPLApplication.d.ts.map +1 -1
  6. package/lib/components/LegendREPLApplication.js +9 -12
  7. package/lib/components/LegendREPLApplication.js.map +1 -1
  8. package/lib/components/LegendREPLDataCubeHeader.d.ts +22 -0
  9. package/lib/components/LegendREPLDataCubeHeader.d.ts.map +1 -0
  10. package/lib/components/LegendREPLDataCubeHeader.js +21 -0
  11. package/lib/components/LegendREPLDataCubeHeader.js.map +1 -0
  12. package/lib/components/LegendREPLFramworkProvider.d.ts +21 -0
  13. package/lib/components/LegendREPLFramworkProvider.d.ts.map +1 -0
  14. package/lib/components/LegendREPLFramworkProvider.js +31 -0
  15. package/lib/components/LegendREPLFramworkProvider.js.map +1 -0
  16. package/lib/components/LegendREPLPublishDataCubeAlert.d.ts +20 -0
  17. package/lib/components/LegendREPLPublishDataCubeAlert.d.ts.map +1 -0
  18. package/lib/components/LegendREPLPublishDataCubeAlert.js +36 -0
  19. package/lib/components/LegendREPLPublishDataCubeAlert.js.map +1 -0
  20. package/lib/index.css +1 -1
  21. package/lib/package.json +1 -1
  22. package/lib/stores/LegendREPLBaseStore.d.ts +31 -0
  23. package/lib/stores/LegendREPLBaseStore.d.ts.map +1 -0
  24. package/lib/stores/LegendREPLBaseStore.js +94 -0
  25. package/lib/stores/LegendREPLBaseStore.js.map +1 -0
  26. package/lib/stores/LegendREPLDataCubeEngine.d.ts +6 -6
  27. package/lib/stores/LegendREPLDataCubeEngine.d.ts.map +1 -1
  28. package/lib/stores/LegendREPLDataCubeEngine.js +43 -21
  29. package/lib/stores/LegendREPLDataCubeEngine.js.map +1 -1
  30. package/lib/stores/LegendREPLDataCubeSource.d.ts +4 -0
  31. package/lib/stores/LegendREPLDataCubeSource.d.ts.map +1 -1
  32. package/lib/stores/LegendREPLDataCubeSource.js +3 -0
  33. package/lib/stores/LegendREPLDataCubeSource.js.map +1 -1
  34. package/lib/stores/LegendREPLServerClient.d.ts +15 -11
  35. package/lib/stores/LegendREPLServerClient.d.ts.map +1 -1
  36. package/lib/stores/LegendREPLServerClient.js +22 -25
  37. package/lib/stores/LegendREPLServerClient.js.map +1 -1
  38. package/package.json +7 -7
  39. package/src/application/LegendREPLNavigation.ts +23 -0
  40. package/src/components/LegendREPLApplication.tsx +16 -35
  41. package/src/components/LegendREPLDataCubeHeader.tsx +53 -0
  42. package/src/components/LegendREPLFramworkProvider.tsx +62 -0
  43. package/src/components/LegendREPLPublishDataCubeAlert.tsx +103 -0
  44. package/src/stores/LegendREPLBaseStore.tsx +135 -0
  45. package/src/stores/LegendREPLDataCubeEngine.ts +60 -26
  46. package/src/stores/LegendREPLDataCubeSource.ts +5 -0
  47. package/src/stores/LegendREPLServerClient.ts +37 -41
  48. package/tsconfig.json +6 -1
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Copyright (c) 2020-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import {
18
+ ActionState,
19
+ NetworkClient,
20
+ assertErrorThrown,
21
+ guaranteeNonNullable,
22
+ uuid,
23
+ } from '@finos/legend-shared';
24
+ import type { LegendREPLApplicationStore } from '../application/LegendREPLApplicationStore.js';
25
+ import { LegendREPLServerClient } from './LegendREPLServerClient.js';
26
+ import {
27
+ DataCubeConfiguration,
28
+ DataCubeQuery,
29
+ LayoutConfiguration,
30
+ WindowState,
31
+ type DataCubeState,
32
+ } from '@finos/legend-data-cube';
33
+ import { LegendREPLDataCubeSource } from './LegendREPLDataCubeSource.js';
34
+ import { PersistentDataCubeQuery } from '@finos/legend-graph';
35
+ import { LegendREPLPublishDataCubeAlert } from '../components/LegendREPLPublishDataCubeAlert.js';
36
+
37
+ export class LegendREPLBaseStore {
38
+ readonly application: LegendREPLApplicationStore;
39
+ readonly client: LegendREPLServerClient;
40
+ readonly publishState = ActionState.create();
41
+
42
+ sourceQuery?: string | undefined;
43
+ currentUser?: string | undefined;
44
+ queryServerBaseUrl?: string | undefined;
45
+ hostedApplicationBaseUrl?: string | undefined;
46
+
47
+ constructor(application: LegendREPLApplicationStore) {
48
+ this.application = application;
49
+ this.client = new LegendREPLServerClient(
50
+ new NetworkClient({
51
+ baseUrl: application.config.useDynamicREPLServer
52
+ ? window.location.origin +
53
+ guaranteeNonNullable(application.config.baseAddress).replace(
54
+ '/repl/',
55
+ '',
56
+ )
57
+ : application.config.replUrl,
58
+ }),
59
+ );
60
+ }
61
+
62
+ async publishDataCube(dataCube: DataCubeState) {
63
+ const isPublishAllowed =
64
+ dataCube.view.source instanceof LegendREPLDataCubeSource &&
65
+ dataCube.view.source.isPersistenceSupported &&
66
+ // eslint-disable-next-line no-process-env
67
+ (process.env.NODE_ENV === 'development' || !dataCube.view.source.isLocal);
68
+
69
+ if (
70
+ !this.sourceQuery ||
71
+ !dataCube.view.isSourceProcessed ||
72
+ !this.queryServerBaseUrl ||
73
+ !isPublishAllowed
74
+ ) {
75
+ return;
76
+ }
77
+
78
+ this.publishState.inProgress();
79
+ const task = dataCube.view.newTask('Validate query');
80
+
81
+ try {
82
+ const query = new DataCubeQuery();
83
+ query.query = await dataCube.engine.getValueSpecificationCode(
84
+ dataCube.engine.generateInitialQuery(
85
+ dataCube.view.snapshotManager.currentSnapshot,
86
+ ),
87
+ );
88
+ query.source = {
89
+ // TODO: I can't think of a better name for now, but this form should be
90
+ // moved to the common module potentially
91
+ _type: 'basicQuery',
92
+ query: this.sourceQuery,
93
+ runtime: dataCube.view.source.runtime,
94
+ columns: dataCube.view.source.sourceColumns,
95
+ model: dataCube.view.source.model,
96
+ };
97
+ const newQuery = new PersistentDataCubeQuery();
98
+ newQuery.id = uuid();
99
+ newQuery.name = DataCubeConfiguration.serialization.fromJson(
100
+ dataCube.view.snapshotManager.currentSnapshot.data.configuration,
101
+ ).name;
102
+ newQuery.content = DataCubeQuery.serialization.toJson(query);
103
+ newQuery.owner = this.currentUser;
104
+ const publishedQuery = PersistentDataCubeQuery.serialization.fromJson(
105
+ await this.client.publishQuery(
106
+ PersistentDataCubeQuery.serialization.toJson(newQuery),
107
+ this.queryServerBaseUrl,
108
+ ),
109
+ );
110
+
111
+ const window = new WindowState(
112
+ new LayoutConfiguration('Publish Query', () => (
113
+ <LegendREPLPublishDataCubeAlert query={publishedQuery} />
114
+ )),
115
+ );
116
+ window.configuration.window = {
117
+ width: 420,
118
+ height: 150,
119
+ minWidth: 300,
120
+ minHeight: 100,
121
+ center: true,
122
+ };
123
+ dataCube.engine.layout.newWindow(window);
124
+ } catch (error) {
125
+ assertErrorThrown(error);
126
+ dataCube.view.engine.alertError(error, {
127
+ message: `Persistence Failure: Can't publish query.`,
128
+ text: `Error: ${error.message}`,
129
+ });
130
+ } finally {
131
+ dataCube.view.endTask(task);
132
+ this.publishState.complete();
133
+ }
134
+ }
135
+ }
@@ -15,7 +15,8 @@
15
15
  */
16
16
 
17
17
  import {
18
- GetBaseQueryResult,
18
+ deserializeREPLQuerySource,
19
+ REPL_DATA_CUBE_SOURCE_TYPE,
19
20
  type LegendREPLServerClient,
20
21
  } from './LegendREPLServerClient.js';
21
22
  import {
@@ -24,8 +25,9 @@ import {
24
25
  _lambda,
25
26
  DataCubeEngine,
26
27
  DataCubeFunction,
27
- type DataCubeAPI,
28
28
  type DataCubeSource,
29
+ type DataCubeAPI,
30
+ DataCubeQuery,
29
31
  } from '@finos/legend-data-cube';
30
32
  import {
31
33
  TDSExecutionResult,
@@ -36,12 +38,17 @@ import {
36
38
  V1_serializeValueSpecification,
37
39
  type V1_Lambda,
38
40
  type V1_ValueSpecification,
41
+ V1_buildEngineError,
42
+ V1_EngineError,
39
43
  } from '@finos/legend-graph';
40
44
  import {
45
+ assertErrorThrown,
41
46
  type DocumentationEntry,
42
47
  guaranteeType,
48
+ HttpStatus,
43
49
  isNonNullable,
44
50
  LogEvent,
51
+ NetworkClientError,
45
52
  type PlainObject,
46
53
  } from '@finos/legend-shared';
47
54
  import { LegendREPLDataCubeSource } from './LegendREPLDataCubeSource.js';
@@ -50,19 +57,19 @@ import {
50
57
  APPLICATION_EVENT,
51
58
  shouldDisplayVirtualAssistantDocumentationEntry,
52
59
  } from '@finos/legend-application';
60
+ import type { LegendREPLBaseStore } from './LegendREPLBaseStore.js';
53
61
 
54
62
  export class LegendREPLDataCubeEngine extends DataCubeEngine {
55
63
  readonly application: LegendREPLApplicationStore;
64
+ readonly baseStore: LegendREPLBaseStore;
56
65
  readonly client: LegendREPLServerClient;
57
66
 
58
- constructor(
59
- application: LegendREPLApplicationStore,
60
- client: LegendREPLServerClient,
61
- ) {
67
+ constructor(baseStore: LegendREPLBaseStore) {
62
68
  super();
63
69
 
64
- this.application = application;
65
- this.client = client;
70
+ this.application = baseStore.application;
71
+ this.baseStore = baseStore;
72
+ this.client = baseStore.client;
66
73
  }
67
74
 
68
75
  blockNavigation(
@@ -92,37 +99,49 @@ export class LegendREPLDataCubeEngine extends DataCubeEngine {
92
99
 
93
100
  override async fetchConfiguration() {
94
101
  const info = await this.client.getInfrastructureInfo();
102
+ this.baseStore.currentUser = info.currentUser;
103
+ this.baseStore.queryServerBaseUrl = info.queryServerBaseUrl;
104
+ this.baseStore.hostedApplicationBaseUrl = info.hostedApplicationBaseUrl;
95
105
  return {
96
106
  gridClientLicense: info.gridClientLicense,
97
107
  };
98
108
  }
99
109
 
100
- override async getInitialInput() {
101
- const baseQuery = GetBaseQueryResult.serialization.fromJson(
110
+ async getBaseQuery() {
111
+ return DataCubeQuery.serialization.fromJson(
102
112
  await this.client.getBaseQuery(),
103
113
  );
114
+ }
115
+
116
+ async processQuerySource(value: PlainObject) {
117
+ const _source = deserializeREPLQuerySource(value);
118
+ this.baseStore.sourceQuery = _source.query;
119
+ if (value._type !== REPL_DATA_CUBE_SOURCE_TYPE) {
120
+ throw new Error(
121
+ `Can't process query source of type '${value._type}'. Only type '${REPL_DATA_CUBE_SOURCE_TYPE}' is supported.`,
122
+ );
123
+ }
124
+
104
125
  const source = new LegendREPLDataCubeSource();
105
- source.mapping = baseQuery.source.mapping;
106
- source.query = await this.parseValueSpecification(
107
- baseQuery.source.query,
108
- false,
109
- );
110
- source.runtime = baseQuery.source.runtime;
111
- source.timestamp = baseQuery.source.timestamp;
126
+ source.query = await this.parseValueSpecification(_source.query, false);
112
127
  source.sourceColumns = (
113
128
  await this.getQueryRelationType(_lambda([], [source.query]), source)
114
129
  ).columns;
130
+ source.runtime = _source.runtime;
115
131
 
116
- return {
117
- query: baseQuery.query,
118
- source,
119
- };
132
+ source.mapping = _source.mapping;
133
+ source.timestamp = _source.timestamp;
134
+ source.model = _source.model;
135
+ source.isLocal = _source.isLocal;
136
+ source.isPersistenceSupported = _source.isPersistenceSupported;
137
+
138
+ return source;
120
139
  }
121
140
 
122
141
  async parseValueSpecification(
123
142
  code: string,
124
143
  returnSourceInformation?: boolean,
125
- ): Promise<V1_ValueSpecification> {
144
+ ) {
126
145
  return V1_deserializeValueSpecification(
127
146
  await this.client.parseValueSpecification({
128
147
  code,
@@ -164,10 +183,25 @@ export class LegendREPLDataCubeEngine extends DataCubeEngine {
164
183
  baseQuery: V1_ValueSpecification,
165
184
  source: DataCubeSource,
166
185
  ) {
167
- return this.client.getQueryCodeRelationReturnType({
168
- code,
169
- baseQuery: V1_serializeValueSpecification(baseQuery, []),
170
- });
186
+ try {
187
+ return await this.client.getQueryCodeRelationReturnType({
188
+ code,
189
+ baseQuery: V1_serializeValueSpecification(baseQuery, []),
190
+ });
191
+ } catch (error) {
192
+ assertErrorThrown(error);
193
+ if (
194
+ error instanceof NetworkClientError &&
195
+ error.response.status === HttpStatus.BAD_REQUEST
196
+ ) {
197
+ throw V1_buildEngineError(
198
+ V1_EngineError.serialization.fromJson(
199
+ error.payload as PlainObject<V1_EngineError>,
200
+ ),
201
+ );
202
+ }
203
+ throw error;
204
+ }
171
205
  }
172
206
 
173
207
  async executeQuery(
@@ -15,9 +15,14 @@
15
15
  */
16
16
 
17
17
  import { DataCubeSource } from '@finos/legend-data-cube';
18
+ import type { PlainObject } from '@finos/legend-shared';
18
19
 
19
20
  export class LegendREPLDataCubeSource extends DataCubeSource {
20
21
  runtime!: string;
22
+
21
23
  mapping?: string | undefined;
22
24
  timestamp!: number;
25
+ model?: PlainObject | undefined;
26
+ isLocal!: boolean;
27
+ isPersistenceSupported!: boolean;
23
28
  }
@@ -15,29 +15,25 @@
15
15
  */
16
16
 
17
17
  import {
18
- assertErrorThrown,
19
18
  ContentType,
20
19
  guaranteeNonNullable,
21
20
  HttpHeader,
22
- HttpStatus,
23
- NetworkClientError,
24
21
  SerializationFactory,
25
- usingModelSchema,
22
+ usingConstantValueSchema,
26
23
  type NetworkClient,
27
24
  type PlainObject,
28
25
  } from '@finos/legend-shared';
29
26
  import {
30
- DataCubeQuery,
27
+ type DataCubeQuery,
31
28
  type CompletionItem,
32
29
  type RelationType,
33
30
  } from '@finos/legend-data-cube';
34
31
  import {
35
- V1_buildEngineError,
36
- V1_EngineError,
32
+ type PersistentDataCubeQuery,
37
33
  type V1_Lambda,
38
34
  type V1_ValueSpecification,
39
35
  } from '@finos/legend-graph';
40
- import { createModelSchema, optional, primitive } from 'serializr';
36
+ import { createModelSchema, optional, primitive, raw } from 'serializr';
41
37
 
42
38
  type GetValueSpecificationCodeInput = {
43
39
  value: PlainObject<V1_ValueSpecification>;
@@ -75,18 +71,32 @@ type ExecutionResult = {
75
71
  };
76
72
 
77
73
  type InfrastructureInfo = {
74
+ currentUser?: string | undefined;
78
75
  gridClientLicense?: string | undefined;
76
+ queryServerBaseUrl?: string | undefined;
77
+ hostedApplicationBaseUrl?: string | undefined;
79
78
  };
80
79
 
81
- class QuerySource {
80
+ export const REPL_DATA_CUBE_SOURCE_TYPE = 'repl';
81
+
82
+ class REPLBaseDataCubeQuerySource {
83
+ query!: string;
82
84
  runtime!: string;
85
+ model?: PlainObject | undefined;
86
+
83
87
  mapping?: string | undefined;
84
- query!: string;
85
88
  timestamp!: number;
89
+ isLocal!: boolean;
90
+ isPersistenceSupported!: boolean;
91
+ // columns // we don't need this analytics, we will get this from the query directly
86
92
 
87
93
  static readonly serialization = new SerializationFactory(
88
- createModelSchema(QuerySource, {
94
+ createModelSchema(REPLBaseDataCubeQuerySource, {
95
+ _type: usingConstantValueSchema(REPL_DATA_CUBE_SOURCE_TYPE),
96
+ isLocal: primitive(),
97
+ isPersistenceSupported: primitive(),
89
98
  mapping: optional(primitive()),
99
+ model: optional(raw()),
90
100
  query: primitive(),
91
101
  runtime: primitive(),
92
102
  timestamp: primitive(),
@@ -94,16 +104,10 @@ class QuerySource {
94
104
  );
95
105
  }
96
106
 
97
- export class GetBaseQueryResult {
98
- query!: DataCubeQuery;
99
- source!: QuerySource;
100
-
101
- static readonly serialization = new SerializationFactory(
102
- createModelSchema(GetBaseQueryResult, {
103
- query: usingModelSchema(DataCubeQuery.serialization.schema),
104
- source: usingModelSchema(QuerySource.serialization.schema),
105
- }),
106
- );
107
+ export function deserializeREPLQuerySource(
108
+ value: PlainObject<REPLBaseDataCubeQuerySource>,
109
+ ) {
110
+ return REPLBaseDataCubeQuerySource.serialization.fromJson(value);
107
111
  }
108
112
 
109
113
  export class LegendREPLServerClient {
@@ -154,7 +158,7 @@ export class LegendREPLServerClient {
154
158
  );
155
159
  }
156
160
 
157
- async getBaseQuery(): Promise<PlainObject<GetBaseQueryResult>> {
161
+ async getBaseQuery(): Promise<PlainObject<DataCubeQuery>> {
158
162
  return this.networkClient.get(`${this.dataCube}/getBaseQuery`);
159
163
  }
160
164
 
@@ -170,25 +174,10 @@ export class LegendREPLServerClient {
170
174
  async getQueryCodeRelationReturnType(
171
175
  input: GetQueryCodeRelationReturnTypeInput,
172
176
  ): Promise<RelationType> {
173
- try {
174
- return this.networkClient.post(
175
- `${this.dataCube}/getRelationReturnType/code`,
176
- input,
177
- );
178
- } catch (error) {
179
- assertErrorThrown(error);
180
- if (
181
- error instanceof NetworkClientError &&
182
- error.response.status === HttpStatus.BAD_REQUEST
183
- ) {
184
- throw V1_buildEngineError(
185
- V1_EngineError.serialization.fromJson(
186
- error.payload as PlainObject<V1_EngineError>,
187
- ),
188
- );
189
- }
190
- throw error;
191
- }
177
+ return this.networkClient.post(
178
+ `${this.dataCube}/getRelationReturnType/code`,
179
+ input,
180
+ );
192
181
  }
193
182
 
194
183
  async executeQuery(
@@ -196,4 +185,11 @@ export class LegendREPLServerClient {
196
185
  ): Promise<ExecutionResult> {
197
186
  return this.networkClient.post(`${this.dataCube}/executeQuery`, input);
198
187
  }
188
+
189
+ async publishQuery(
190
+ query: PlainObject<PersistentDataCubeQuery>,
191
+ queryStoreBaseUrl: string,
192
+ ): Promise<PlainObject<PersistentDataCubeQuery>> {
193
+ return this.networkClient.post(`${queryStoreBaseUrl}`, query);
194
+ }
199
195
  }
package/tsconfig.json CHANGED
@@ -54,12 +54,17 @@
54
54
  "./src/__lib__/LegendREPLSetting.ts",
55
55
  "./src/application/LegendREPLApplicationConfig.ts",
56
56
  "./src/application/LegendREPLApplicationStore.ts",
57
+ "./src/application/LegendREPLNavigation.ts",
57
58
  "./src/stores/LegendREPLDataCubeEngine.ts",
58
59
  "./src/stores/LegendREPLDataCubeSource.ts",
59
60
  "./src/stores/LegendREPLServerClient.ts",
60
61
  "./src/index.tsx",
61
62
  "./src/application/LegendREPL.tsx",
62
- "./src/components/LegendREPLApplication.tsx"
63
+ "./src/components/LegendREPLApplication.tsx",
64
+ "./src/components/LegendREPLDataCubeHeader.tsx",
65
+ "./src/components/LegendREPLFramworkProvider.tsx",
66
+ "./src/components/LegendREPLPublishDataCubeAlert.tsx",
67
+ "./src/stores/LegendREPLBaseStore.tsx"
63
68
  ],
64
69
  "include": [
65
70
  "src/**/*.ts",