@finos/legend-application-studio 28.14.0 → 28.14.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 (63) hide show
  1. package/lib/components/editor/editor-group/function-activator/testable/FunctionTestableEditor.d.ts +1 -1
  2. package/lib/components/editor/editor-group/function-activator/testable/FunctionTestableEditor.d.ts.map +1 -1
  3. package/lib/components/editor/editor-group/function-activator/testable/FunctionTestableEditor.js +93 -14
  4. package/lib/components/editor/editor-group/function-activator/testable/FunctionTestableEditor.js.map +1 -1
  5. package/lib/components/editor/editor-group/service-editor/ServiceRegistrationEditor.d.ts.map +1 -1
  6. package/lib/components/editor/editor-group/service-editor/ServiceRegistrationEditor.js +7 -1
  7. package/lib/components/editor/editor-group/service-editor/ServiceRegistrationEditor.js.map +1 -1
  8. package/lib/components/editor/editor-group/service-editor/testable/ServiceTestsEditor.d.ts +1 -13
  9. package/lib/components/editor/editor-group/service-editor/testable/ServiceTestsEditor.d.ts.map +1 -1
  10. package/lib/components/editor/editor-group/service-editor/testable/ServiceTestsEditor.js +7 -21
  11. package/lib/components/editor/editor-group/service-editor/testable/ServiceTestsEditor.js.map +1 -1
  12. package/lib/components/editor/editor-group/testable/TestableSharedComponents.d.ts +12 -1
  13. package/lib/components/editor/editor-group/testable/TestableSharedComponents.d.ts.map +1 -1
  14. package/lib/components/editor/editor-group/testable/TestableSharedComponents.js +13 -3
  15. package/lib/components/editor/editor-group/testable/TestableSharedComponents.js.map +1 -1
  16. package/lib/index.css +2 -2
  17. package/lib/index.css.map +1 -1
  18. package/lib/package.json +1 -1
  19. package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.d.ts +34 -10
  20. package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.d.ts.map +1 -1
  21. package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.js +174 -95
  22. package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.js.map +1 -1
  23. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.d.ts +1 -8
  24. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.d.ts.map +1 -1
  25. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.js +1 -70
  26. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.js.map +1 -1
  27. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.d.ts +1 -1
  28. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.d.ts.map +1 -1
  29. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.js +2 -4
  30. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.js.map +1 -1
  31. package/lib/stores/editor/editor-state/element-editor-state/service/ServiceRegistrationState.d.ts +2 -0
  32. package/lib/stores/editor/editor-state/element-editor-state/service/ServiceRegistrationState.d.ts.map +1 -1
  33. package/lib/stores/editor/editor-state/element-editor-state/service/ServiceRegistrationState.js +6 -0
  34. package/lib/stores/editor/editor-state/element-editor-state/service/ServiceRegistrationState.js.map +1 -1
  35. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestEditorState.d.ts +0 -8
  36. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestEditorState.d.ts.map +1 -1
  37. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestEditorState.js +3 -73
  38. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestEditorState.js.map +1 -1
  39. package/lib/stores/editor/editor-state/element-editor-state/testable/TestableEditorState.d.ts +12 -2
  40. package/lib/stores/editor/editor-state/element-editor-state/testable/TestableEditorState.d.ts.map +1 -1
  41. package/lib/stores/editor/editor-state/element-editor-state/testable/TestableEditorState.js +120 -16
  42. package/lib/stores/editor/editor-state/element-editor-state/testable/TestableEditorState.js.map +1 -1
  43. package/lib/stores/editor/utils/TestableUtils.d.ts +7 -1
  44. package/lib/stores/editor/utils/TestableUtils.d.ts.map +1 -1
  45. package/lib/stores/editor/utils/TestableUtils.js +71 -2
  46. package/lib/stores/editor/utils/TestableUtils.js.map +1 -1
  47. package/lib/stores/graph-modifier/DomainGraphModifierHelper.d.ts +6 -1
  48. package/lib/stores/graph-modifier/DomainGraphModifierHelper.d.ts.map +1 -1
  49. package/lib/stores/graph-modifier/DomainGraphModifierHelper.js +16 -1
  50. package/lib/stores/graph-modifier/DomainGraphModifierHelper.js.map +1 -1
  51. package/package.json +4 -4
  52. package/src/components/editor/editor-group/function-activator/testable/FunctionTestableEditor.tsx +376 -61
  53. package/src/components/editor/editor-group/service-editor/ServiceRegistrationEditor.tsx +38 -1
  54. package/src/components/editor/editor-group/service-editor/testable/ServiceTestsEditor.tsx +18 -92
  55. package/src/components/editor/editor-group/testable/TestableSharedComponents.tsx +74 -1
  56. package/src/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.ts +280 -131
  57. package/src/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.ts +2 -94
  58. package/src/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.ts +5 -5
  59. package/src/stores/editor/editor-state/element-editor-state/service/ServiceRegistrationState.ts +7 -0
  60. package/src/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestEditorState.ts +1 -143
  61. package/src/stores/editor/editor-state/element-editor-state/testable/TestableEditorState.ts +159 -19
  62. package/src/stores/editor/utils/TestableUtils.ts +144 -4
  63. package/src/stores/graph-modifier/DomainGraphModifierHelper.ts +33 -0
@@ -15,7 +15,6 @@
15
15
  */
16
16
 
17
17
  import {
18
- type Binding,
19
18
  type ServiceTest,
20
19
  type Service,
21
20
  type ValueSpecification,
@@ -24,16 +23,7 @@ import {
24
23
  buildLambdaVariableExpressions,
25
24
  VariableExpression,
26
25
  PureMultiExecution,
27
- PackageableElementImplicitReference,
28
- matchFunctionName,
29
- isStubbed_RawLambda,
30
- InstanceValue,
31
- LambdaFunctionInstanceValue,
32
- SimpleFunctionExpression,
33
- CollectionInstanceValue,
34
26
  resolveServiceQueryRawLambda,
35
- PrimitiveInstanceValue,
36
- PrimitiveType,
37
27
  } from '@finos/legend-graph';
38
28
  import { action, flow, makeObservable, observable } from 'mobx';
39
29
  import {
@@ -59,15 +49,9 @@ import {
59
49
  isNonNullable,
60
50
  returnUndefOnError,
61
51
  uuid,
62
- getNullableFirstEntry,
63
- LogEvent,
64
52
  } from '@finos/legend-shared';
65
53
  import type { EditorStore } from '../../../../EditorStore.js';
66
- import {
67
- QUERY_BUILDER_SUPPORTED_FUNCTIONS,
68
- generateVariableExpressionMockValue,
69
- } from '@finos/legend-query-builder';
70
- import { LEGEND_STUDIO_APP_EVENT } from '../../../../../../__lib__/LegendStudioEvent.js';
54
+ import { generateVariableExpressionMockValue } from '@finos/legend-query-builder';
71
55
 
72
56
  export enum SERIALIZATION_FORMAT {
73
57
  PURE = 'PURE',
@@ -199,7 +183,6 @@ export class ServiceTestSetupState {
199
183
  addServiceTestAssertKeys: action,
200
184
  syncWithQuery: action,
201
185
  removeParamValueState: action,
202
- getContentTypeWithParamFromQuery: action,
203
186
  });
204
187
 
205
188
  this.testState = testState;
@@ -243,131 +226,6 @@ export class ServiceTestSetupState {
243
226
  }));
244
227
  }
245
228
 
246
- getContentTypeWithParamFromQuery(): {
247
- contentType: string;
248
- param: string;
249
- }[] {
250
- const query = resolveServiceQueryRawLambda(this.testState.service);
251
- if (query && !isStubbed_RawLambda(query)) {
252
- // safely pass unsupported funtions when building ValueSpecification from Rawlambda
253
- try {
254
- const valueSpec =
255
- this.editorStore.graphManagerState.graphManager.buildValueSpecification(
256
- this.editorStore.graphManagerState.graphManager.serializeRawValueSpecification(
257
- query,
258
- ),
259
- this.editorStore.graphManagerState.graph,
260
- );
261
- if (valueSpec instanceof LambdaFunctionInstanceValue) {
262
- return this.getContentTypeWithParamRecursively(
263
- valueSpec.values[0]?.expressionSequence.find(
264
- (exp) =>
265
- exp instanceof SimpleFunctionExpression &&
266
- (matchFunctionName(
267
- exp.functionName,
268
- QUERY_BUILDER_SUPPORTED_FUNCTIONS.SERIALIZE,
269
- ) ||
270
- matchFunctionName(
271
- exp.functionName,
272
- QUERY_BUILDER_SUPPORTED_FUNCTIONS.EXTERNALIZE,
273
- )),
274
- ),
275
- );
276
- }
277
- } catch (error) {
278
- this.editorStore.applicationStore.logService.error(
279
- LogEvent.create(LEGEND_STUDIO_APP_EVENT.SERVICE_TEST_SETUP_FAILURE),
280
- error,
281
- );
282
- }
283
- }
284
- return [];
285
- }
286
-
287
- getContentTypeWithParamRecursively(
288
- expression: ValueSpecification | undefined,
289
- ): {
290
- contentType: string;
291
- param: string;
292
- }[] {
293
- let currentExpression = expression;
294
- const res: {
295
- contentType: string;
296
- param: string;
297
- }[] = [];
298
- // use if statement to safely scan service query without breaking the app
299
- while (currentExpression instanceof SimpleFunctionExpression) {
300
- if (
301
- matchFunctionName(
302
- currentExpression.functionName,
303
- QUERY_BUILDER_SUPPORTED_FUNCTIONS.INTERNALIZE,
304
- ) ||
305
- matchFunctionName(
306
- currentExpression.functionName,
307
- QUERY_BUILDER_SUPPORTED_FUNCTIONS.GET_RUNTIME_WITH_MODEL_QUERY_CONNECTION,
308
- )
309
- ) {
310
- if (currentExpression.parametersValues[1] instanceof InstanceValue) {
311
- if (
312
- currentExpression.parametersValues[1].values[0] instanceof
313
- PackageableElementImplicitReference &&
314
- currentExpression.parametersValues[2] instanceof VariableExpression
315
- ) {
316
- res.push({
317
- contentType: (
318
- currentExpression.parametersValues[1].values[0].value as Binding
319
- ).contentType,
320
- param: currentExpression.parametersValues[2].name,
321
- });
322
- } else if (
323
- matchFunctionName(
324
- currentExpression.functionName,
325
- QUERY_BUILDER_SUPPORTED_FUNCTIONS.GET_RUNTIME_WITH_MODEL_QUERY_CONNECTION,
326
- ) &&
327
- currentExpression.parametersValues[1] instanceof
328
- PrimitiveInstanceValue &&
329
- currentExpression.parametersValues[1].genericType.value.rawType ===
330
- PrimitiveType.STRING &&
331
- currentExpression.parametersValues[2] instanceof VariableExpression
332
- ) {
333
- res.push({
334
- contentType: currentExpression.parametersValues[1]
335
- .values[0] as string,
336
- param: currentExpression.parametersValues[2].name,
337
- });
338
- }
339
- }
340
- currentExpression = currentExpression.parametersValues[1];
341
- } else if (
342
- matchFunctionName(
343
- currentExpression.functionName,
344
- QUERY_BUILDER_SUPPORTED_FUNCTIONS.FROM,
345
- )
346
- ) {
347
- currentExpression = currentExpression.parametersValues[2];
348
- } else if (
349
- matchFunctionName(
350
- currentExpression.functionName,
351
- QUERY_BUILDER_SUPPORTED_FUNCTIONS.MERGERUNTIMES,
352
- )
353
- ) {
354
- const collection = currentExpression.parametersValues[0];
355
- if (collection instanceof CollectionInstanceValue) {
356
- collection.values
357
- .map((v) => this.getContentTypeWithParamRecursively(v))
358
- .flat()
359
- .map((p) => res.push(p));
360
- }
361
- currentExpression = collection;
362
- } else {
363
- currentExpression = getNullableFirstEntry(
364
- currentExpression.parametersValues,
365
- );
366
- }
367
- }
368
- return res;
369
- }
370
-
371
229
  addServiceTestAssertKeys(val: string[]): void {
372
230
  service_addAssertKeyForTest(this.testState.test, val);
373
231
  }
@@ -36,6 +36,7 @@ import {
36
36
  addUniqueEntry,
37
37
  deleteEntry,
38
38
  isNonNullable,
39
+ filterByType,
39
40
  } from '@finos/legend-shared';
40
41
  import { action, flowResult, makeObservable, observable } from 'mobx';
41
42
  import type { EditorStore } from '../../../EditorStore.js';
@@ -45,7 +46,10 @@ import {
45
46
  testable_deleteTest,
46
47
  testable_setId,
47
48
  } from '../../../../graph-modifier/Testable_GraphModifierHelper.js';
48
- import { createEmptyEqualToJsonAssertion } from '../../../utils/TestableUtils.js';
49
+ import {
50
+ createEmptyEqualToJsonAssertion,
51
+ isTestPassing,
52
+ } from '../../../utils/TestableUtils.js';
49
53
  import { TESTABLE_RESULT } from '../../../sidebar-state/testable/GlobalTestRunnerState.js';
50
54
  import {
51
55
  TestAssertionEditorState,
@@ -144,22 +148,6 @@ export abstract class TestableTestEditorState {
144
148
  }
145
149
  }
146
150
 
147
- *runTest(): GeneratorFn<void> {
148
- try {
149
- this.resetResult();
150
- this.runningTestAction.inProgress();
151
- const result = (yield flowResult(this.fetchTestResult())) as TestResult;
152
- this.handleTestResult(result);
153
- this.runningTestAction.complete();
154
- } catch (error) {
155
- assertErrorThrown(error);
156
- this.editorStore.applicationStore.notificationService.notifyError(
157
- `Error running test: ${error.message}`,
158
- );
159
- this.runningTestAction.fail();
160
- }
161
- }
162
-
163
151
  // Fetches test results. Caller of test should catch the error
164
152
  async fetchTestResult(): Promise<TestResult> {
165
153
  const input = new RunTestsTestableInput(this.testable);
@@ -195,6 +183,18 @@ export abstract class TestableTestEditorState {
195
183
  });
196
184
  }
197
185
 
186
+ correspondsToTestResult(val: TestResult): boolean {
187
+ const atomicTest = this.test;
188
+ if (atomicTest.id === val.atomicTest.id) {
189
+ const parent = atomicTest.__parent;
190
+ if (parent instanceof TestSuite) {
191
+ return parent.id === val.parentSuite?.id;
192
+ }
193
+ return val.parentSuite === undefined && val.testable === this.testable;
194
+ }
195
+ return false;
196
+ }
197
+
198
198
  get assertionCount(): number {
199
199
  return this.assertionEditorStates.length;
200
200
  }
@@ -224,6 +224,21 @@ export abstract class TestableTestEditorState {
224
224
  (state) => state.assertionResultState.result !== TESTABLE_RESULT.PASSED,
225
225
  ).length;
226
226
  }
227
+ *runTest(): GeneratorFn<void> {
228
+ try {
229
+ this.resetResult();
230
+ this.runningTestAction.inProgress();
231
+ const result = (yield flowResult(this.fetchTestResult())) as TestResult;
232
+ this.handleTestResult(result);
233
+ this.runningTestAction.complete();
234
+ } catch (error) {
235
+ assertErrorThrown(error);
236
+ this.editorStore.applicationStore.notificationService.notifyError(
237
+ `Error running test: ${error.message}`,
238
+ );
239
+ this.runningTestAction.fail();
240
+ }
241
+ }
227
242
  }
228
243
 
229
244
  export abstract class TestableTestSuiteEditorState {
@@ -339,6 +354,7 @@ export abstract class TestablePackageableElementEditorState {
339
354
  readonly testable: Testable;
340
355
  testableResults: TestResult[] | undefined;
341
356
  selectedTestSuite: TestableTestSuiteEditorState | undefined;
357
+ runningSuite: TestSuite | undefined;
342
358
 
343
359
  testableComponentToRename: Test | undefined;
344
360
 
@@ -353,12 +369,58 @@ export abstract class TestablePackageableElementEditorState {
353
369
 
354
370
  abstract init(): void;
355
371
 
356
- abstract handleNewResults(results: TestResult[]): void;
357
-
358
372
  get suiteCount(): number {
359
373
  return this.testable.tests.length;
360
374
  }
361
375
 
376
+ get suites(): TestSuite[] {
377
+ return this.testable.tests.filter(filterByType(TestSuite));
378
+ }
379
+
380
+ get passingSuites(): TestSuite[] {
381
+ const results = this.testableResults;
382
+ if (results?.length) {
383
+ return this.suites.filter((suite) =>
384
+ results
385
+ .filter((res) => res.parentSuite?.id === suite.id)
386
+ .every((e) => isTestPassing(e)),
387
+ );
388
+ }
389
+ return [];
390
+ }
391
+
392
+ get failingSuites(): TestSuite[] {
393
+ const results = this.testableResults;
394
+ if (results?.length) {
395
+ return this.suites.filter((suite) =>
396
+ results
397
+ .filter((res) => res.parentSuite?.id === suite.id)
398
+ .some((e) => !isTestPassing(e)),
399
+ );
400
+ }
401
+ return [];
402
+ }
403
+
404
+ resolveSuiteResults(suite: TestSuite): TestResult[] | undefined {
405
+ return this.testableResults?.filter((t) => t.parentSuite?.id === suite.id);
406
+ }
407
+
408
+ clearTestResultsForSuite(suite: TestSuite): void {
409
+ this.testableResults = this.testableResults?.filter(
410
+ (t) => !(this.resolveSuiteResults(suite) ?? []).includes(t),
411
+ );
412
+ }
413
+
414
+ get staticSuites(): TestSuite[] {
415
+ const results = this.testableResults;
416
+ if (results?.length) {
417
+ return this.suites.filter((suite) =>
418
+ results.every((res) => res.parentSuite?.id !== suite.id),
419
+ );
420
+ }
421
+ return this.suites;
422
+ }
423
+
362
424
  setTestableResults(val: TestResult[] | undefined): void {
363
425
  this.testableResults = val;
364
426
  }
@@ -377,9 +439,36 @@ export abstract class TestablePackageableElementEditorState {
377
439
  deleteTestSuite(testSuite: TestSuite): void {
378
440
  testable_deleteTest(this.testable, testSuite);
379
441
  if (this.selectedTestSuite?.suite === testSuite) {
442
+ this.selectedTestSuite = undefined;
380
443
  this.init();
381
444
  }
382
445
  }
446
+
447
+ *runAllFailingSuites(): GeneratorFn<void> {
448
+ try {
449
+ this.isRunningFailingSuitesState.inProgress();
450
+ const input = new RunTestsTestableInput(this.testable);
451
+ this.failingSuites.forEach((s) => {
452
+ s.tests.forEach((t) => input.unitTestIds.push(new UniqueTestId(s, t)));
453
+ });
454
+ const testResults =
455
+ (yield this.editorStore.graphManagerState.graphManager.runTests(
456
+ [input],
457
+ this.editorStore.graphManagerState.graph,
458
+ )) as TestResult[];
459
+ this.handleNewResults(testResults);
460
+ this.isRunningFailingSuitesState.complete();
461
+ } catch (error) {
462
+ assertErrorThrown(error);
463
+ this.editorStore.applicationStore.notificationService.notifyError(error);
464
+ this.isRunningFailingSuitesState.fail();
465
+ } finally {
466
+ this.selectedTestSuite?.testStates.forEach((t) =>
467
+ t.runningTestAction.complete(),
468
+ );
469
+ }
470
+ }
471
+
383
472
  *runTestable(): GeneratorFn<void> {
384
473
  try {
385
474
  this.setTestableResults(undefined);
@@ -406,4 +495,55 @@ export abstract class TestablePackageableElementEditorState {
406
495
  );
407
496
  }
408
497
  }
498
+
499
+ *runSuite(suite: TestSuite): GeneratorFn<void> {
500
+ try {
501
+ this.runningSuite = suite;
502
+ this.clearTestResultsForSuite(suite);
503
+ this.selectedTestSuite?.testStates.forEach((t) => t.resetResult());
504
+ this.selectedTestSuite?.testStates.forEach((t) =>
505
+ t.runningTestAction.inProgress(),
506
+ );
507
+ const input = new RunTestsTestableInput(this.testable);
508
+ suite.tests.forEach((t) =>
509
+ input.unitTestIds.push(new UniqueTestId(suite, t)),
510
+ );
511
+ const testResults =
512
+ (yield this.editorStore.graphManagerState.graphManager.runTests(
513
+ [input],
514
+ this.editorStore.graphManagerState.graph,
515
+ )) as TestResult[];
516
+
517
+ this.handleNewResults(testResults);
518
+ } catch (error) {
519
+ assertErrorThrown(error);
520
+ this.editorStore.applicationStore.notificationService.notifyError(error);
521
+ this.isRunningTestableSuitesState.fail();
522
+ } finally {
523
+ this.selectedTestSuite?.testStates.forEach((t) =>
524
+ t.runningTestAction.complete(),
525
+ );
526
+ this.runningSuite = undefined;
527
+ }
528
+ }
529
+
530
+ handleNewResults(results: TestResult[]): void {
531
+ if (this.testableResults?.length) {
532
+ const newSuitesResults = results
533
+ .map((e) => e.parentSuite?.id)
534
+ .filter(isNonNullable);
535
+ const reducedFilters = this.testableResults.filter(
536
+ (res) => !newSuitesResults.includes(res.parentSuite?.id ?? ''),
537
+ );
538
+ this.setTestableResults([...reducedFilters, ...results]);
539
+ } else {
540
+ this.setTestableResults(results);
541
+ }
542
+ this.testableResults?.forEach((result) => {
543
+ const state = this.selectedTestSuite?.testStates.find((testState) =>
544
+ testState.correspondsToTestResult(result),
545
+ );
546
+ state?.handleTestResult(result);
547
+ });
548
+ }
409
549
  }
@@ -29,29 +29,44 @@ import {
29
29
  type AtomicTest,
30
30
  type Class,
31
31
  type EmbeddedDataVisitor,
32
+ type INTERNAL__UnknownConnection,
33
+ type DataElementReference,
34
+ type INTERNAL__UnknownEmbeddedData,
35
+ type TestResult,
36
+ type ValueSpecification,
37
+ type Binding,
38
+ type RawLambda,
32
39
  ExternalFormatData,
33
40
  RelationalCSVData,
34
41
  ConnectionTestData,
35
42
  EqualToJson,
36
43
  DEFAULT_TEST_ASSERTION_PREFIX,
37
44
  RelationalCSVDataTable,
38
- type INTERNAL__UnknownConnection,
39
45
  getAllIdentifiedConnectionsFromRuntime,
40
46
  ModelStoreData,
41
47
  ModelEmbeddedData,
42
48
  PackageableElementExplicitReference,
43
- type DataElementReference,
44
- type INTERNAL__UnknownEmbeddedData,
45
- type TestResult,
46
49
  TestExecuted,
47
50
  TestExecutionStatus,
51
+ isStubbed_RawLambda,
52
+ SimpleFunctionExpression,
53
+ InstanceValue,
54
+ CollectionInstanceValue,
55
+ matchFunctionName,
56
+ PackageableElementImplicitReference,
57
+ VariableExpression,
58
+ PrimitiveInstanceValue,
59
+ PrimitiveType,
60
+ LambdaFunctionInstanceValue,
48
61
  } from '@finos/legend-graph';
49
62
  import {
50
63
  assertTrue,
51
64
  ContentType,
52
65
  generateEnumerableNameFromToken,
66
+ getNullableFirstEntry,
53
67
  guaranteeNonEmptyString,
54
68
  isNonNullable,
69
+ LogEvent,
55
70
  returnUndefOnError,
56
71
  UnsupportedOperationError,
57
72
  uuid,
@@ -60,6 +75,8 @@ import { EmbeddedDataType } from '../editor-state/ExternalFormatState.js';
60
75
  import type { EditorStore } from '../EditorStore.js';
61
76
  import { createMockDataForMappingElementSource } from './MockDataUtils.js';
62
77
  import type { DSL_Data_LegendStudioApplicationPlugin_Extension } from '../../extensions/DSL_Data_LegendStudioApplicationPlugin_Extension.js';
78
+ import { QUERY_BUILDER_SUPPORTED_FUNCTIONS } from '@finos/legend-query-builder';
79
+ import { LEGEND_STUDIO_APP_EVENT } from '../../../__lib__/LegendStudioEvent.js';
63
80
 
64
81
  export const DEFAULT_TEST_ASSERTION_ID = 'assertion_1';
65
82
  export const DEFAULT_TEST_ID = 'test_1';
@@ -359,3 +376,126 @@ export const TEMPORARY__createRelationalDataFromCSV = (
359
376
  export const isTestPassing = (testResult: TestResult): boolean =>
360
377
  testResult instanceof TestExecuted &&
361
378
  testResult.testExecutionStatus === TestExecutionStatus.PASS;
379
+
380
+ // external format param type
381
+ export interface TestParamContentType {
382
+ contentType: string;
383
+ param: string;
384
+ }
385
+ export const getContentTypeWithParamRecursively = (
386
+ expression: ValueSpecification | undefined,
387
+ ): TestParamContentType[] => {
388
+ let currentExpression = expression;
389
+ const res: TestParamContentType[] = [];
390
+ // use if statement to safely scan service query without breaking the app
391
+ while (currentExpression instanceof SimpleFunctionExpression) {
392
+ if (
393
+ matchFunctionName(
394
+ currentExpression.functionName,
395
+ QUERY_BUILDER_SUPPORTED_FUNCTIONS.INTERNALIZE,
396
+ ) ||
397
+ matchFunctionName(
398
+ currentExpression.functionName,
399
+ QUERY_BUILDER_SUPPORTED_FUNCTIONS.GET_RUNTIME_WITH_MODEL_QUERY_CONNECTION,
400
+ )
401
+ ) {
402
+ if (currentExpression.parametersValues[1] instanceof InstanceValue) {
403
+ if (
404
+ currentExpression.parametersValues[1].values[0] instanceof
405
+ PackageableElementImplicitReference &&
406
+ currentExpression.parametersValues[2] instanceof VariableExpression
407
+ ) {
408
+ res.push({
409
+ contentType: (
410
+ currentExpression.parametersValues[1].values[0].value as Binding
411
+ ).contentType,
412
+ param: currentExpression.parametersValues[2].name,
413
+ });
414
+ } else if (
415
+ matchFunctionName(
416
+ currentExpression.functionName,
417
+ QUERY_BUILDER_SUPPORTED_FUNCTIONS.GET_RUNTIME_WITH_MODEL_QUERY_CONNECTION,
418
+ ) &&
419
+ currentExpression.parametersValues[1] instanceof
420
+ PrimitiveInstanceValue &&
421
+ currentExpression.parametersValues[1].genericType.value.rawType ===
422
+ PrimitiveType.STRING &&
423
+ currentExpression.parametersValues[2] instanceof VariableExpression
424
+ ) {
425
+ res.push({
426
+ contentType: currentExpression.parametersValues[1]
427
+ .values[0] as string,
428
+ param: currentExpression.parametersValues[2].name,
429
+ });
430
+ }
431
+ }
432
+ currentExpression = currentExpression.parametersValues[1];
433
+ } else if (
434
+ matchFunctionName(
435
+ currentExpression.functionName,
436
+ QUERY_BUILDER_SUPPORTED_FUNCTIONS.FROM,
437
+ )
438
+ ) {
439
+ currentExpression = currentExpression.parametersValues[2];
440
+ } else if (
441
+ matchFunctionName(
442
+ currentExpression.functionName,
443
+ QUERY_BUILDER_SUPPORTED_FUNCTIONS.MERGERUNTIMES,
444
+ )
445
+ ) {
446
+ const collection = currentExpression.parametersValues[0];
447
+ if (collection instanceof CollectionInstanceValue) {
448
+ collection.values
449
+ .map((v) => getContentTypeWithParamRecursively(v))
450
+ .flat()
451
+ .map((p) => res.push(p));
452
+ }
453
+ currentExpression = collection;
454
+ } else {
455
+ currentExpression = getNullableFirstEntry(
456
+ currentExpression.parametersValues,
457
+ );
458
+ }
459
+ }
460
+ return res;
461
+ };
462
+
463
+ export const getContentTypeWithParamFromQuery = (
464
+ query: RawLambda | undefined,
465
+ editorStore: EditorStore,
466
+ ): TestParamContentType[] => {
467
+ if (query && !isStubbed_RawLambda(query)) {
468
+ // safely pass unsupported funtions when building ValueSpecification from Rawlambda
469
+ try {
470
+ const valueSpec =
471
+ editorStore.graphManagerState.graphManager.buildValueSpecification(
472
+ editorStore.graphManagerState.graphManager.serializeRawValueSpecification(
473
+ query,
474
+ ),
475
+ editorStore.graphManagerState.graph,
476
+ );
477
+ if (valueSpec instanceof LambdaFunctionInstanceValue) {
478
+ return getContentTypeWithParamRecursively(
479
+ valueSpec.values[0]?.expressionSequence.find(
480
+ (exp) =>
481
+ exp instanceof SimpleFunctionExpression &&
482
+ (matchFunctionName(
483
+ exp.functionName,
484
+ QUERY_BUILDER_SUPPORTED_FUNCTIONS.SERIALIZE,
485
+ ) ||
486
+ matchFunctionName(
487
+ exp.functionName,
488
+ QUERY_BUILDER_SUPPORTED_FUNCTIONS.EXTERNALIZE,
489
+ )),
490
+ ),
491
+ );
492
+ }
493
+ } catch (error) {
494
+ editorStore.applicationStore.logService.error(
495
+ LogEvent.create(LEGEND_STUDIO_APP_EVENT.SERVICE_TEST_SETUP_FAILURE),
496
+ error,
497
+ );
498
+ }
499
+ }
500
+ return [];
501
+ };
@@ -50,6 +50,8 @@ import {
50
50
  type INTERNAL__UnknownFunctionActivator,
51
51
  type FunctionStoreTestData,
52
52
  type ObserverContext,
53
+ type FunctionParameterValue,
54
+ type FunctionTest,
53
55
  type FunctionTestSuite,
54
56
  type AggregationKind,
55
57
  type EmbeddedData,
@@ -73,6 +75,7 @@ import {
73
75
  getOtherAssociatedProperty,
74
76
  observe_EmbeddedData,
75
77
  observe_FunctionTestSuite,
78
+ observe_FunctionParameterValue,
76
79
  } from '@finos/legend-graph';
77
80
 
78
81
  // --------------------------------------------- Packageable Element -------------------------------------
@@ -415,6 +418,36 @@ export const function_addTestSuite = action(
415
418
  },
416
419
  );
417
420
 
421
+ export const function_setParameterValueSpec = action(
422
+ (parameterValue: FunctionParameterValue, val: object) => {
423
+ parameterValue.value = val;
424
+ },
425
+ );
426
+
427
+ export const function_setParameterValues = action(
428
+ (test: FunctionTest, values: FunctionParameterValue[]) => {
429
+ test.parameters = values.map(observe_FunctionParameterValue);
430
+ },
431
+ );
432
+
433
+ export const function_deleteParameterValue = action(
434
+ (test: FunctionTest, value: FunctionParameterValue) => {
435
+ deleteEntry(test.parameters ?? [], value);
436
+ },
437
+ );
438
+
439
+ export const function_addParameterValue = action(
440
+ (test: FunctionTest, value: FunctionParameterValue) => {
441
+ test.parameters?.push(observe_FunctionParameterValue(value));
442
+ },
443
+ );
444
+
445
+ export const function_setParameterName = action(
446
+ (parameterValue: FunctionParameterValue, val: string) => {
447
+ parameterValue.name = val;
448
+ },
449
+ );
450
+
418
451
  // --------------------------------------------- Enumeration -------------------------------------
419
452
 
420
453
  export const enum_setName = action((val: Enum, value: string): void => {