@finos/legend-application-studio 28.3.4 → 28.3.5
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/components/editor/editor-group/data-editor/RelationalCSVDataEditor.d.ts +5 -0
- package/lib/components/editor/editor-group/data-editor/RelationalCSVDataEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/service-editor/ServiceExecutionQueryEditor.d.ts +4 -1
- package/lib/components/editor/editor-group/service-editor/ServiceExecutionQueryEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/service-editor/ServiceExecutionQueryEditor.js +51 -3
- package/lib/components/editor/editor-group/service-editor/ServiceExecutionQueryEditor.js.map +1 -1
- package/lib/components/editor/editor-group/service-editor/testable/ServiceTestDataEditor.d.ts +23 -1
- package/lib/components/editor/editor-group/service-editor/testable/ServiceTestDataEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/service-editor/testable/ServiceTestDataEditor.js +101 -8
- package/lib/components/editor/editor-group/service-editor/testable/ServiceTestDataEditor.js.map +1 -1
- package/lib/components/editor/side-bar/Explorer.d.ts.map +1 -1
- package/lib/components/editor/side-bar/Explorer.js +8 -2
- package/lib/components/editor/side-bar/Explorer.js.map +1 -1
- package/lib/index.css +1 -1
- package/lib/package.json +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.d.ts +38 -1
- package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.js +195 -6
- package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.js.map +1 -1
- package/package.json +4 -4
- package/src/components/editor/editor-group/data-editor/RelationalCSVDataEditor.tsx +1 -1
- package/src/components/editor/editor-group/service-editor/ServiceExecutionQueryEditor.tsx +101 -7
- package/src/components/editor/editor-group/service-editor/testable/ServiceTestDataEditor.tsx +296 -5
- package/src/components/editor/side-bar/Explorer.tsx +17 -0
- package/src/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.ts +337 -11
package/src/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.ts
CHANGED
@@ -25,6 +25,13 @@ import {
|
|
25
25
|
type Mapping,
|
26
26
|
type TestDataGenerationResult,
|
27
27
|
type GraphManagerState,
|
28
|
+
type Column,
|
29
|
+
type ValueSpecification,
|
30
|
+
type Table,
|
31
|
+
type PrimitiveInstanceValue,
|
32
|
+
type ObserverContext,
|
33
|
+
type PureModel,
|
34
|
+
type RelationalDataType,
|
28
35
|
ConnectionTestData,
|
29
36
|
PureSingleExecution,
|
30
37
|
PureMultiExecution,
|
@@ -41,6 +48,10 @@ import {
|
|
41
48
|
Database,
|
42
49
|
RuntimePointer,
|
43
50
|
buildRawLambdaFromLambdaFunction,
|
51
|
+
TableRowIdentifiers,
|
52
|
+
RowIdentifier,
|
53
|
+
ColumnValuePair,
|
54
|
+
TablePtr,
|
44
55
|
} from '@finos/legend-graph';
|
45
56
|
import {
|
46
57
|
type GeneratorFn,
|
@@ -53,6 +64,7 @@ import {
|
|
53
64
|
getNullableFirstEntry,
|
54
65
|
assertType,
|
55
66
|
assertTrue,
|
67
|
+
uuid,
|
56
68
|
} from '@finos/legend-shared';
|
57
69
|
import { action, flow, flowResult, makeObservable, observable } from 'mobx';
|
58
70
|
import type { EditorStore } from '../../../../EditorStore.js';
|
@@ -83,7 +95,9 @@ import {
|
|
83
95
|
buildExecutionParameterValues,
|
84
96
|
buildParametersLetLambdaFunc,
|
85
97
|
getExecutionQueryFromRawLambda,
|
98
|
+
createMockPrimitiveValueSpecification,
|
86
99
|
} from '@finos/legend-query-builder';
|
100
|
+
import { getPrimitiveTypeFromRelationalType } from '../../../../utils/MockDataUtils.js';
|
87
101
|
|
88
102
|
export const createConnectionTestData = (
|
89
103
|
val: IdentifiedConnection,
|
@@ -97,6 +111,24 @@ export const createConnectionTestData = (
|
|
97
111
|
return connectionTestData;
|
98
112
|
};
|
99
113
|
|
114
|
+
export const createMockPrimitiveValueSpecificationFromRelationalDataType = (
|
115
|
+
relationalDataType: RelationalDataType,
|
116
|
+
graph: PureModel,
|
117
|
+
observerContext: ObserverContext,
|
118
|
+
): ValueSpecification | undefined => {
|
119
|
+
const primitiveTypeFromRelational =
|
120
|
+
getPrimitiveTypeFromRelationalType(relationalDataType);
|
121
|
+
|
122
|
+
if (primitiveTypeFromRelational) {
|
123
|
+
return createMockPrimitiveValueSpecification(
|
124
|
+
primitiveTypeFromRelational,
|
125
|
+
graph,
|
126
|
+
observerContext,
|
127
|
+
);
|
128
|
+
}
|
129
|
+
return undefined;
|
130
|
+
};
|
131
|
+
|
100
132
|
export class ServiceTestDataParametersState extends LambdaParametersState {
|
101
133
|
connectionTestDataState: ConnectionTestDataState;
|
102
134
|
|
@@ -111,24 +143,38 @@ export class ServiceTestDataParametersState extends LambdaParametersState {
|
|
111
143
|
this.connectionTestDataState = connectionTestDataState;
|
112
144
|
}
|
113
145
|
|
114
|
-
openModal(
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
146
|
+
openModal(
|
147
|
+
serviceExecutionParameters: {
|
148
|
+
query: RawLambda;
|
149
|
+
mapping: Mapping;
|
150
|
+
runtime: Runtime;
|
151
|
+
},
|
152
|
+
option?: {
|
153
|
+
generateWithSeedData: boolean;
|
154
|
+
},
|
155
|
+
): void {
|
119
156
|
this.parameterStates = this.build(serviceExecutionParameters.query);
|
120
|
-
this.parameterValuesEditorState.open(
|
121
|
-
()
|
122
|
-
flowResult(
|
157
|
+
this.parameterValuesEditorState.open((): Promise<void> => {
|
158
|
+
if (option?.generateWithSeedData) {
|
159
|
+
return flowResult(
|
160
|
+
this.connectionTestDataState.generateTestDataWithSeedDataForDatabaseConnection(
|
161
|
+
serviceExecutionParameters,
|
162
|
+
),
|
163
|
+
).catch(
|
164
|
+
this.connectionTestDataState.editorStore.applicationStore
|
165
|
+
.alertUnhandledError,
|
166
|
+
);
|
167
|
+
} else {
|
168
|
+
return flowResult(
|
123
169
|
this.connectionTestDataState.generateTestDataForDatabaseConnection(
|
124
170
|
serviceExecutionParameters,
|
125
171
|
),
|
126
172
|
).catch(
|
127
173
|
this.connectionTestDataState.editorStore.applicationStore
|
128
174
|
.alertUnhandledError,
|
129
|
-
)
|
130
|
-
|
131
|
-
);
|
175
|
+
);
|
176
|
+
}
|
177
|
+
}, PARAMETER_SUBMIT_ACTION.RUN);
|
132
178
|
}
|
133
179
|
|
134
180
|
build(query: RawLambda): LambdaParameterState[] {
|
@@ -157,14 +203,107 @@ export class ServiceTestDataParametersState extends LambdaParametersState {
|
|
157
203
|
}
|
158
204
|
}
|
159
205
|
|
206
|
+
export class RowIdentifierState {
|
207
|
+
readonly connectionTestDataState: ConnectionTestDataState;
|
208
|
+
readonly _UUID = uuid();
|
209
|
+
column: Column;
|
210
|
+
value: ValueSpecification;
|
211
|
+
|
212
|
+
constructor(
|
213
|
+
connectionTestDataState: ConnectionTestDataState,
|
214
|
+
column: Column,
|
215
|
+
value: ValueSpecification,
|
216
|
+
) {
|
217
|
+
makeObservable(this, {
|
218
|
+
column: observable,
|
219
|
+
value: observable,
|
220
|
+
updateRowIdentifierColumn: action,
|
221
|
+
updateRowIdentifierValue: action,
|
222
|
+
});
|
223
|
+
this.connectionTestDataState = connectionTestDataState;
|
224
|
+
this.column = column;
|
225
|
+
this.value = value;
|
226
|
+
}
|
227
|
+
|
228
|
+
updateRowIdentifierColumn(col: Column): void {
|
229
|
+
this.column = col;
|
230
|
+
}
|
231
|
+
|
232
|
+
updateRowIdentifierValue(val: ValueSpecification): void {
|
233
|
+
this.value = observe_ValueSpecification(
|
234
|
+
val,
|
235
|
+
this.connectionTestDataState.editorStore.changeDetectionState
|
236
|
+
.observerContext,
|
237
|
+
);
|
238
|
+
}
|
239
|
+
}
|
240
|
+
|
241
|
+
export class TableRowIdentifierState {
|
242
|
+
readonly connectionTestDataState: ConnectionTestDataState;
|
243
|
+
readonly _UUID = uuid();
|
244
|
+
table: Table;
|
245
|
+
rowIdentifierStates: RowIdentifierState[] = [];
|
246
|
+
|
247
|
+
constructor(
|
248
|
+
connectionTestDataState: ConnectionTestDataState,
|
249
|
+
table: Table,
|
250
|
+
rowIdentifierStates: RowIdentifierState[],
|
251
|
+
) {
|
252
|
+
makeObservable(this, {
|
253
|
+
table: observable,
|
254
|
+
rowIdentifierStates: observable,
|
255
|
+
updateTable: action,
|
256
|
+
setNewRowIdentifierState: action,
|
257
|
+
addNewRowIdentifierState: action,
|
258
|
+
removeRowIdentifierState: action,
|
259
|
+
});
|
260
|
+
this.connectionTestDataState = connectionTestDataState;
|
261
|
+
this.table = table;
|
262
|
+
this.rowIdentifierStates = rowIdentifierStates;
|
263
|
+
}
|
264
|
+
|
265
|
+
updateTable(table: Table): void {
|
266
|
+
this.table = table;
|
267
|
+
}
|
268
|
+
|
269
|
+
setNewRowIdentifierState(rowIdentifierStates: RowIdentifierState[]): void {
|
270
|
+
this.rowIdentifierStates = rowIdentifierStates;
|
271
|
+
}
|
272
|
+
|
273
|
+
addNewRowIdentifierState(column: Column): void {
|
274
|
+
const valueSpec =
|
275
|
+
createMockPrimitiveValueSpecificationFromRelationalDataType(
|
276
|
+
guaranteeNonNullable(column.type),
|
277
|
+
this.connectionTestDataState.editorStore.graphManagerState.graph,
|
278
|
+
this.connectionTestDataState.editorStore.changeDetectionState
|
279
|
+
.observerContext,
|
280
|
+
);
|
281
|
+
if (valueSpec) {
|
282
|
+
const rowIdentifierState = new RowIdentifierState(
|
283
|
+
this.connectionTestDataState,
|
284
|
+
column,
|
285
|
+
valueSpec,
|
286
|
+
);
|
287
|
+
this.rowIdentifierStates.push(rowIdentifierState);
|
288
|
+
}
|
289
|
+
}
|
290
|
+
|
291
|
+
removeRowIdentifierState(rowIdentifierState: RowIdentifierState): void {
|
292
|
+
deleteEntry(this.rowIdentifierStates, rowIdentifierState);
|
293
|
+
}
|
294
|
+
}
|
295
|
+
|
160
296
|
export class ConnectionTestDataState {
|
161
297
|
readonly editorStore: EditorStore;
|
162
298
|
readonly testDataState: ServiceTestDataState;
|
163
299
|
readonly connectionData: ConnectionTestData;
|
164
300
|
readonly parametersState: ServiceTestDataParametersState;
|
165
301
|
readonly generatingTestDataState = ActionState.create();
|
302
|
+
readonly generatingTestDataWithSeedDataState = ActionState.create();
|
166
303
|
readonly generateSchemaQueryState = ActionState.create();
|
167
304
|
useSharedModal = false;
|
305
|
+
useSeedDataInputModal = false;
|
306
|
+
tableRowIdentifierStates: TableRowIdentifierState[] = [];
|
168
307
|
|
169
308
|
embeddedEditorState: EmbeddedDataEditorState;
|
170
309
|
anonymizeGeneratedData = true;
|
@@ -174,17 +313,26 @@ export class ConnectionTestDataState {
|
|
174
313
|
connectionData: ConnectionTestData,
|
175
314
|
) {
|
176
315
|
makeObservable(this, {
|
316
|
+
tableRowIdentifierStates: observable,
|
177
317
|
generatingTestDataState: observable,
|
318
|
+
generatingTestDataWithSeedDataState: observable,
|
178
319
|
generateSchemaQueryState: observable,
|
179
320
|
embeddedEditorState: observable,
|
180
321
|
useSharedModal: observable,
|
322
|
+
useSeedDataInputModal: observable,
|
181
323
|
anonymizeGeneratedData: observable,
|
182
324
|
setAnonymizeGeneratedData: action,
|
325
|
+
setUseSeedDataInputModal: action,
|
326
|
+
setNewTableIdentifierState: action,
|
327
|
+
addNewTableIdentifierState: action,
|
328
|
+
removeTableIdentifierState: action,
|
183
329
|
changeEmbeddedData: action,
|
184
330
|
buildEmbeddedEditorState: action,
|
185
331
|
createExecutableQuery: action,
|
186
332
|
generateTestData: flow,
|
187
333
|
generateTestDataForDatabaseConnection: flow,
|
334
|
+
generateTestDataWithSeedData: flow,
|
335
|
+
generateTestDataWithSeedDataForDatabaseConnection: flow,
|
188
336
|
generateQuerySchemas: flow,
|
189
337
|
});
|
190
338
|
this.testDataState = testDataState;
|
@@ -214,10 +362,50 @@ export class ConnectionTestDataState {
|
|
214
362
|
}
|
215
363
|
}
|
216
364
|
|
365
|
+
getAvailableTables(): Table[] {
|
366
|
+
const runtime =
|
367
|
+
this.testDataState.testSuiteState.testableState.serviceEditorState
|
368
|
+
.executionState.serviceExecutionParameters?.runtime;
|
369
|
+
if (runtime instanceof RuntimePointer) {
|
370
|
+
const db =
|
371
|
+
runtime.packageableRuntime.value.runtimeValue.connections[0]?.store
|
372
|
+
.value;
|
373
|
+
if (db instanceof Database) {
|
374
|
+
return db.schemas.flatMap((schema) => schema.tables);
|
375
|
+
}
|
376
|
+
}
|
377
|
+
return [];
|
378
|
+
}
|
379
|
+
|
217
380
|
setUseSharedModal(val: boolean): void {
|
218
381
|
this.useSharedModal = val;
|
219
382
|
}
|
220
383
|
|
384
|
+
setUseSeedDataInputModal(val: boolean): void {
|
385
|
+
this.useSeedDataInputModal = val;
|
386
|
+
}
|
387
|
+
|
388
|
+
setNewTableIdentifierState(
|
389
|
+
tableRowIdentifierStates: TableRowIdentifierState[],
|
390
|
+
): void {
|
391
|
+
this.tableRowIdentifierStates = tableRowIdentifierStates;
|
392
|
+
}
|
393
|
+
|
394
|
+
addNewTableIdentifierState(table: Table): void {
|
395
|
+
const tableRowIdentifierState = new TableRowIdentifierState(
|
396
|
+
this,
|
397
|
+
table,
|
398
|
+
[],
|
399
|
+
);
|
400
|
+
this.tableRowIdentifierStates.push(tableRowIdentifierState);
|
401
|
+
}
|
402
|
+
|
403
|
+
removeTableIdentifierState(
|
404
|
+
tableRowIdentifierState: TableRowIdentifierState,
|
405
|
+
): void {
|
406
|
+
deleteEntry(this.tableRowIdentifierStates, tableRowIdentifierState);
|
407
|
+
}
|
408
|
+
|
221
409
|
setAnonymizeGeneratedData(val: boolean): void {
|
222
410
|
this.anonymizeGeneratedData = val;
|
223
411
|
}
|
@@ -337,6 +525,144 @@ export class ConnectionTestDataState {
|
|
337
525
|
}
|
338
526
|
}
|
339
527
|
|
528
|
+
*generateTestDataWithSeedDataForDatabaseConnection(serviceExecutionParameters: {
|
529
|
+
query: RawLambda;
|
530
|
+
mapping: Mapping;
|
531
|
+
runtime: Runtime;
|
532
|
+
}): GeneratorFn<void> {
|
533
|
+
try {
|
534
|
+
this.generatingTestDataWithSeedDataState.inProgress();
|
535
|
+
// NOTE: since we don't have a generic mechanism for test-data generation
|
536
|
+
// we will only report metrics around API usage, when we genericize, we will
|
537
|
+
// move this out
|
538
|
+
LegendStudioTelemetryHelper.logEvent_TestDataGenerationLaunched(
|
539
|
+
this.testDataState.editorStore.applicationStore.telemetryService,
|
540
|
+
);
|
541
|
+
const report = reportGraphAnalytics(
|
542
|
+
this.editorStore.graphManagerState.graph,
|
543
|
+
);
|
544
|
+
const tableRowIdentifiers = this.tableRowIdentifierStates.map(
|
545
|
+
(tableRowIdentifierState) => {
|
546
|
+
const rowIdentifiersArray =
|
547
|
+
tableRowIdentifierState.rowIdentifierStates.map(
|
548
|
+
(rowIdentifierState) =>
|
549
|
+
new RowIdentifier([
|
550
|
+
new ColumnValuePair(
|
551
|
+
rowIdentifierState.column.name,
|
552
|
+
(rowIdentifierState.value as PrimitiveInstanceValue)
|
553
|
+
.values[0] as object, // to do : change once engine code is in place
|
554
|
+
),
|
555
|
+
]),
|
556
|
+
);
|
557
|
+
const tablePtr = new TablePtr();
|
558
|
+
tablePtr.database = tableRowIdentifierState.table.schema._OWNER.path;
|
559
|
+
tablePtr.mainTableDb = tablePtr.database;
|
560
|
+
tablePtr.schema = tableRowIdentifierState.table.schema.name;
|
561
|
+
tablePtr.table = tableRowIdentifierState.table.name;
|
562
|
+
return new TableRowIdentifiers(tablePtr, rowIdentifiersArray);
|
563
|
+
},
|
564
|
+
);
|
565
|
+
const value =
|
566
|
+
(yield this.editorStore.graphManagerState.graphManager.generateExecuteTestDataWithSeedData(
|
567
|
+
getExecutionQueryFromRawLambda(
|
568
|
+
serviceExecutionParameters.query,
|
569
|
+
this.parametersState.parameterStates,
|
570
|
+
this.editorStore.graphManagerState,
|
571
|
+
),
|
572
|
+
tableRowIdentifiers,
|
573
|
+
serviceExecutionParameters.mapping,
|
574
|
+
serviceExecutionParameters.runtime,
|
575
|
+
this.editorStore.graphManagerState.graph,
|
576
|
+
{
|
577
|
+
anonymizeGeneratedData: this.anonymizeGeneratedData,
|
578
|
+
parameterValues: buildExecutionParameterValues(
|
579
|
+
this.parametersState.parameterStates,
|
580
|
+
this.editorStore.graphManagerState,
|
581
|
+
),
|
582
|
+
},
|
583
|
+
report,
|
584
|
+
)) as string;
|
585
|
+
|
586
|
+
// NOTE: since we don't have a generic mechanism for test-data generation
|
587
|
+
// we will only report metrics around API usage, when we genericize, we will
|
588
|
+
// move this out
|
589
|
+
LegendStudioTelemetryHelper.logEvent_TestDataGenerationSucceeded(
|
590
|
+
this.editorStore.applicationStore.telemetryService,
|
591
|
+
report,
|
592
|
+
);
|
593
|
+
service_setConnectionTestDataEmbeddedData(
|
594
|
+
this.connectionData,
|
595
|
+
TEMPORARY__createRelationalDataFromCSV(value),
|
596
|
+
this.editorStore.changeDetectionState.observerContext,
|
597
|
+
);
|
598
|
+
this.embeddedEditorState = new EmbeddedDataEditorState(
|
599
|
+
this.testDataState.editorStore,
|
600
|
+
this.connectionData.testData,
|
601
|
+
);
|
602
|
+
this.generatingTestDataWithSeedDataState.pass();
|
603
|
+
} catch (error) {
|
604
|
+
assertErrorThrown(error);
|
605
|
+
this.editorStore.applicationStore.notificationService.notifyError(
|
606
|
+
`Unable to generate test data: ${error.message}`,
|
607
|
+
);
|
608
|
+
this.generatingTestDataWithSeedDataState.fail();
|
609
|
+
} finally {
|
610
|
+
this.generatingTestDataWithSeedDataState.complete();
|
611
|
+
}
|
612
|
+
}
|
613
|
+
|
614
|
+
*generateTestDataWithSeedData(): GeneratorFn<void> {
|
615
|
+
try {
|
616
|
+
this.generatingTestDataWithSeedDataState.inProgress();
|
617
|
+
const connection = guaranteeNonNullable(
|
618
|
+
this.resolveConnectionValue(this.connectionData.connectionId),
|
619
|
+
`Unable to resolve connection ID '${this.connectionData.connectionId}`,
|
620
|
+
);
|
621
|
+
if (connection instanceof DatabaseConnection) {
|
622
|
+
const serviceExecutionParameters = guaranteeNonNullable(
|
623
|
+
this.testDataState.testSuiteState.testableState.serviceEditorState
|
624
|
+
.executionState.serviceExecutionParameters,
|
625
|
+
);
|
626
|
+
const parameters = (serviceExecutionParameters.query.parameters ??
|
627
|
+
[]) as object[];
|
628
|
+
if (parameters.length > 0) {
|
629
|
+
this.parametersState.openModal(serviceExecutionParameters, {
|
630
|
+
generateWithSeedData: true,
|
631
|
+
});
|
632
|
+
return;
|
633
|
+
} else {
|
634
|
+
yield flowResult(
|
635
|
+
this.generateTestDataWithSeedDataForDatabaseConnection(
|
636
|
+
serviceExecutionParameters,
|
637
|
+
),
|
638
|
+
);
|
639
|
+
}
|
640
|
+
} else {
|
641
|
+
// TODO: delete this once the backend code is in place
|
642
|
+
service_setConnectionTestDataEmbeddedData(
|
643
|
+
this.connectionData,
|
644
|
+
connection.accept_ConnectionVisitor(
|
645
|
+
new TEMPORARY__EmbeddedDataConnectionVisitor(this.editorStore),
|
646
|
+
),
|
647
|
+
this.editorStore.changeDetectionState.observerContext,
|
648
|
+
);
|
649
|
+
}
|
650
|
+
this.embeddedEditorState = new EmbeddedDataEditorState(
|
651
|
+
this.testDataState.editorStore,
|
652
|
+
this.connectionData.testData,
|
653
|
+
);
|
654
|
+
this.generatingTestDataWithSeedDataState.pass();
|
655
|
+
} catch (error) {
|
656
|
+
assertErrorThrown(error);
|
657
|
+
this.editorStore.applicationStore.notificationService.notifyError(
|
658
|
+
`Unable to generate test data with seed data: ${error.message}`,
|
659
|
+
);
|
660
|
+
this.generatingTestDataWithSeedDataState.fail();
|
661
|
+
} finally {
|
662
|
+
this.generatingTestDataWithSeedDataState.complete();
|
663
|
+
}
|
664
|
+
}
|
665
|
+
|
340
666
|
*generateQuerySchemas(): GeneratorFn<void> {
|
341
667
|
try {
|
342
668
|
this.generateSchemaQueryState.inProgress();
|