diff --git a/CODEOWNERS b/CODEOWNERS
index 4ec886084ef..9ae1e6d5b14 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -1,10 +1,10 @@
-* @pierredebelen @epsstan @davidharte-gs @gs-ssh16 @hardikmaheshwari
+* @pierredebelen @epsstan @davidharte-gs @gs-ssh16 @hardikmaheshwari @aormerod-gs
/.github/** @finos/legend-engine-maintainers
/docs/** @finos/legend-engine-maintainers
/legend-engine-application-query/** @finos/legend-engine-maintainers
/legend-engine-config/** @finos/legend-engine-maintainers
-/legend-engine-core/** @pierredebelen @epsstan @davidharte-gs @gs-ssh16 @hardikmaheshwari
-/legend-engine-pure/** @pierredebelen @epsstan @davidharte-gs @gs-ssh16 @hardikmaheshwari
+/legend-engine-core/** @pierredebelen @epsstan @davidharte-gs @gs-ssh16 @hardikmaheshwari @aormerod-gs
+/legend-engine-pure/** @pierredebelen @epsstan @davidharte-gs @gs-ssh16 @hardikmaheshwari @aormerod-gs
/legend-engine-xts-analytics/** @finos/legend-engine-maintainers
/legend-engine-xts-authentication/** @finos/legend-engine-maintainers
/legend-engine-xts-avro/** @finos/legend-engine-maintainers
@@ -17,7 +17,7 @@
/legend-engine-xts-flatdata/** @finos/legend-engine-maintainers
/legend-engine-xts-functionActivator/** @finos/legend-engine-maintainers
/legend-engine-xts-generation/** @finos/legend-engine-maintainers
-/legend-engine-xts-graphQL/** @pierredebelen @epsstan @davidharte-gs @gs-ssh16 @hardikmaheshwari
+/legend-engine-xts-graphQL/** @pierredebelen @epsstan @davidharte-gs @gs-ssh16 @hardikmaheshwari @aormerod-gs
/legend-engine-xts-haskell/** @finos/legend-engine-maintainers
/legend-engine-xts-iceberg/** @finos/legend-engine-maintainers
/legend-engine-xts-java/** @finos/legend-engine-maintainers
@@ -37,4 +37,4 @@
/legend-engine-xts-text/** @finos/legend-engine-maintainers
/legend-engine-xts-xml/** @finos/legend-engine-maintainers
.gitignore @finos/legend-engine-maintainers
-pom.xml @finos/legend-engine-maintainers
\ No newline at end of file
+pom.xml @finos/legend-engine-maintainers
diff --git a/docs/externalFormat/extensions/FlatData/integration-with-external-format-contract.md b/docs/externalFormat/extensions/FlatData/integration-with-external-format-contract.md
index 82a985bfffb..2c1f372ae7b 100644
--- a/docs/externalFormat/extensions/FlatData/integration-with-external-format-contract.md
+++ b/docs/externalFormat/extensions/FlatData/integration-with-external-format-contract.md
@@ -6,45 +6,45 @@ This page explains the integration of Flatdata with External Format Contract
Flatdata integrates with external format ecosystem via following contracts :
-1. [Flatdata ExternalFormat contract instance](../../../../legend-engine-xt-flatdata-pure/src/main/resources/core_external_format_flatdata/externalFormatContract.pure)
-2. [Flatdata ExternalFormat LegendJavaPlatformBindingDescriptor](../../../../legend-engine-xt-flatdata-javaPlatformBinding-pure/src/main/resources/core_external_format_flatdata_java_platform_binding/legendJavaPlatformBinding/descriptor.pure)
-3. [Flatdata External Format Extension](../../../../legend-engine-xt-flatdata-model/src/main/java/org/finos/legend/engine/external/format/flatdata/FlatDataExternalFormatExtension.java)
-4. [Flatadata Runtime extension](../../../../legend-engine-xt-flatdata-runtime/src/main/java/org/finos/legend/engine/external/format/flatdata/FlatDataRuntimeExtension.java)
+1. [Flatdata ExternalFormat contract instance](../../../../legend-engine-xts-flatdata/legend-engine-xt-flatdata-pure/src/main/resources/core_external_format_flatdata/externalFormatContract.pure)
+2. [Flatdata ExternalFormat LegendJavaPlatformBindingDescriptor](../../../../legend-engine-xts-flatdata/legend-engine-xt-flatdata-javaPlatformBinding-pure/src/main/resources/core_external_format_flatdata_java_platform_binding/legendJavaPlatformBinding/descriptor.pure)
+3. [Flatdata External Format Extension](../../../../legend-engine-xts-flatdata/legend-engine-xt-flatdata-model/src/main/java/org/finos/legend/engine/external/format/flatdata/FlatDataExternalFormatExtension.java)
+4. [Flatadata Runtime extension](../../../../legend-engine-xts-flatdata/legend-engine-xt-flatdata-runtime/src/main/java/org/finos/legend/engine/external/format/flatdata/FlatDataRuntimeExtension.java)
### Flatdata module structure
Flatdata source code is distributed across 6 core modules as explained below :
1. `legend-engine-xt-flatdata-pure`: This module contains pure code for flatdata format. It hosts
- - [Flatdata ExternalFormat contract instance](../../../../legend-engine-xt-flatdata-pure/src/main/resources/core_external_format_flatdata/externalFormatContract.pure)
- - [Flatdata metamodel](../../../../legend-engine-xt-flatdata-pure/src/main/resources/core_external_format_flatdata/metamodel.pure)
- - [Flatdata to Pure models transformation logic](../../../../legend-engine-xt-flatdata-pure/src/main/resources/core_external_format_flatdata/transformation/toPure)
- - [Flatdata from Pure models transformation logic](../../../../legend-engine-xt-flatdata-pure/src/main/resources/core_external_format_flatdata/transformation/fromPure)
- - [Flatdata binding validation logic](../../../../legend-engine-xt-flatdata-pure/src/main/resources/core_external_format_flatdata/binding/validation)
+ - [Flatdata ExternalFormat contract instance](../../../../legend-engine-xts-flatdata/legend-engine-xt-flatdata-pure/src/main/resources/core_external_format_flatdata/externalFormatContract.pure)
+ - [Flatdata metamodel](../../../../legend-engine-xts-flatdata/legend-engine-xt-flatdata-pure/src/main/resources/core_external_format_flatdata/metamodel/metamodel.pure)
+ - [Flatdata to Pure models transformation logic](../../../../legend-engine-xts-flatdata/legend-engine-xt-flatdata-pure/src/main/resources/core_external_format_flatdata/transformation/toPure)
+ - [Flatdata from Pure models transformation logic](../../../../legend-engine-xts-flatdata/legend-engine-xt-flatdata-pure/src/main/resources/core_external_format_flatdata/transformation/fromPure)
+ - [Flatdata binding validation logic](../../../../legend-engine-xts-flatdata/legend-engine-xt-flatdata-pure/src/main/resources/core_external_format_flatdata/binding/validation)
2. `legend-engine-xt-flatdata-shared`: This is a lightweight module containing contracts/code shared by generation/execution logic. It hosts
- - [Flatdata protocol classes](../../../../legend-engine-xt-flatdata-shared/pom.xml) : These are generated using a plugin.
- - [Flatdata driver contracts](../../../../legend-engine-xt-flatdata-shared/src/main/java/org/finos/legend/engine/external/format/flatdata/driver/spi)
- - [Flatdata core drivers](../../../../legend-engine-xt-flatdata-shared/src/main/java/org/finos/legend/engine/external/format/flatdata/driver/core)
+ - [Flatdata protocol classes](../../../../legend-engine-xts-flatdata/legend-engine-xt-flatdata-shared/pom.xml) : These are generated using a plugin.
+ - [Flatdata driver contracts](../../../../legend-engine-xts-flatdata/legend-engine-xt-flatdata-shared/src/main/java/org/finos/legend/engine/external/format/flatdata/driver/spi)
+ - [Flatdata core drivers](../../../../legend-engine-xts-flatdata/legend-engine-xt-flatdata-shared/src/main/java/org/finos/legend/engine/external/format/flatdata/driver/core)
3. `legend-engine-xt-flatdata-model`: This module links flatdata to external format ecosystem. It hosts
- - [Flatdata External Format Extension](../../../../legend-engine-xt-flatdata-model/src/main/java/org/finos/legend/engine/external/format/flatdata/FlatDataExternalFormatExtension.java)
- - [Flatdata Parser](../../../../legend-engine-xt-flatdata-model/src/main/java/org/finos/legend/engine/external/format/flatdata/grammar/fromPure)
- - [Flatdata Composer](../../../../legend-engine-xt-flatdata-model/src/main/java/org/finos/legend/engine/external/format/flatdata/grammar/toPure)
- - [Flatdata Compiler](../../../../legend-engine-xt-flatdata-model/pom.xml) : This transformation is generated using a plugin
- - [Flatdata Transformer](../../../../legend-engine-xt-flatdata-model/pom.xml) : This transformation is generated using a plugin
- - [Flatdata Extension Service File](../../../../legend-engine-xt-flatdata-model/src/main/resources/META-INF/services/org.finos.legend.engine.external.shared.format.model.ExternalFormatExtension)
+ - [Flatdata External Format Extension](../../../../legend-engine-xts-flatdata/legend-engine-xt-flatdata-model/src/main/java/org/finos/legend/engine/external/format/flatdata/FlatDataExternalFormatExtension.java)
+ - [Flatdata Parser](../../../../legend-engine-xts-flatdata/legend-engine-xt-flatdata-model/src/main/java/org/finos/legend/engine/external/format/flatdata/grammar/fromPure)
+ - [Flatdata Composer](../../../../legend-engine-xts-flatdata/legend-engine-xt-flatdata-model/src/main/java/org/finos/legend/engine/external/format/flatdata/grammar/toPure)
+ - [Flatdata Compiler](../../../../legend-engine-xts-flatdata/legend-engine-xt-flatdata-model/pom.xml) : This transformation is generated using a plugin
+ - [Flatdata Transformer](../../../../legend-engine-xts-flatdata/legend-engine-xt-flatdata-model/pom.xml) : This transformation is generated using a plugin
+ - [Flatdata Extension Service File](../../../../legend-engine-xts-flatdata/legend-engine-xt-flatdata-model/src/main/resources/META-INF/services/org.finos.legend.engine.external.shared.format.model.ExternalFormatExtension)
4. `legend-engine-xt-flatdata-javaPlatformBinding-pure`: This module contains pure code to generate java classes for serialization/deserialization to/from flatdata. It hosts
- - [Flatdata ExternalFormat LegendJavaPlatformBindingDescriptor](../../../../legend-engine-xt-flatdata-javaPlatformBinding-pure/src/main/resources/core_external_format_flatdata_java_platform_binding/legendJavaPlatformBinding/descriptor.pure)
- - [Flatdata internalize descriptor](../../../../legend-engine-xt-flatdata-javaPlatformBinding-pure/src/main/resources/core_external_format_flatdata_java_platform_binding/legendJavaPlatformBinding/internalize.pure)
- - [Flatdata externalize descriptor](../../../../legend-engine-xt-flatdata-javaPlatformBinding-pure/src/main/resources/core_external_format_flatdata_java_platform_binding/legendJavaPlatformBinding/externalize.pure)
+ - [Flatdata ExternalFormat LegendJavaPlatformBindingDescriptor](../../../../legend-engine-xts-flatdata/legend-engine-xt-flatdata-javaPlatformBinding-pure/src/main/resources/core_external_format_flatdata_java_platform_binding/legendJavaPlatformBinding/descriptor.pure)
+ - [Flatdata internalize descriptor](../../../../legend-engine-xts-flatdata/legend-engine-xt-flatdata-javaPlatformBinding-pure/src/main/resources/core_external_format_flatdata_java_platform_binding/legendJavaPlatformBinding/internalize.pure)
+ - [Flatdata externalize descriptor](../../../../legend-engine-xts-flatdata/legend-engine-xt-flatdata-javaPlatformBinding-pure/src/main/resources/core_external_format_flatdata_java_platform_binding/legendJavaPlatformBinding/externalize.pure)
5. `legend-engine-xt-flatdata-runtime`: This module contains logic to execute externalize/internalize on Flatdata. It hosts
- - [Flatadata runtime extension](../../../../legend-engine-xt-flatdata-runtime/src/main/java/org/finos/legend/engine/external/format/flatdata/FlatDataRuntimeExtension.java)
- - [Flatdata runtime extension Service File](../../../../legend-engine-xt-flatdata-runtime/src/main/resources/META-INF/services)
+ - [Flatadata runtime extension](../../../../legend-engine-xts-flatdata/legend-engine-xt-flatdata-runtime/src/main/java/org/finos/legend/engine/external/format/flatdata/FlatDataRuntimeExtension.java)
+ - [Flatdata runtime extension Service File](../../../../legend-engine-xts-flatdata/legend-engine-xt-flatdata-runtime/src/main/resources/META-INF/services)
-6. `legend-engine-xt-flatdata-test`: This module contains logic to execute flatdata tests in maven pipeline.
+6. `legend-engine-xt-flatdata-javaPlatformBinding-test`: This module contains logic to execute flatdata tests in maven pipeline.
-Apart from these core modules we believe flatdata is a generic format which should cater to variety of file formats. Hence we have structured flatdata to be extensible and support variety of other file formats (like bloomberg) via [FlatDataDriverDescription](../../../../legend-engine-xt-flatdata-shared/src/main/java/org/finos/legend/engine/external/format/flatdata/driver/spi/FlatDataDriverDescription.java) implementations
+Apart from these core modules we believe flatdata is a generic format which should cater to variety of file formats. Hence we have structured flatdata to be extensible and support variety of other file formats (like bloomberg) via [FlatDataDriverDescription](../../../../legend-engine-xts-flatdata/legend-engine-xt-flatdata-shared/src/main/java/org/finos/legend/engine/external/format/flatdata/driver/spi/FlatDataDriverDescription.java) implementations
Module: `legend-engine-xt-flatdata-driver-bloomberg` serves as an example how flatdata can be extended for more formats.
diff --git a/docs/externalFormat/steps-to-add-new-external-format.md b/docs/externalFormat/steps-to-add-new-external-format.md
index a0e036e48d0..ce59e90b2f3 100644
--- a/docs/externalFormat/steps-to-add-new-external-format.md
+++ b/docs/externalFormat/steps-to-add-new-external-format.md
@@ -6,7 +6,7 @@ This page describes steps required to add support for a new external format.
### Pure
-- Implement [ExternalFormatContract](../../legend-engine-pure-code-compiled-core/src/main/resources/core/pure/binding/externalFormat/externalFormatContract.pure) : External Format Contract defines your format in legend ecosystem and links all its offered features and configurations. It is defined by following fields
+- Implement [ExternalFormatContract](../../legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/binding/externalFormat/externalFormatContract.pure) : External Format Contract defines your format in legend ecosystem and links all its offered features and configurations. It is defined by following fields
- `id` : Provide id for your External Format
- `contentTypes` : Provide content types for your External Format
- `externalFormatMetamodel` : Define Metamodel for External Format
@@ -15,13 +15,13 @@ This page describes steps required to add support for a new external format.
- Everything except id and schema metamodel is optional for defining an external format. You may choose to add features you need with your external format in parts and as you need them.
Each external format can choose to implement following features -
- `externalFormatToPureDescriptor` : Pure Model generation from External Format Schema
- This is needed when you want to allow users of your external format to generate Pure models from external format schema.
- - To add support for this you need to implement [ExternalFormatToPureDescriptor](../../legend-engine-pure-code-compiled-core/src/main/resources/core/pure/binding/externalFormat/externalFormatContract.pure). This requires you to -
+ - To add support for this you need to implement [ExternalFormatToPureDescriptor](../../legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/binding/externalFormat/externalFormatContract.pure). This requires you to -
- Model SchemaToModelConfiguration for your external format
- Implement a function which takes in an instance of SchemaSet (holding schema instances of your external format) and modeled configuration and generates packageable elements
- Provide a default config for your SchemaToModelConfiguration
- `externalFormatFromPureDescriptor` : External Format Schema generation from Pure Model
- This is needed when you want to allow users of your external format to generate external format schema from authored pure models
- - To add support for this you need to implement [ExternalFormatFromPureDescriptor](../../legend-engine-pure-code-compiled-core/src/main/resources/core/pure/binding/externalFormat/externalFormatContract.pure). This requires you to -
+ - To add support for this you need to implement [ExternalFormatFromPureDescriptor](../../legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/binding/externalFormat/externalFormatContract.pure). This requires you to -
- Model ModelToSchemaConfiguration for your external format
- Implement a function which takes in an instance of ModelUnit and modeled configuration and generates SchemaSet
- Provide a default config for your ModelToSchemaConfiguration
@@ -33,15 +33,15 @@ This page describes steps required to add support for a new external format.
- This is needed when you want to allow users to serialize instances into your external format with custom configurations
- This is used at plan generation/execution time.
- To add support for this you need to -
- - Model subtype of [ExternalFormatExternalizeConfig](../../legend-engine-pure-code-compiled-core/src/main/resources/core/pure/binding/externalFormat/externalFormatContract.pure)
+ - Model subtype of [ExternalFormatExternalizeConfig](../../legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/binding/externalFormat/externalFormatContract.pure)
- Author algorithm to dynamically generate platform binding requirements (for JAVA see below)
- `internalizeConfig` : Defines configurations needed to deserialize data aligning with external format into instances.
- This is needed when you want to allow users to deserialize data aligning with external format into instances to be used with legend ecosystem with custom configurations
- This is used at plan generation/execution time.
- To add support for this you need to -
- - Model [ExternalFormatInternalizeConfig](../../legend-engine-pure-code-compiled-core/src/main/resources/core/pure/binding/externalFormat/externalFormatContract.pure)
+ - Model [ExternalFormatInternalizeConfig](../../legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/binding/externalFormat/externalFormatContract.pure)
- Author algorithm to dynamically generate platform binding requirements (for JAVA see below)
- - `internalizeReturnsChecked` : Defines whether your format returns deserialized instances wrapped in [Checked](../../legend-engine-pure-code-compiled-core/src/main/resources/core/pure/dataQuality/dataQuality.pure) structure or not.
+ - `internalizeReturnsChecked` : Defines whether your format returns deserialized instances wrapped in [Checked](../../legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/dataQuality/dataQuality.pure) structure or not.
- If your external format support internalize (deserialization) feature then you can choose to return deserialized instances wrapped in checked structure.
- Returning checked instances allows you to provide record level lineage and defect information to your users.
- `Default Value`: false
@@ -50,18 +50,18 @@ This page describes steps required to add support for a new external format.
- This field links serialize tree representation for this source record metamodel and defines structure in which record level lineage information will be presented to the user
-- Implement [ExternalFormatLegendJavaPlatformBindingDescriptor](../../legend-engine-xt-javaPlatformBinding-pure/src/main/resources/core_java_platform_binding/legendJavaPlatformBinding/binding/descriptor.pure) : ExternalFormatLegendJavaPlatformBindingDescriptor is a description of algorithms required to integrate your format with JAVA implementation of Legend query engine
+- Implement [ExternalFormatLegendJavaPlatformBindingDescriptor](../../legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-pure/src/main/resources/core_java_platform_binding/legendJavaPlatformBinding/binding/descriptor.pure) : ExternalFormatLegendJavaPlatformBindingDescriptor is a description of algorithms required to integrate your format with JAVA implementation of Legend query engine
- `externalFormatContract` : Links your ExternalFormatContract defined above
- `enginePlatformDependencies` : Inject Engine Dependencies for your format into JAVA Platform Binding conventions.
- These are the java interfaces which your algorithms can use when generating JAVA platform binding code.
- These dependencies serve as the contract between plan generation and execution.
- Now you can choose to implement either or both of serialization/deserialization support for your format
- `externalizeDescriptor` : Description of algorithms required to generate code to support serialization. To add this feature you need to -
- - Provide instance of [ExternalFormatExternalizeBindingDescriptor](../../legend-engine-xt-javaPlatformBinding-pure/src/main/resources/core_java_platform_binding/legendJavaPlatformBinding/binding/descriptor.pure)
+ - Provide instance of [ExternalFormatExternalizeBindingDescriptor](../../legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-pure/src/main/resources/core_java_platform_binding/legendJavaPlatformBinding/binding/descriptor.pure)
- `externalizeGenerator` : Author a function which takes in ExternalFormatExternalizeExecutionNode, Path, GenerationContext, DebugContext and return GeneratedCode. GenerateCode contain entry point and JAVA classes which would be added to the execution plan.
- `externalizePreparator` : You may optionally need to provide an implementation to inject some types into TypeInfoSet to support your generations. Based on basic analysis of query certain types are injected into TypeInfoSet for every ExternalFormatContract
- `internalizeDescriptor` : Description of algorithms required to generate code to support deserialization. To add this feature you need to -
- - Provide instance of [ExternalFormatInternalizeBindingDescriptor](../../legend-engine-xt-javaPlatformBinding-pure/src/main/resources/core_java_platform_binding/legendJavaPlatformBinding/binding/descriptor.pure)
+ - Provide instance of [ExternalFormatInternalizeBindingDescriptor](../../legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-pure/src/main/resources/core_java_platform_binding/legendJavaPlatformBinding/binding/descriptor.pure)
- `internalizeGenerator` : Author a function which takes in ExternalFormatInternalizeExecutionNode, Path, GenerationContext, DebugContext and return GeneratedCode. GenerateCode contain entry point and JAVA classes which would be added to the execution plan
- `internalizePreparator` : You may optionally need to provide an implementation to inject some types into TypeInfoSet to support your generations. Based on basic analysis of query certain types are injected into TypeInfoSet for every ExternalFormatContract
@@ -163,7 +163,7 @@ This page describes steps required to add support for a new external format.
```
-- Implement [ExternalFormatExtension](../../legend-engine-external-shared-format-model/src/main/java/org/finos/legend/engine/external/shared/format/model/ExternalFormatExtension.java) : Basic extension required to integrate external format in legend ecosystem
+- Implement [ExternalFormatExtension](../../legend-engine-core/legend-engine-core-language-pure/legend-engine-external-shared-format-model/src/main/java/org/finos/legend/engine/external/shared/format/model/ExternalFormatExtension.java) : Basic extension required to integrate external format in legend ecosystem
- Each and every external format need to provide implementation for this interface to integrate the format with legend ecosystem.
- To implement this interface you need to provide implementation for following 3 functions -
- `getExternalFormatContract` : Link ExternalFormatContract modeled in PURE
@@ -171,25 +171,25 @@ This page describes steps required to add support for a new external format.
- `metamodelToText` : Implement algorithm to generate PURE grammar from instances of metamodel classes. You should use transformer/composer defined in previous step.
- Define service file with your implementation class, so that your implementation is picked via ServiceLoaders
-- Implement [ExternalFormatSchemaGenerationExtension](../../legend-engine-external-shared-format-model/src/main/java/org/finos/legend/engine/external/shared/format/model/transformation/fromModel/ExternalFormatSchemaGenerationExtension.java): Extension required to integrate your format with Legend schema generation capabilities
+- Implement [ExternalFormatSchemaGenerationExtension](../../legend-engine-core/legend-engine-core-language-pure/legend-engine-external-shared-format-model/src/main/java/org/finos/legend/engine/external/shared/format/model/transformation/fromModel/ExternalFormatSchemaGenerationExtension.java): Extension required to integrate your format with Legend schema generation capabilities
- Implement this to integrate with Legend's schema generation.
- - This extends [ExternalFormatExtension](../../legend-engine-external-shared-format-model/src/main/java/org/finos/legend/engine/external/shared/format/model/ExternalFormatExtension.java)
+ - This extends [ExternalFormatExtension](../../legend-engine-core/legend-engine-core-language-pure/legend-engine-external-shared-format-model/src/main/java/org/finos/legend/engine/external/shared/format/model/ExternalFormatExtension.java)
- To implement this interface you need to implement following functionality in addition to those listed above
- `compileModelToSchemaConfiguration` : Compiles instances of JAVA classes for ModelToSchemaConfiguration into its metamodel counterpart
- Author ModelToSchemaConfiguration in JAVA aligning with what you would have implemented in PURE
- Implement algorithm to translate instances of JAVA classes for ModelToSchemaConfiguration into its metamodel counterpart
- `Prerequiste` : You need to implement `externalFormatFromPureDescriptor` in PURE contract for your format
-- Implement [ExternalFormatModelGenerationExtension](../../legend-engine-external-shared-format-model/src/main/java/org/finos/legend/engine/external/shared/format/model/transformation/toModel/ExternalFormatModelGenerationExtension.java): Extension required to integrate your format with Legend model generation capabilities
+- Implement [ExternalFormatModelGenerationExtension](../../legend-engine-core/legend-engine-core-language-pure/legend-engine-external-shared-format-model/src/main/java/org/finos/legend/engine/external/shared/format/model/transformation/toModel/ExternalFormatModelGenerationExtension.java): Extension required to integrate your format with Legend model generation capabilities
- Implement this to integrate with Legend's model generation.
- - This extends [ExternalFormatExtension](../../legend-engine-external-shared-format-model/src/main/java/org/finos/legend/engine/external/shared/format/model/ExternalFormatExtension.java)
+ - This extends [ExternalFormatExtension](../../legend-engine-core/legend-engine-core-language-pure/legend-engine-external-shared-format-model/src/main/java/org/finos/legend/engine/external/shared/format/model/ExternalFormatExtension.java)
- To implement this interface you need to implement following functionality in addition to those listed above
- `compileSchemaToModelConfiguration` : Compiles instances of JAVA classes for SchemaToModelConfiguration into its metamodel counterpart
- Author SchemaToModelConfiguration in JAVA aligning with what you would have implemented in PURE
- Implement algorithm to translate instances of JAVA classes for SchemaToModelConfiguration into its metamodel counterpart
- `Prerequiste` : You need to implement `externalFormatToPureDescriptor` in PURE contract for your format
-- Implement [ExternalFormatRuntimeExtension](../../legend-engine-external-shared-format-runtime/src/main/java/org/finos/legend/engine/external/shared/runtime/ExternalFormatRuntimeExtension.java) : Extension to integrate your format with Legend's query execution engine
+- Implement [ExternalFormatRuntimeExtension](../../legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-external-shared-format-runtime/src/main/java/org/finos/legend/engine/external/shared/runtime/ExternalFormatRuntimeExtension.java) : Extension to integrate your format with Legend's query execution engine
- Implement this to allow your users to use serialization/deserialization feature with your external format.
- To implement this interface you need to provide implementation for following functions -
- `getContentTypes` : Provide contentTypes for your format
@@ -232,7 +232,7 @@ We recommend following module structure as a starting point -
- legend-engine-xt-{format}-javaPlatformBinding-pure : Module to host pure code for generation of java code to support execution on java engine. Implementation of ExternalFormatLegendJavaPlatformBindingDescriptor is defined here.
- legend-engine-xt-{format}-model : Module to host implementation of ExternalFormatExtension, ExternalFormatSchemaGenerationExtension, ExternalFormatModelGenerationExtension
- legend-engine-xt-{format}-runtime : Module to host implementation of ExternalFormatRuntimeExtension
-- legend-engine-xt-{format}-test : Module to run defined tests in maven pipeline
+- legend-engine-xt-{format}-javaPlatformBinding-test : Module to run defined tests in maven pipeline using java platform binding
#### Dependency Graph
@@ -243,11 +243,14 @@ graph LR
Runtime(legend-engine-xt-format-runtime)
Pure(legend-engine-xt-format-pure)
PureJava(legend-engine-xt-format-javaPlatformBinding-pure)
+ JavaTest(legend-engine-xt-format-javaPlatformBinding-test)
PureJava --> Pure
Model --> Pure
Model --> Shared
Runtime --> Shared
+ JavaTest --> PureJava
+ JavaTest --> Runtime
```
As mentioned these are recommendations at best. Please feel free to diverge from this. Please feel free to explore existing formats to understand the structure more
diff --git a/legend-engine-application-query/pom.xml b/legend-engine-application-query/pom.xml
index 08e8b49dd68..a769efc77e2 100644
--- a/legend-engine-application-query/pom.xml
+++ b/legend-engine-application-query/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-application-query
diff --git a/legend-engine-config/legend-engine-configuration/pom.xml b/legend-engine-config/legend-engine-configuration/pom.xml
index acf6b79a5ee..28ffc2ff09f 100644
--- a/legend-engine-config/legend-engine-configuration/pom.xml
+++ b/legend-engine-config/legend-engine-configuration/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-config
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-configuration
diff --git a/legend-engine-config/legend-engine-connection-integration-tests/pom.xml b/legend-engine-config/legend-engine-connection-integration-tests/pom.xml
index 6953e8a064b..3228943aa0c 100644
--- a/legend-engine-config/legend-engine-connection-integration-tests/pom.xml
+++ b/legend-engine-config/legend-engine-connection-integration-tests/pom.xml
@@ -15,11 +15,12 @@
limitations under the License.
-->
-
+
org.finos.legend.engine
legend-engine-config
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-connection-integration-tests
@@ -74,26 +75,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- junit
- junit
- test
-
org.junit.jupiter
junit-jupiter-api
@@ -104,6 +86,11 @@
junit-jupiter-engine
test
+
+ net.bytebuddy
+ byte-buddy
+ test
+
diff --git a/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/AbstractConnectionFactoryTest.java b/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/AbstractConnectionFactoryTest.java
index 880898bb024..e5b6435ece9 100644
--- a/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/AbstractConnectionFactoryTest.java
+++ b/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/AbstractConnectionFactoryTest.java
@@ -17,19 +17,23 @@
import org.finos.legend.authentication.vault.CredentialVault;
import org.finos.legend.authentication.vault.impl.EnvironmentCredentialVault;
import org.finos.legend.authentication.vault.impl.SystemPropertiesCredentialVault;
+import org.finos.legend.connection.AuthenticationMechanismConfiguration;
import org.finos.legend.connection.Authenticator;
import org.finos.legend.connection.ConnectionFactory;
import org.finos.legend.connection.DatabaseType;
-import org.finos.legend.connection.EnvironmentConfiguration;
import org.finos.legend.connection.IdentityFactory;
import org.finos.legend.connection.IdentitySpecification;
+import org.finos.legend.connection.impl.InstrumentedStoreInstanceProvider;
+import org.finos.legend.connection.LegendEnvironment;
import org.finos.legend.connection.RelationalDatabaseStoreSupport;
import org.finos.legend.connection.StoreInstance;
+import org.finos.legend.connection.impl.EncryptedPrivateKeyPairAuthenticationConfiguration;
import org.finos.legend.connection.impl.KerberosCredentialExtractor;
import org.finos.legend.connection.impl.KeyPairCredentialBuilder;
import org.finos.legend.connection.impl.SnowflakeConnectionBuilder;
+import org.finos.legend.connection.impl.UserPasswordAuthenticationConfiguration;
import org.finos.legend.connection.impl.UserPasswordCredentialBuilder;
-import org.finos.legend.connection.jdbc.StaticJDBCConnectionBuilder;
+import org.finos.legend.connection.impl.StaticJDBCConnectionBuilder;
import org.finos.legend.connection.protocol.AuthenticationConfiguration;
import org.finos.legend.connection.protocol.AuthenticationMechanismType;
import org.finos.legend.engine.shared.core.identity.Identity;
@@ -41,8 +45,9 @@ public abstract class AbstractConnectionFactoryTest
{
protected static final String TEST_STORE_INSTANCE_NAME = "test-store";
- protected EnvironmentConfiguration environmentConfiguration;
+ protected LegendEnvironment environment;
protected IdentityFactory identityFactory;
+ protected InstrumentedStoreInstanceProvider storeInstanceProvider;
protected ConnectionFactory connectionFactory;
@BeforeEach
@@ -50,47 +55,43 @@ public void initialize()
{
this.setup();
- EnvironmentConfiguration.Builder environmentConfigurationBuilder = new EnvironmentConfiguration.Builder()
+ LegendEnvironment.Builder environmentBuilder = new LegendEnvironment.Builder()
.withVaults(
new SystemPropertiesCredentialVault(),
new EnvironmentCredentialVault()
)
.withStoreSupports(
- new RelationalDatabaseStoreSupport.Builder()
+ new RelationalDatabaseStoreSupport.Builder(DatabaseType.POSTGRES)
.withIdentifier("Postgres")
- .withDatabase(DatabaseType.POSTGRES)
- .withAuthenticationMechanisms(
- AuthenticationMechanismType.USER_PASSWORD
+ .withAuthenticationMechanismConfigurations(
+ new AuthenticationMechanismConfiguration.Builder(AuthenticationMechanismType.USER_PASSWORD).withAuthenticationConfigurationTypes(
+ UserPasswordAuthenticationConfiguration.class
+ ).build()
)
.build(),
- new RelationalDatabaseStoreSupport.Builder()
+ new RelationalDatabaseStoreSupport.Builder(DatabaseType.SNOWFLAKE)
.withIdentifier("Snowflake")
- .withDatabase(DatabaseType.SNOWFLAKE)
- .withAuthenticationMechanisms(
- AuthenticationMechanismType.KEY_PAIR
-// AuthenticationMechanismType.OAUTH
+ .withAuthenticationMechanismConfigurations(
+ new AuthenticationMechanismConfiguration.Builder(AuthenticationMechanismType.KEY_PAIR).withAuthenticationConfigurationTypes(
+ EncryptedPrivateKeyPairAuthenticationConfiguration.class
+ ).build()
)
.build()
- )
- .withAuthenticationMechanisms(
- AuthenticationMechanismType.USER_PASSWORD,
- AuthenticationMechanismType.API_KEY,
- AuthenticationMechanismType.KEY_PAIR,
- AuthenticationMechanismType.KERBEROS
);
CredentialVault credentialVault = this.getCredentialVault();
if (credentialVault != null)
{
- environmentConfigurationBuilder.withVault(credentialVault);
+ environmentBuilder.withVault(credentialVault);
}
- this.environmentConfiguration = environmentConfigurationBuilder.build();
+ this.environment = environmentBuilder.build();
- this.identityFactory = new IdentityFactory.Builder(environmentConfiguration)
+ this.identityFactory = new IdentityFactory.Builder(this.environment)
.build();
- this.connectionFactory = new ConnectionFactory.Builder(environmentConfiguration)
+ this.storeInstanceProvider = new InstrumentedStoreInstanceProvider();
+ this.connectionFactory = new ConnectionFactory.Builder(this.environment, this.storeInstanceProvider)
.withCredentialBuilders(
new KerberosCredentialExtractor(),
new UserPasswordCredentialBuilder(),
@@ -129,12 +130,12 @@ public CredentialVault getCredentialVault()
@Test
public void runTest() throws Exception
{
- this.connectionFactory.injectStoreInstance(this.getStoreInstance());
+ this.storeInstanceProvider.injectStoreInstance(this.getStoreInstance());
Identity identity = this.getIdentity();
AuthenticationConfiguration authenticationConfiguration = this.getAuthenticationConfiguration();
Authenticator authenticator = this.connectionFactory.getAuthenticator(identity, TEST_STORE_INSTANCE_NAME, authenticationConfiguration);
- T connection = this.connectionFactory.getConnection(authenticator);
+ T connection = this.connectionFactory.getConnection(identity, authenticator);
this.runTestWithConnection(connection);
System.out.println("Successfully established and checked connection!");
diff --git a/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/TestJDBCConnectionManager.java b/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/TestJDBCConnectionManager.java
new file mode 100644
index 00000000000..7abf243d608
--- /dev/null
+++ b/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/TestJDBCConnectionManager.java
@@ -0,0 +1,295 @@
+// Copyright 2023 Goldman Sachs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.finos.legend.engine.connection.test;
+
+import net.bytebuddy.asm.Advice;
+import org.finos.legend.authentication.vault.impl.PropertiesFileCredentialVault;
+import org.finos.legend.connection.AuthenticationMechanismConfiguration;
+import org.finos.legend.connection.Authenticator;
+import org.finos.legend.connection.ConnectionFactory;
+import org.finos.legend.connection.DatabaseType;
+import org.finos.legend.connection.IdentityFactory;
+import org.finos.legend.connection.IdentitySpecification;
+import org.finos.legend.connection.JDBCConnectionBuilder;
+import org.finos.legend.connection.LegendEnvironment;
+import org.finos.legend.connection.PostgresTestContainerWrapper;
+import org.finos.legend.connection.RelationalDatabaseStoreSupport;
+import org.finos.legend.connection.StoreInstance;
+import org.finos.legend.connection.impl.InstrumentedStoreInstanceProvider;
+import org.finos.legend.connection.impl.JDBCConnectionManager;
+import org.finos.legend.connection.impl.StaticJDBCConnectionBuilder;
+import org.finos.legend.connection.impl.UserPasswordAuthenticationConfiguration;
+import org.finos.legend.connection.impl.UserPasswordCredentialBuilder;
+import org.finos.legend.connection.protocol.AuthenticationConfiguration;
+import org.finos.legend.connection.protocol.AuthenticationMechanismType;
+import org.finos.legend.connection.protocol.ConnectionSpecification;
+import org.finos.legend.connection.protocol.StaticJDBCConnectionSpecification;
+import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.authentication.vault.PropertiesFileSecret;
+import org.finos.legend.engine.shared.core.identity.Identity;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.sql.Connection;
+import java.sql.SQLTransientConnectionException;
+import java.util.Properties;
+
+public class TestJDBCConnectionManager
+{
+ PostgresTestContainerWrapper postgresContainer;
+ private static final String TEST_STORE_INSTANCE_NAME = "test-store";
+
+ private LegendEnvironment environment;
+ private IdentityFactory identityFactory;
+ private InstrumentedStoreInstanceProvider storeInstanceProvider;
+ private ConnectionFactory connectionFactory;
+ private StoreInstance storeInstance;
+
+ @BeforeEach
+ public void setup()
+ {
+ postgresContainer = PostgresTestContainerWrapper.build();
+ postgresContainer.start();
+
+ Properties properties = new Properties();
+ properties.put("passwordRef", this.postgresContainer.getPassword());
+
+ LegendEnvironment.Builder environmentBuilder = new LegendEnvironment.Builder()
+ .withVaults(new PropertiesFileCredentialVault(properties))
+ .withStoreSupports(
+ new RelationalDatabaseStoreSupport.Builder(DatabaseType.POSTGRES)
+ .withIdentifier("Postgres")
+ .withAuthenticationMechanismConfigurations(
+ new AuthenticationMechanismConfiguration.Builder(AuthenticationMechanismType.USER_PASSWORD).withAuthenticationConfigurationTypes(
+ UserPasswordAuthenticationConfiguration.class
+ ).build()
+ )
+ .build()
+ );
+
+ this.environment = environmentBuilder.build();
+ this.identityFactory = new IdentityFactory.Builder(this.environment)
+ .build();
+ this.storeInstanceProvider = new InstrumentedStoreInstanceProvider();
+ ConnectionSpecification connectionSpecification = new StaticJDBCConnectionSpecification(
+ this.postgresContainer.getHost(),
+ this.postgresContainer.getPort(),
+ this.postgresContainer.getDatabaseName()
+ );
+ this.storeInstance = new StoreInstance.Builder(this.environment)
+ .withIdentifier(TEST_STORE_INSTANCE_NAME)
+ .withStoreSupportIdentifier("Postgres")
+ .withConnectionSpecification(connectionSpecification)
+ .build();
+ }
+
+ @AfterEach
+ public void cleanUp()
+ {
+ postgresContainer.stop();
+
+ JDBCConnectionManager.getInstance().flushPool();
+ }
+
+ @Test
+ public void testBasicConnectionPooling() throws Exception
+ {
+ JDBCConnectionBuilder customizedJDBCConnectionBuilder = new StaticJDBCConnectionBuilder.WithPlaintextUsernamePassword();
+ customizedJDBCConnectionBuilder.setConnectionPoolConfig(
+ new JDBCConnectionManager.ConnectionPoolConfig.Builder()
+ .withMaxPoolSize(2)
+ .withConnectionTimeout(1000L)
+ .build()
+ );
+ this.connectionFactory = new ConnectionFactory.Builder(this.environment, this.storeInstanceProvider)
+ .withCredentialBuilders(
+ new UserPasswordCredentialBuilder()
+ )
+ .withConnectionBuilders(
+ customizedJDBCConnectionBuilder
+ )
+ .build();
+ this.storeInstanceProvider.injectStoreInstance(this.storeInstance);
+ Identity identity = identityFactory.createIdentity(
+ new IdentitySpecification.Builder()
+ .withName("test-user")
+ .build()
+ );
+ ConnectionSpecification connectionSpecification = this.storeInstance.getConnectionSpecification();
+ AuthenticationConfiguration authenticationConfiguration = new UserPasswordAuthenticationConfiguration(
+ postgresContainer.getUser(),
+ new PropertiesFileSecret("passwordRef")
+ );
+ Authenticator authenticator = this.connectionFactory.getAuthenticator(identity, TEST_STORE_INSTANCE_NAME, authenticationConfiguration);
+
+ JDBCConnectionManager connectionManager = JDBCConnectionManager.getInstance();
+ Assertions.assertEquals(0, connectionManager.getPoolSize());
+
+ // 1. Get a connection, this should initialize the pool as well as create a new connection in the empty pool
+ // this connection should be active
+ Connection connection0 = this.connectionFactory.getConnection(identity, authenticator);
+
+ String poolName = JDBCConnectionManager.getPoolName(identity, connectionSpecification, authenticationConfiguration);
+ JDBCConnectionManager.ConnectionPool connectionPool = connectionManager.getPool(poolName);
+
+ // 2. Close the connection, verify that the pool keeps this connection around in idle state
+ Connection underlyingConnection0 = connection0.unwrap(Connection.class);
+ connection0.close();
+
+ Assertions.assertEquals(1, connectionPool.getTotalConnections());
+ Assertions.assertEquals(0, connectionPool.getActiveConnections());
+ Assertions.assertEquals(1, connectionPool.getIdleConnections());
+
+ // 3. Get a new connection, the pool should return the idle connection and create no new connection
+ Connection connection1 = this.connectionFactory.getConnection(identity, authenticator);
+
+ Assertions.assertEquals(underlyingConnection0, connection1.unwrap(Connection.class));
+ Assertions.assertEquals(1, connectionPool.getTotalConnections());
+ Assertions.assertEquals(1, connectionPool.getActiveConnections());
+ Assertions.assertEquals(0, connectionPool.getIdleConnections());
+
+ // 4. Get another connection while the first one is still alive and used, a new connection
+ // will be created in the pool
+ this.connectionFactory.getConnection(identity, authenticator);
+
+ Assertions.assertEquals(2, connectionPool.getTotalConnections());
+ Assertions.assertEquals(2, connectionPool.getActiveConnections());
+ Assertions.assertEquals(0, connectionPool.getIdleConnections());
+
+ // 5. Get yet another connection while the first and second one are still alive and used, this will
+ // exceed the pool size, throwing an error
+ Assertions.assertThrows(SQLTransientConnectionException.class, () ->
+ {
+ this.connectionFactory.getConnection(identity, authenticator);
+ });
+ }
+
+ @Test
+ public void testConnectionPoolingForDifferentIdentities() throws Exception
+ {
+ this.connectionFactory = new ConnectionFactory.Builder(this.environment, this.storeInstanceProvider)
+ .withCredentialBuilders(
+ new UserPasswordCredentialBuilder()
+ )
+ .withConnectionBuilders(
+ new StaticJDBCConnectionBuilder.WithPlaintextUsernamePassword()
+ )
+ .build();
+ this.storeInstanceProvider.injectStoreInstance(this.storeInstance);
+ Identity identity1 = identityFactory.createIdentity(
+ new IdentitySpecification.Builder()
+ .withName("testUser1")
+ .build()
+ );
+ Identity identity2 = identityFactory.createIdentity(
+ new IdentitySpecification.Builder()
+ .withName("testUser2")
+ .build()
+ );
+ ConnectionSpecification connectionSpecification = this.storeInstance.getConnectionSpecification();
+ AuthenticationConfiguration authenticationConfiguration = new UserPasswordAuthenticationConfiguration(
+ postgresContainer.getUser(),
+ new PropertiesFileSecret("passwordRef")
+ );
+
+ JDBCConnectionManager connectionManager = JDBCConnectionManager.getInstance();
+ Assertions.assertEquals(0, connectionManager.getPoolSize());
+
+ // 1. Get a new connection for identity1, which should initialize a pool
+ this.connectionFactory.getConnection(identity1, this.connectionFactory.getAuthenticator(identity1, TEST_STORE_INSTANCE_NAME, authenticationConfiguration));
+
+ String poolName1 = JDBCConnectionManager.getPoolName(identity1, connectionSpecification, authenticationConfiguration);
+ JDBCConnectionManager.ConnectionPool connectionPool1 = connectionManager.getPool(poolName1);
+
+ Assertions.assertEquals(1, connectionManager.getPoolSize());
+ Assertions.assertEquals(1, connectionPool1.getTotalConnections());
+ Assertions.assertEquals(1, connectionPool1.getActiveConnections());
+ Assertions.assertEquals(0, connectionPool1.getIdleConnections());
+
+ // 2. Get a new connection for identity2, which should initialize another pool
+ this.connectionFactory.getConnection(identity2, this.connectionFactory.getAuthenticator(identity2, TEST_STORE_INSTANCE_NAME, authenticationConfiguration));
+
+ String poolName2 = JDBCConnectionManager.getPoolName(identity2, connectionSpecification, authenticationConfiguration);
+ JDBCConnectionManager.ConnectionPool connectionPool2 = connectionManager.getPool(poolName2);
+
+ Assertions.assertEquals(2, connectionManager.getPoolSize());
+ Assertions.assertEquals(1, connectionPool2.getTotalConnections());
+ Assertions.assertEquals(1, connectionPool2.getActiveConnections());
+ Assertions.assertEquals(0, connectionPool2.getIdleConnections());
+ }
+
+ @Test
+ public void testRetryOnBrokenConnection()
+ {
+ //
+ }
+
+ public static class CustomAdvice
+ {
+ @Advice.OnMethodExit
+ public static void intercept(@Advice.Return(readOnly = false) String value)
+ {
+ System.out.println("intercepted: " + value);
+ value = "hi: " + value;
+ }
+ }
+
+// public static class MyWay
+// {
+// }
+//
+// private static class InstrumentedStaticJDBCConnectionBuilder
+// {
+// static class WithPlaintextUsernamePassword extends StaticJDBCConnectionBuilder.WithPlaintextUsernamePassword
+// {
+// WithPlaintextUsernamePassword(Function hikariConfigHandler)
+// {
+// this.connectionManager = new InstrumentedJDBCConnectionManager(hikariConfigHandler);
+// }
+//
+// @Override
+// public JDBCConnectionManager getConnectionManager()
+// {
+// return this.connectionManager;
+// }
+//
+// @Override
+// protected Type[] actualTypeArguments()
+// {
+// Type genericSuperClass = this.getClass().getSuperclass().getGenericSuperclass();
+// ParameterizedType parameterizedType = (ParameterizedType) genericSuperClass;
+// return parameterizedType.getActualTypeArguments();
+// }
+// }
+// }
+//
+// private static class InstrumentedJDBCConnectionManager extends JDBCConnectionManager
+// {
+// private final Function hikariConfigHandler;
+//
+// InstrumentedJDBCConnectionManager(Function hikariConfigHandler)
+// {
+// this.hikariConfigHandler = hikariConfigHandler;
+// }
+//
+//// @Override
+//// protected void handleHikariConfig(HikariConfig config)
+//// {
+//// config.setRegisterMbeans(true);
+//// this.hikariConfigHandler.apply(config);
+//// }
+// }
+}
diff --git a/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/TestPostgresConnection.java b/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/TestPostgresConnection.java
index 1f92986d3e6..9e311f05fa8 100644
--- a/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/TestPostgresConnection.java
+++ b/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/TestPostgresConnection.java
@@ -16,10 +16,11 @@
import org.finos.legend.authentication.vault.CredentialVault;
import org.finos.legend.authentication.vault.impl.PropertiesFileCredentialVault;
+import org.finos.legend.connection.AuthenticationMechanismConfiguration;
import org.finos.legend.connection.PostgresTestContainerWrapper;
import org.finos.legend.connection.StoreInstance;
import org.finos.legend.connection.impl.UserPasswordAuthenticationConfiguration;
-import org.finos.legend.connection.jdbc.StaticJDBCConnectionSpecification;
+import org.finos.legend.connection.protocol.StaticJDBCConnectionSpecification;
import org.finos.legend.connection.protocol.AuthenticationConfiguration;
import org.finos.legend.connection.protocol.AuthenticationMechanismType;
import org.finos.legend.connection.protocol.ConnectionSpecification;
@@ -30,7 +31,7 @@
import java.sql.Statement;
import java.util.Properties;
-import static org.junit.Assume.assumeTrue;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
public class TestPostgresConnection
{
@@ -48,7 +49,7 @@ public void setup()
}
catch (Exception e)
{
- assumeTrue("Can't start PostgreSQLContainer", false);
+ assumeTrue(false, "Can't start PostgreSQLContainer");
}
}
@@ -77,11 +78,11 @@ public StoreInstance getStoreInstance()
this.postgresContainer.getPort(),
this.postgresContainer.getDatabaseName()
);
- return new StoreInstance.Builder(this.environmentConfiguration)
+ return new StoreInstance.Builder(this.environment)
.withIdentifier(TEST_STORE_INSTANCE_NAME)
.withStoreSupportIdentifier("Postgres")
- .withAuthenticationMechanisms(
- AuthenticationMechanismType.USER_PASSWORD
+ .withAuthenticationMechanismConfigurations(
+ new AuthenticationMechanismConfiguration.Builder(AuthenticationMechanismType.USER_PASSWORD).build()
)
.withConnectionSpecification(connectionSpecification)
.build();
diff --git a/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/TestSnowflakeConnection.java b/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/TestSnowflakeConnection.java
index 2d522ff96d8..825725a5eea 100644
--- a/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/TestSnowflakeConnection.java
+++ b/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/TestSnowflakeConnection.java
@@ -16,6 +16,7 @@
import org.finos.legend.authentication.vault.CredentialVault;
import org.finos.legend.authentication.vault.impl.PropertiesFileCredentialVault;
+import org.finos.legend.connection.AuthenticationMechanismConfiguration;
import org.finos.legend.connection.StoreInstance;
import org.finos.legend.connection.impl.EncryptedPrivateKeyPairAuthenticationConfiguration;
import org.finos.legend.connection.protocol.AuthenticationConfiguration;
@@ -29,14 +30,14 @@
import java.sql.Statement;
import java.util.Properties;
-import static org.junit.Assume.assumeTrue;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
public class TestSnowflakeConnection
{
public static class WithKeyPair extends AbstractConnectionFactoryTest
{
- private static final String TEST_SNOWFLAKE_PK = "TEST_SNOWFLAKE_PK";
- private static final String TEST_SNOWFLAKE_PK_PASSPHRASE = "TEST_SNOWFLAKE_PK_PASSPHRASE";
+ private static final String CONNECTION_INTEGRATION_TEST__SNOWFLAKE_PK = "CONNECTION_INTEGRATION_TEST__SNOWFLAKE_PK";
+ private static final String CONNECTION_INTEGRATION_TEST__SNOWFLAKE_PK_PASSPHRASE = "CONNECTION_INTEGRATION_TEST__SNOWFLAKE_PK_PASSPHRASE";
private String snowflakePrivateKey;
private String snowflakePassPhrase;
@@ -45,12 +46,12 @@ public void setup()
{
try
{
- this.snowflakePrivateKey = this.environmentConfiguration.lookupVaultSecret(new EnvironmentCredentialVaultSecret(TEST_SNOWFLAKE_PK), null);
- this.snowflakePassPhrase = this.environmentConfiguration.lookupVaultSecret(new EnvironmentCredentialVaultSecret(TEST_SNOWFLAKE_PK_PASSPHRASE), null);
+ this.snowflakePrivateKey = this.environment.lookupVaultSecret(new EnvironmentCredentialVaultSecret(CONNECTION_INTEGRATION_TEST__SNOWFLAKE_PK), null);
+ this.snowflakePassPhrase = this.environment.lookupVaultSecret(new EnvironmentCredentialVaultSecret(CONNECTION_INTEGRATION_TEST__SNOWFLAKE_PK_PASSPHRASE), null);
}
catch (Exception e)
{
- assumeTrue("Can't retrieve Snowflake test instance key-pair info (TEST_SNOWFLAKE_PK, TEST_SNOWFLAKE_PK_PASSPHRASE)", false);
+ assumeTrue(false, String.format("Can't retrieve Snowflake connection key-pair info (%s, %s environment variables are expected)", CONNECTION_INTEGRATION_TEST__SNOWFLAKE_PK, CONNECTION_INTEGRATION_TEST__SNOWFLAKE_PK_PASSPHRASE));
}
}
@@ -79,11 +80,11 @@ public StoreInstance getStoreInstance()
connectionSpecification.region = "us-east-2";
connectionSpecification.cloudType = "aws";
connectionSpecification.role = "SUMMIT_DEV";
- return new StoreInstance.Builder(this.environmentConfiguration)
+ return new StoreInstance.Builder(this.environment)
.withIdentifier(TEST_STORE_INSTANCE_NAME)
.withStoreSupportIdentifier("Snowflake")
- .withAuthenticationMechanisms(
- AuthenticationMechanismType.KEY_PAIR
+ .withAuthenticationMechanismConfigurations(
+ new AuthenticationMechanismConfiguration.Builder(AuthenticationMechanismType.KEY_PAIR).build()
)
.withConnectionSpecification(connectionSpecification)
.build();
diff --git a/legend-engine-config/legend-engine-extensions-collection-execution/pom.xml b/legend-engine-config/legend-engine-extensions-collection-execution/pom.xml
index c5718331ea0..7ae5876854c 100644
--- a/legend-engine-config/legend-engine-extensions-collection-execution/pom.xml
+++ b/legend-engine-config/legend-engine-extensions-collection-execution/pom.xml
@@ -19,7 +19,7 @@
legend-engine-config
org.finos.legend.engine
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
diff --git a/legend-engine-config/legend-engine-extensions-collection-generation/pom.xml b/legend-engine-config/legend-engine-extensions-collection-generation/pom.xml
index 7d0531e7440..62e94574827 100644
--- a/legend-engine-config/legend-engine-extensions-collection-generation/pom.xml
+++ b/legend-engine-config/legend-engine-extensions-collection-generation/pom.xml
@@ -19,7 +19,7 @@
legend-engine-config
org.finos.legend.engine
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
@@ -295,6 +295,11 @@
legend-engine-xt-relationalStore-sybaseiq-pure
runtime
+
+ org.finos.legend.engine
+ legend-engine-xt-relationalStore-sparksql-pure
+ runtime
+
org.finos.legend.engine
legend-engine-xt-relationalStore-javaPlatformBinding-pure
diff --git a/legend-engine-config/legend-engine-extensions-collection-generation/src/test/java/org/finos/legend/engine/extensions/collection/generation/TestExtensions.java b/legend-engine-config/legend-engine-extensions-collection-generation/src/test/java/org/finos/legend/engine/extensions/collection/generation/TestExtensions.java
index 5ae46944c3d..da2039c880d 100644
--- a/legend-engine-config/legend-engine-extensions-collection-generation/src/test/java/org/finos/legend/engine/extensions/collection/generation/TestExtensions.java
+++ b/legend-engine-config/legend-engine-extensions-collection-generation/src/test/java/org/finos/legend/engine/extensions/collection/generation/TestExtensions.java
@@ -509,6 +509,7 @@ protected Iterable getExpectedCodeRepositories()
.with("core_relational_presto")
.with("core_relational_sybase")
.with("core_relational_sybaseiq")
+ .with("core_relational_sparksql")
.with("core_relational_store_entitlement")
.with("core_servicestore")
.with("core_authentication")
diff --git a/legend-engine-config/legend-engine-pure-code-compiled-core-configuration/pom.xml b/legend-engine-config/legend-engine-pure-code-compiled-core-configuration/pom.xml
index 3bb342ccfdf..558bd130fdc 100644
--- a/legend-engine-config/legend-engine-pure-code-compiled-core-configuration/pom.xml
+++ b/legend-engine-config/legend-engine-pure-code-compiled-core-configuration/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-config
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
diff --git a/legend-engine-config/legend-engine-server-integration-tests/pom.xml b/legend-engine-config/legend-engine-server-integration-tests/pom.xml
index 1f9f12ce1e4..6de9ae3c274 100644
--- a/legend-engine-config/legend-engine-server-integration-tests/pom.xml
+++ b/legend-engine-config/legend-engine-server-integration-tests/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-config
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-server-integration-tests
diff --git a/legend-engine-config/legend-engine-server-support-core/pom.xml b/legend-engine-config/legend-engine-server-support-core/pom.xml
index f159071b85f..c1e3b6084a8 100644
--- a/legend-engine-config/legend-engine-server-support-core/pom.xml
+++ b/legend-engine-config/legend-engine-server-support-core/pom.xml
@@ -3,7 +3,7 @@
legend-engine-config
org.finos.legend.engine
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
diff --git a/legend-engine-config/legend-engine-server/pom.xml b/legend-engine-config/legend-engine-server/pom.xml
index f1a088aa20b..02789e87e86 100644
--- a/legend-engine-config/legend-engine-server/pom.xml
+++ b/legend-engine-config/legend-engine-server/pom.xml
@@ -19,14 +19,12 @@
org.finos.legend.engine
legend-engine-config
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-server
Legend Engine - Server
-
-
jar
@@ -134,6 +132,11 @@
legend-engine-xt-relationalStore-sybaseiq-pure
runtime
+
+ org.finos.legend.engine
+ legend-engine-xt-relationalStore-sparksql-pure
+ runtime
+
org.finos.legend.engine
legend-engine-language-pure-grammar-api
@@ -669,6 +672,23 @@
+
+ org.finos.legend.engine
+ legend-engine-xt-authentication-connection-factory
+
+
+ org.finos.legend.engine
+ legend-engine-xt-relationalStore-connection
+
+
+ org.finos.legend.engine
+ legend-engine-xt-relationalStore-postgres-connection
+ runtime
+
+
+ org.finos.legend.engine
+ legend-engine-xt-relationalStore-snowflake-connection
+
diff --git a/legend-engine-config/legend-engine-server/src/main/java/org/finos/legend/engine/server/Server.java b/legend-engine-config/legend-engine-server/src/main/java/org/finos/legend/engine/server/Server.java
index 60fa1a7cfdc..ad248e0062b 100644
--- a/legend-engine-config/legend-engine-server/src/main/java/org/finos/legend/engine/server/Server.java
+++ b/legend-engine-config/legend-engine-server/src/main/java/org/finos/legend/engine/server/Server.java
@@ -39,7 +39,25 @@
import org.finos.legend.authentication.intermediationrule.IntermediationRule;
import org.finos.legend.authentication.intermediationrule.impl.EncryptedPrivateKeyFromVaultRule;
import org.finos.legend.authentication.vault.CredentialVaultProvider;
+import org.finos.legend.authentication.vault.impl.EnvironmentCredentialVault;
import org.finos.legend.authentication.vault.impl.PropertiesFileCredentialVault;
+import org.finos.legend.authentication.vault.impl.SystemPropertiesCredentialVault;
+import org.finos.legend.connection.AuthenticationMechanismConfiguration;
+import org.finos.legend.connection.ConnectionFactory;
+import org.finos.legend.connection.DatabaseType;
+import org.finos.legend.connection.LegendEnvironment;
+import org.finos.legend.connection.RelationalDatabaseStoreSupport;
+import org.finos.legend.connection.StoreInstanceProvider;
+import org.finos.legend.connection.impl.DefaultStoreInstanceProvider;
+import org.finos.legend.connection.impl.EncryptedPrivateKeyPairAuthenticationConfiguration;
+import org.finos.legend.connection.impl.HACKY__SnowflakeConnectionAdapter;
+import org.finos.legend.connection.impl.KerberosCredentialExtractor;
+import org.finos.legend.connection.impl.KeyPairCredentialBuilder;
+import org.finos.legend.connection.impl.SnowflakeConnectionBuilder;
+import org.finos.legend.connection.impl.StaticJDBCConnectionBuilder;
+import org.finos.legend.connection.impl.UserPasswordAuthenticationConfiguration;
+import org.finos.legend.connection.impl.UserPasswordCredentialBuilder;
+import org.finos.legend.connection.protocol.AuthenticationMechanismType;
import org.finos.legend.engine.api.analytics.DataSpaceAnalytics;
import org.finos.legend.engine.api.analytics.DiagramAnalytics;
import org.finos.legend.engine.api.analytics.LineageAnalytics;
@@ -67,13 +85,13 @@
import org.finos.legend.engine.language.pure.grammar.api.grammarToJson.TransformGrammarToJson;
import org.finos.legend.engine.language.pure.grammar.api.jsonToGrammar.JsonToGrammar;
import org.finos.legend.engine.language.pure.grammar.api.jsonToGrammar.TransformJsonToGrammar;
-import org.finos.legend.engine.language.pure.relational.api.relationalElement.RelationalElementAPI;
import org.finos.legend.engine.language.pure.grammar.api.relationalOperationElement.RelationalOperationElementGrammarToJson;
import org.finos.legend.engine.language.pure.grammar.api.relationalOperationElement.RelationalOperationElementJsonToGrammar;
import org.finos.legend.engine.language.pure.grammar.api.relationalOperationElement.TransformRelationalOperationElementGrammarToJson;
import org.finos.legend.engine.language.pure.grammar.api.relationalOperationElement.TransformRelationalOperationElementJsonToGrammar;
import org.finos.legend.engine.language.pure.modelManager.ModelManager;
import org.finos.legend.engine.language.pure.modelManager.sdlc.SDLCLoader;
+import org.finos.legend.engine.language.pure.relational.api.relationalElement.RelationalElementAPI;
import org.finos.legend.engine.plan.execution.PlanExecutor;
import org.finos.legend.engine.plan.execution.api.ExecutePlanLegacy;
import org.finos.legend.engine.plan.execution.api.ExecutePlanStrategic;
@@ -100,8 +118,8 @@
import org.finos.legend.engine.protocol.hostedService.metamodel.HostedServiceDeploymentConfiguration;
import org.finos.legend.engine.protocol.pure.v1.PureProtocolObjectMapperFactory;
import org.finos.legend.engine.protocol.pure.v1.model.PureProtocol;
-import org.finos.legend.engine.pure.code.core.PureCoreExtensionLoader;
import org.finos.legend.engine.protocol.snowflakeApp.metamodel.SnowflakeDeploymentConfiguration;
+import org.finos.legend.engine.pure.code.core.PureCoreExtensionLoader;
import org.finos.legend.engine.query.graphQL.api.debug.GraphQLDebug;
import org.finos.legend.engine.query.graphQL.api.execute.GraphQLExecute;
import org.finos.legend.engine.query.graphQL.api.grammar.GraphQLGrammar;
@@ -157,7 +175,7 @@ public class Server extends Application
public static void main(String[] args) throws Exception
{
EngineUrlStreamHandlerFactory.initialize();
- new Server().run(args.length == 0 ? new String[] {"server", "legend-engine-config/legend-engine-server/src/test/resources/org/finos/legend/engine/server/test/userTestConfig.json"} : args);
+ new Server().run(args.length == 0 ? new String[]{"server", "legend-engine-config/legend-engine-server/src/test/resources/org/finos/legend/engine/server/test/userTestConfig.json"} : args);
}
@Override
@@ -261,6 +279,10 @@ public void run(T serverConfiguration, Environment environment)
relationalExecution.setFlowProviderClass(LegendDefaultDatabaseAuthenticationFlowProvider.class);
relationalExecution.setFlowProviderConfiguration(new LegendDefaultDatabaseAuthenticationFlowProviderConfiguration());
}
+ relationalExecution.setConnectionFactory(this.setupConnectionFactory(serverConfiguration.vaults));
+ relationalExecution.setRelationalDatabaseConnectionAdapters(Lists.mutable.of(
+ new HACKY__SnowflakeConnectionAdapter.WithKeyPair()
+ ));
relationalStoreExecutor = (RelationalStoreExecutor) Relational.build(serverConfiguration.relationalexecution);
@@ -349,7 +371,7 @@ public void run(T serverConfiguration, Environment environment)
environment.jersey().register(new ExecutePlanLegacy(planExecutor));
// Function Activator
- environment.jersey().register(new FunctionActivatorAPI(modelManager, serverConfiguration.activatorConfiguration, routerExtensions));
+ environment.jersey().register(new FunctionActivatorAPI(modelManager, Lists.mutable.empty(), routerExtensions));
// GraphQL
environment.jersey().register(new GraphQLGrammar());
@@ -391,6 +413,48 @@ public void run(T serverConfiguration, Environment environment)
enableCors(environment);
}
+ // TODO: @akphi - this is temporary, rework when we find a better way to handle the initialization of connection factory from config or some external source.
+ private ConnectionFactory setupConnectionFactory(List vaultConfigurations)
+ {
+ LegendEnvironment environment = new LegendEnvironment.Builder()
+ .withVaults(
+ new SystemPropertiesCredentialVault(),
+ new EnvironmentCredentialVault(),
+ new PropertiesFileCredentialVault(this.buildVaultProperties(vaultConfigurations))
+ )
+ .withStoreSupports(
+ new RelationalDatabaseStoreSupport.Builder(DatabaseType.POSTGRES)
+ .withIdentifier("Postgres")
+ .withAuthenticationMechanismConfigurations(
+ new AuthenticationMechanismConfiguration.Builder(AuthenticationMechanismType.USER_PASSWORD).withAuthenticationConfigurationTypes(
+ UserPasswordAuthenticationConfiguration.class
+ ).build()
+ )
+ .build(),
+ new RelationalDatabaseStoreSupport.Builder(DatabaseType.SNOWFLAKE)
+ .withIdentifier("Snowflake")
+ .withAuthenticationMechanismConfigurations(
+ new AuthenticationMechanismConfiguration.Builder(AuthenticationMechanismType.KEY_PAIR).withAuthenticationConfigurationTypes(
+ EncryptedPrivateKeyPairAuthenticationConfiguration.class
+ ).build()
+ )
+ .build()
+ ).build();
+
+ StoreInstanceProvider storeInstanceProvider = new DefaultStoreInstanceProvider.Builder().build();
+ return new ConnectionFactory.Builder(environment, storeInstanceProvider)
+ .withCredentialBuilders(
+ new KerberosCredentialExtractor(),
+ new UserPasswordCredentialBuilder(),
+ new KeyPairCredentialBuilder()
+ )
+ .withConnectionBuilders(
+ new StaticJDBCConnectionBuilder.WithPlaintextUsernamePassword(),
+ new SnowflakeConnectionBuilder.WithKeyPair()
+ )
+ .build();
+ }
+
private void loadVaults(List vaultConfigurations)
{
if (vaultConfigurations != null)
diff --git a/legend-engine-config/legend-engine-server/src/test/resources/org/finos/legend/engine/server/test/userTestConfig.json b/legend-engine-config/legend-engine-server/src/test/resources/org/finos/legend/engine/server/test/userTestConfig.json
index acd17396d0d..8106f02d379 100644
--- a/legend-engine-config/legend-engine-server/src/test/resources/org/finos/legend/engine/server/test/userTestConfig.json
+++ b/legend-engine-config/legend-engine-server/src/test/resources/org/finos/legend/engine/server/test/userTestConfig.json
@@ -80,12 +80,5 @@
},
"errorhandlingconfiguration": {
"enabled": true
- },
- "activatorConfiguration":[
- {"_type":"hostedServiceConfig", "host": "127.0.0.1",
- "port":9090,
- "path": "/api/service/v1/registerHostedService",
- "stage": "SANDBOX"
- }
- ]
-}
\ No newline at end of file
+ }
+}
diff --git a/legend-engine-config/pom.xml b/legend-engine-config/pom.xml
index 14faa9b8896..8bc10e8ab9a 100644
--- a/legend-engine-config/pom.xml
+++ b/legend-engine-config/pom.xml
@@ -18,7 +18,7 @@
org.finos.legend.engine
legend-engine
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
diff --git a/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-dependencies/pom.xml b/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-dependencies/pom.xml
index eace5c1cbd8..e3c2d9be4e5 100644
--- a/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-dependencies/pom.xml
+++ b/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-dependencies/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-executionPlan-execution
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-executionPlan-dependencies
diff --git a/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-execution-api/pom.xml b/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-execution-api/pom.xml
index 289088d20c7..97a581c99cd 100644
--- a/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-execution-api/pom.xml
+++ b/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-execution-api/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-executionPlan-execution
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-executionPlan-execution-api
diff --git a/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-execution-authorizer/pom.xml b/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-execution-authorizer/pom.xml
index 31f83d41dc9..67188fdcbcb 100644
--- a/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-execution-authorizer/pom.xml
+++ b/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-execution-authorizer/pom.xml
@@ -3,7 +3,7 @@
legend-engine-core-executionPlan-execution
org.finos.legend.engine
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
diff --git a/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-execution-store-inMemory/pom.xml b/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-execution-store-inMemory/pom.xml
index 4696a11dc8c..65c758f45a1 100644
--- a/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-execution-store-inMemory/pom.xml
+++ b/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-execution-store-inMemory/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-executionPlan-execution
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-executionPlan-execution-store-inMemory
diff --git a/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-execution/pom.xml b/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-execution/pom.xml
index d089f5fb53d..49018781741 100644
--- a/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-execution/pom.xml
+++ b/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-execution/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-executionPlan-execution
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-executionPlan-execution
diff --git a/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-external-shared-format-runtime/pom.xml b/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-external-shared-format-runtime/pom.xml
index 62b63333d3d..c34283b87bf 100644
--- a/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-external-shared-format-runtime/pom.xml
+++ b/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-external-shared-format-runtime/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-executionPlan-execution
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
diff --git a/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-external-shared-format-runtime/src/main/java/org/finos/legend/engine/external/shared/runtime/write/ExternalFormatSerializeResult.java b/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-external-shared-format-runtime/src/main/java/org/finos/legend/engine/external/shared/runtime/write/ExternalFormatSerializeResult.java
index 1c41eec625f..ff0c13475c8 100644
--- a/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-external-shared-format-runtime/src/main/java/org/finos/legend/engine/external/shared/runtime/write/ExternalFormatSerializeResult.java
+++ b/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-external-shared-format-runtime/src/main/java/org/finos/legend/engine/external/shared/runtime/write/ExternalFormatSerializeResult.java
@@ -14,6 +14,9 @@
package org.finos.legend.engine.external.shared.runtime.write;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import org.eclipse.collections.impl.factory.Lists;
import org.finos.legend.engine.plan.execution.result.Result;
import org.finos.legend.engine.plan.execution.result.ResultVisitor;
@@ -52,6 +55,21 @@ public Serializer getSerializer(SerializationFormat format)
return new ExternalFormatDefaultSerializer(externalFormatWriter, this);
}
+ @Override
+ public String flush(Serializer serializer)
+ {
+ try
+ {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ externalFormatWriter.writeDataAsString(bos);
+ return bos.toString(StandardCharsets.UTF_8.name());
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
@Override
public void close()
{
diff --git a/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-external-shared-format-runtime/src/main/java/org/finos/legend/engine/external/shared/runtime/write/ExternalFormatWriter.java b/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-external-shared-format-runtime/src/main/java/org/finos/legend/engine/external/shared/runtime/write/ExternalFormatWriter.java
index aa2742dceb1..77a0d4d9556 100644
--- a/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-external-shared-format-runtime/src/main/java/org/finos/legend/engine/external/shared/runtime/write/ExternalFormatWriter.java
+++ b/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-external-shared-format-runtime/src/main/java/org/finos/legend/engine/external/shared/runtime/write/ExternalFormatWriter.java
@@ -20,4 +20,10 @@
public abstract class ExternalFormatWriter
{
public abstract void writeData(OutputStream stream) throws IOException;
+
+ public void writeDataAsString(OutputStream outputStream) throws IOException
+ {
+ writeData(outputStream);
+ }
+
}
diff --git a/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-external-shared-format-runtime/src/test/java/org/finos/legend/engine/external/shared/runtime/fixtures/firmModel/Firm.java b/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-external-shared-format-runtime/src/test/java/org/finos/legend/engine/external/shared/runtime/fixtures/firmModel/Firm.java
index de291c706f2..87ee15e38b1 100644
--- a/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-external-shared-format-runtime/src/test/java/org/finos/legend/engine/external/shared/runtime/fixtures/firmModel/Firm.java
+++ b/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-external-shared-format-runtime/src/test/java/org/finos/legend/engine/external/shared/runtime/fixtures/firmModel/Firm.java
@@ -53,8 +53,12 @@ public String getPureClassName()
private List addresses;
+ private int addressesSize;
+
private List employees;
+ private int employeesSize;
+
public String getName()
{
return this.nameSize == 0 ? null : this.name;
@@ -95,6 +99,7 @@ public void _addressesAdd(AddressUse value)
this.addresses = new ArrayList();
}
this.addresses.add(value);
+ this.addressesSize++;
}
public List getEmployees()
@@ -109,6 +114,7 @@ void _employeesAddImpl(Person value)
this.employees = new ArrayList();
}
this.employees.add(value);
+ this.employeesSize++;
}
public void _employeesAdd(Person value)
@@ -128,10 +134,6 @@ public List checkMultiplicities()
{
defects.add(BasicDefect.newClassStructureDefect("Invalid multiplicity for ranking: expected [0..1] found [" + this.rankingSize + "]", "meta::external::format::shared::testpack::simple::Firm"));
}
- if (this.addresses.size() < 1L)
- {
- defects.add(BasicDefect.newClassStructureDefect("Invalid multiplicity for addresses: expected [1..*] found [" + this.addresses.size() + "]", "meta::external::format::shared::testpack::simple::Firm"));
- }
return defects;
}
diff --git a/legend-engine-core/legend-engine-core-executionPlan-execution/pom.xml b/legend-engine-core/legend-engine-core-executionPlan-execution/pom.xml
index fcc3ae58002..5fdf54971e3 100644
--- a/legend-engine-core/legend-engine-core-executionPlan-execution/pom.xml
+++ b/legend-engine-core/legend-engine-core-executionPlan-execution/pom.xml
@@ -18,7 +18,7 @@
org.finos.legend.engine
legend-engine-core
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
diff --git a/legend-engine-core/legend-engine-core-executionPlan-generation/legend-engine-executionPlan-generation/pom.xml b/legend-engine-core/legend-engine-core-executionPlan-generation/legend-engine-executionPlan-generation/pom.xml
index 0a4dfb27845..0c73f22f72f 100644
--- a/legend-engine-core/legend-engine-core-executionPlan-generation/legend-engine-executionPlan-generation/pom.xml
+++ b/legend-engine-core/legend-engine-core-executionPlan-generation/legend-engine-executionPlan-generation/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-executionPlan-generation
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
diff --git a/legend-engine-core/legend-engine-core-executionPlan-generation/pom.xml b/legend-engine-core/legend-engine-core-executionPlan-generation/pom.xml
index 28c44758958..9ce432c6c7e 100644
--- a/legend-engine-core/legend-engine-core-executionPlan-generation/pom.xml
+++ b/legend-engine-core/legend-engine-core-executionPlan-generation/pom.xml
@@ -18,7 +18,7 @@
org.finos.legend.engine
legend-engine-core
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
diff --git a/legend-engine-core/legend-engine-core-language-pure/legend-engine-external-shared-format-model/pom.xml b/legend-engine-core/legend-engine-core-language-pure/legend-engine-external-shared-format-model/pom.xml
index e2a0b970c41..e10ac455a12 100644
--- a/legend-engine-core/legend-engine-core-language-pure/legend-engine-external-shared-format-model/pom.xml
+++ b/legend-engine-core/legend-engine-core-language-pure/legend-engine-external-shared-format-model/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-language-pure
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
diff --git a/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-compiler-api/pom.xml b/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-compiler-api/pom.xml
index 0280a519bdd..56bfa71742d 100644
--- a/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-compiler-api/pom.xml
+++ b/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-compiler-api/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-language-pure
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-language-pure-compiler-api
diff --git a/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-compiler/pom.xml b/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-compiler/pom.xml
index d481a687937..89f2bbf1130 100644
--- a/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-compiler/pom.xml
+++ b/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-compiler/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-language-pure
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-language-pure-compiler
diff --git a/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-compiler/src/main/java/org/finos/legend/engine/language/pure/compiler/toPureGraph/Milestoning.java b/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-compiler/src/main/java/org/finos/legend/engine/language/pure/compiler/toPureGraph/Milestoning.java
index 7a03d75c02e..a397fb44af4 100644
--- a/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-compiler/src/main/java/org/finos/legend/engine/language/pure/compiler/toPureGraph/Milestoning.java
+++ b/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-compiler/src/main/java/org/finos/legend/engine/language/pure/compiler/toPureGraph/Milestoning.java
@@ -289,8 +289,19 @@ private static QualifiedProperty> newSingleDateMilestoningQualifiedPropertyNoA
._rawType(context.pureModel.getType("meta::pure::metamodel::function::property::QualifiedProperty"))
._typeArguments(Lists.fixedSize.of(PureModel.buildFunctionType(Lists.mutable.of(thisVar), qualifiedProperty._genericType(), originalProperty._multiplicity(), context.pureModel)));
+ SimpleFunctionExpression finalExpression = filterExpression;
+ if (originalProperty._multiplicity() == context.pureModel.getMultiplicity("one"))
+ {
+ finalExpression = new Root_meta_pure_metamodel_valuespecification_SimpleFunctionExpression_Impl("", null, context.pureModel.getClass("meta::pure::metamodel::valuespecification::SimpleFunctionExpression"))
+ ._func(context.pureModel.getFunction("meta::pure::functions::multiplicity::toOne_T_MANY__T_1_", true))
+ ._functionName("toOne")
+ ._genericType(qualifiedProperty._genericType())
+ ._multiplicity(context.pureModel.getMultiplicity("one"))
+ ._parametersValues(Lists.fixedSize.of(filterExpression));
+ }
+
qualifiedProperty._classifierGenericType(classifierGenericType);
- qualifiedProperty._expressionSequence(Lists.fixedSize.of(filterExpression));
+ qualifiedProperty._expressionSequence(Lists.fixedSize.of(finalExpression));
return qualifiedProperty;
}
@@ -357,12 +368,23 @@ private static MutableList> newSingleDateMilestoningQualifi
._multiplicity(context.pureModel.getMultiplicity("zeromany"))
._parametersValues(Lists.fixedSize.of(filterLhs, filterInstanceValue));
+ SimpleFunctionExpression finalExpression = filterExpression;
+ if (originalProperty._multiplicity() == context.pureModel.getMultiplicity("one"))
+ {
+ finalExpression = new Root_meta_pure_metamodel_valuespecification_SimpleFunctionExpression_Impl("", null, context.pureModel.getClass("meta::pure::metamodel::valuespecification::SimpleFunctionExpression"))
+ ._func(context.pureModel.getFunction("meta::pure::functions::multiplicity::toOne_T_MANY__T_1_", true))
+ ._functionName("toOne")
+ ._genericType(qualifiedProperty._genericType())
+ ._multiplicity(context.pureModel.getMultiplicity("one"))
+ ._parametersValues(Lists.fixedSize.of(filterExpression));
+ }
+
GenericType classifierGenericType = new Root_meta_pure_metamodel_type_generics_GenericType_Impl("", null, context.pureModel.getClass("meta::pure::metamodel::type::generics::GenericType"))
._rawType(context.pureModel.getType("meta::pure::metamodel::function::property::QualifiedProperty"))
._typeArguments(Lists.fixedSize.of(PureModel.buildFunctionType(Lists.mutable.of(thisVar).withAll(datesToCompare.collect(Functions.firstOfPair())), qualifiedProperty._genericType(), originalProperty._multiplicity(), context.pureModel)));
qualifiedProperty._classifierGenericType(classifierGenericType);
- qualifiedProperty._expressionSequence(Lists.fixedSize.of(filterExpression));
+ qualifiedProperty._expressionSequence(Lists.fixedSize.of(finalExpression));
return Lists.mutable.of(qualifiedProperty);
}
diff --git a/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-compiler/src/main/java/org/finos/legend/engine/language/pure/compiler/toPureGraph/handlers/Handlers.java b/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-compiler/src/main/java/org/finos/legend/engine/language/pure/compiler/toPureGraph/handlers/Handlers.java
index ca961cb9c47..4b65ee3aa26 100644
--- a/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-compiler/src/main/java/org/finos/legend/engine/language/pure/compiler/toPureGraph/handlers/Handlers.java
+++ b/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-compiler/src/main/java/org/finos/legend/engine/language/pure/compiler/toPureGraph/handlers/Handlers.java
@@ -913,6 +913,7 @@ private void registerStrings()
register("meta::pure::functions::string::replace_String_1__String_1__String_1__String_1_", true, ps -> res("String", "one"));
register("meta::pure::functions::string::reverseString_String_1__String_1_", true, ps -> res("String", "one"));
register("meta::pure::functions::string::split_String_1__String_1__String_MANY_", true, ps -> res("String", "zeroMany"));
+ register("meta::pure::functions::string::splitPart_String_$0_1$__String_1__Integer_1__String_$0_1$_", false, ps -> res("String", "zeroOne"));
register(m(m(h("meta::pure::functions::string::substring_String_1__Integer_1__Integer_1__String_1_", true, ps -> res("String", "one"), ps -> ps.size() == 3)),
m(h("meta::pure::functions::string::substring_String_1__Integer_1__String_1_", true, ps -> res("String", "one"), ps -> true))));
register("meta::pure::functions::string::toLower_String_1__String_1_", true, ps -> res("String", "one"));
@@ -2040,6 +2041,7 @@ private Map buildDispatch()
map.put("meta::pure::functions::string::reverseString_String_1__String_1_", (List ps) -> ps.size() == 1 && isOne(ps.get(0)._multiplicity()) && ("Nil".equals(ps.get(0)._genericType()._rawType()._name()) || "String".equals(ps.get(0)._genericType()._rawType()._name())));
map.put("meta::pure::functions::string::splitOnCamelCase_String_1__String_MANY_", (List ps) -> ps.size() == 1 && isOne(ps.get(0)._multiplicity()) && ("Nil".equals(ps.get(0)._genericType()._rawType()._name()) || "String".equals(ps.get(0)._genericType()._rawType()._name())));
map.put("meta::pure::functions::string::split_String_1__String_1__String_MANY_", (List ps) -> ps.size() == 2 && isOne(ps.get(0)._multiplicity()) && ("Nil".equals(ps.get(0)._genericType()._rawType()._name()) || "String".equals(ps.get(0)._genericType()._rawType()._name())) && isOne(ps.get(1)._multiplicity()) && ("Nil".equals(ps.get(1)._genericType()._rawType()._name()) || "String".equals(ps.get(1)._genericType()._rawType()._name())));
+ map.put("meta::pure::functions::string::splitPart_String_$0_1$__String_1__Integer_1__String_$0_1$_", (List ps) -> ps.size() == 3 && matchZeroOne(ps.get(0)._multiplicity()) && ("Nil".equals(ps.get(0)._genericType()._rawType()._name()) || "String".equals(ps.get(0)._genericType()._rawType()._name())) && isOne(ps.get(1)._multiplicity()) && ("Nil".equals(ps.get(1)._genericType()._rawType()._name()) || "String".equals(ps.get(1)._genericType()._rawType()._name())) && isOne(ps.get(2)._multiplicity()) && ("Nil".equals(ps.get(2)._genericType()._rawType()._name()) || "Integer".equals(ps.get(2)._genericType()._rawType()._name())));
map.put("meta::pure::functions::string::startsWith_String_$0_1$__String_1__Boolean_1_", (List ps) -> ps.size() == 2 && matchZeroOne(ps.get(0)._multiplicity()) && ("Nil".equals(ps.get(0)._genericType()._rawType()._name()) || "String".equals(ps.get(0)._genericType()._rawType()._name())) && isOne(ps.get(1)._multiplicity()) && ("Nil".equals(ps.get(1)._genericType()._rawType()._name()) || "String".equals(ps.get(1)._genericType()._rawType()._name())));
map.put("meta::pure::functions::string::startsWith_String_1__String_1__Boolean_1_", (List ps) -> ps.size() == 2 && isOne(ps.get(0)._multiplicity()) && ("Nil".equals(ps.get(0)._genericType()._rawType()._name()) || "String".equals(ps.get(0)._genericType()._rawType()._name())) && isOne(ps.get(1)._multiplicity()) && ("Nil".equals(ps.get(1)._genericType()._rawType()._name()) || "String".equals(ps.get(1)._genericType()._rawType()._name())));
map.put("meta::pure::functions::string::substringAfter_String_1__String_1__String_1_", (List ps) -> ps.size() == 2 && isOne(ps.get(0)._multiplicity()) && ("Nil".equals(ps.get(0)._genericType()._rawType()._name()) || "String".equals(ps.get(0)._genericType()._rawType()._name())) && isOne(ps.get(1)._multiplicity()) && ("Nil".equals(ps.get(1)._genericType()._rawType()._name()) || "String".equals(ps.get(1)._genericType()._rawType()._name())));
diff --git a/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-compiler/src/test/java/org/finos/legend/engine/language/pure/compiler/test/fromGrammar/TestDomainCompilationFromGrammar.java b/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-compiler/src/test/java/org/finos/legend/engine/language/pure/compiler/test/fromGrammar/TestDomainCompilationFromGrammar.java
index dc855abb8e5..86a18fe9604 100644
--- a/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-compiler/src/test/java/org/finos/legend/engine/language/pure/compiler/test/fromGrammar/TestDomainCompilationFromGrammar.java
+++ b/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-compiler/src/test/java/org/finos/legend/engine/language/pure/compiler/test/fromGrammar/TestDomainCompilationFromGrammar.java
@@ -2295,6 +2295,66 @@ public void testMilestoningSimplePropertiesInNonMilestonedClassesAreNotRestricte
Assert.assertTrue(biTemporalAddressProperties.allSatisfy(p -> Lists.immutable.with("processingDate", "processingDateComplex", "businessDate", "businessDateComplex").contains(p.getName())));
}
+ @Test
+ public void testMilestoningPropertiesQualfiedExpressionForToOne()
+ {
+ String grammar = "###Pure\n" +
+ "Class <> test::ProcessingTemporalAddress\n" +
+ "{\n" +
+ " DunmmyProperty : String[1];\n" +
+ "}\n" +
+ "\n" +
+ "Class <> test::BusinessTemporalAddress\n" +
+ "{\n" +
+ " DunmmyProperty : String[1];\n" +
+ "}\n" +
+ "\n" +
+ "Class <> test::BiTemporalAddress\n" +
+ "{\n" +
+ " DunmmyProperty : String[1];\n" +
+ "}\n" +
+ "\n" +
+ "Class test::Person\n" +
+ "{\n" +
+ " processingTemporalAddress1 : test::ProcessingTemporalAddress[1];\n" +
+ " businessTemporalAddress1 : test::BusinessTemporalAddress[1];\n" +
+ " biTemporalAddress1 : test::BiTemporalAddress[1];\n" +
+ " processingTemporalAddress2 : test::ProcessingTemporalAddress[0..1];\n" +
+ " businessTemporalAddress2 : test::BusinessTemporalAddress[0..1];\n" +
+ " biTemporalAddress2 : test::BiTemporalAddress[0..1];\n" +
+ " processingTemporalAddress3 : test::ProcessingTemporalAddress[*];\n" +
+ " businessTemporalAddress3 : test::BusinessTemporalAddress[*];\n" +
+ " biTemporalAddress3 : test::BiTemporalAddress[*];\n" +
+ "}";
+ PureModel pm = test(grammar).getTwo();
+
+ RichIterable extends QualifiedProperty>> personQualifiedProperties = pm.getClass("test::Person")._qualifiedProperties();
+ boolean checkQualifiedExpressionForprocessingTemporalAddress1 = checkQualifiedExpressionForToOneAsTopLevelFunctionExpression(personQualifiedProperties.detect(p -> p.getName().equals("processingTemporalAddress1")));
+ boolean checkQualifiedExpressionForbusinessTemporalAddress1 = checkQualifiedExpressionForToOneAsTopLevelFunctionExpression(personQualifiedProperties.detect(p -> p.getName().equals("businessTemporalAddress1")));
+ boolean checkQualifiedExpressionForbiTemporalAddress1 = checkQualifiedExpressionForToOneAsTopLevelFunctionExpression(personQualifiedProperties.detect(p -> p.getName().equals("biTemporalAddress1")));
+ boolean checkQualifiedExpressionForprocessingTemporalAddress2 = checkQualifiedExpressionForToOneAsTopLevelFunctionExpression(personQualifiedProperties.detect(p -> p.getName().equals("processingTemporalAddress2")));
+ boolean checkQualifiedExpressionForbusinessTemporalAddress2 = checkQualifiedExpressionForToOneAsTopLevelFunctionExpression(personQualifiedProperties.detect(p -> p.getName().equals("businessTemporalAddress2")));
+ boolean checkQualifiedExpressionForbiTemporalAddress2 = checkQualifiedExpressionForToOneAsTopLevelFunctionExpression(personQualifiedProperties.detect(p -> p.getName().equals("biTemporalAddress2")));
+ boolean checkQualifiedExpressionForprocessingTemporalAddress3 = checkQualifiedExpressionForToOneAsTopLevelFunctionExpression(personQualifiedProperties.detect(p -> p.getName().equals("processingTemporalAddress3")));
+ boolean checkQualifiedExpressionForbusinessTemporalAddress3 = checkQualifiedExpressionForToOneAsTopLevelFunctionExpression(personQualifiedProperties.detect(p -> p.getName().equals("businessTemporalAddress3")));
+ boolean checkQualifiedExpressionForbiTemporalAddress3 = checkQualifiedExpressionForToOneAsTopLevelFunctionExpression(personQualifiedProperties.detect(p -> p.getName().equals("biTemporalAddress3")));
+ Assert.assertTrue("Qualfied expression generated for processingTemporalAddress should have toOne() as topLevel functionExpression", checkQualifiedExpressionForprocessingTemporalAddress1);
+ Assert.assertTrue("Qualfied expression generated for BusinessTemporalAddress should have toOne() as topLevel functionExpression", checkQualifiedExpressionForbusinessTemporalAddress1);
+ Assert.assertTrue("Qualfied expression generated for BiTemporalAddress should have toOne() as topLevel functionExpression", checkQualifiedExpressionForbiTemporalAddress1);
+ Assert.assertTrue("Qualfied expression generated for processingTemporalAddress should not have toOne() as topLevel functionExpression", !checkQualifiedExpressionForprocessingTemporalAddress2);
+ Assert.assertTrue("Qualfied expression generated for BusinessTemporalAddress should not have toOne() as topLevel functionExpression", !checkQualifiedExpressionForbusinessTemporalAddress2);
+ Assert.assertTrue("Qualfied expression generated for BiTemporalAddress should not have toOne() as topLevel functionExpression", !checkQualifiedExpressionForbiTemporalAddress2);
+ Assert.assertTrue("Qualfied expression generated for processingTemporalAddress should not have toOne() as topLevel functionExpression", !checkQualifiedExpressionForprocessingTemporalAddress3);
+ Assert.assertTrue("Qualfied expression generated for BusinessTemporalAddress should not have toOne() as topLevel functionExpression", !checkQualifiedExpressionForbusinessTemporalAddress3);
+ Assert.assertTrue("Qualfied expression generated for BiTemporalAddress should not have toOne() as topLevel functionExpression", !checkQualifiedExpressionForbiTemporalAddress3);
+ }
+
+ private boolean checkQualifiedExpressionForToOneAsTopLevelFunctionExpression(QualifiedProperty generatedMilestoningClassQualifiedProperty)
+ {
+ FunctionExpression topLevelExpression = ((FunctionExpression) generatedMilestoningClassQualifiedProperty._expressionSequence().getFirst());
+ return topLevelExpression._func()._functionName().equals("toOne");
+ }
+
@Test
public void testMilestoningSimplePropertiesAreNotOverridenByUserProperties()
{
@@ -2353,13 +2413,22 @@ public void testMilestoningSimplePropertiesAreNotOverridenByUserProperties()
private boolean generatedMilestoningQualifgiedPropertyUsesGeneratedMilestoningProperty(Property generatedMilestoningClassSimpleProperty, QualifiedProperty generatedMilestoningClassQualifiedProperty)
{
- FunctionExpression topLevelExpression = (FunctionExpression) ((LambdaFunction) ((InstanceValue) ((FunctionExpression) generatedMilestoningClassQualifiedProperty._expressionSequence().getFirst())._parametersValues().toList().get(1))._values().getOnly())._expressionSequence().getOnly();
- if (topLevelExpression._func()._functionName().equals("and"))
+ FunctionExpression topLevelExpression = ((FunctionExpression) generatedMilestoningClassQualifiedProperty._expressionSequence().getFirst());
+ FunctionExpression simplifiedExpression;
+ if (topLevelExpression._func()._functionName().equals("toOne"))
+ {
+ simplifiedExpression = (FunctionExpression) ((LambdaFunction) ((InstanceValue) ((FunctionExpression) (topLevelExpression._parametersValues().toList().get(0)))._parametersValues().toList().get(1))._values().getOnly())._expressionSequence().getOnly();
+ }
+ else
+ {
+ simplifiedExpression = (FunctionExpression) ((LambdaFunction) ((InstanceValue) topLevelExpression._parametersValues().toList().get(1))._values().getOnly())._expressionSequence().getOnly();
+ }
+ if (simplifiedExpression._func()._functionName().equals("and"))
{
int idx = generatedMilestoningClassSimpleProperty.getName().equals("processingDate") ? 0 : 1;
- topLevelExpression = (FunctionExpression) topLevelExpression._parametersValues().toList().get(idx);
+ simplifiedExpression = (FunctionExpression) simplifiedExpression._parametersValues().toList().get(idx);
}
- Property filterMilestoningDateProperty = (Property) ((FunctionExpression) topLevelExpression._parametersValues().toList().get(0))._func();
+ Property filterMilestoningDateProperty = (Property) ((FunctionExpression) simplifiedExpression._parametersValues().toList().get(0))._func();
return generatedMilestoningClassSimpleProperty.equals(filterMilestoningDateProperty);
}
diff --git a/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-grammar-api/pom.xml b/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-grammar-api/pom.xml
index 66917c3dd0f..1a7b491da29 100644
--- a/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-grammar-api/pom.xml
+++ b/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-grammar-api/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-language-pure
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-language-pure-grammar-api
diff --git a/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-grammar/pom.xml b/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-grammar/pom.xml
index e086f318371..973cef500c9 100644
--- a/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-grammar/pom.xml
+++ b/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-grammar/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-language-pure
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-language-pure-grammar
diff --git a/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-modelManager-sdlc/pom.xml b/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-modelManager-sdlc/pom.xml
index a8331ce3dca..71bb9445572 100644
--- a/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-modelManager-sdlc/pom.xml
+++ b/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-modelManager-sdlc/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-language-pure
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-language-pure-modelManager-sdlc
diff --git a/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-modelManager/pom.xml b/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-modelManager/pom.xml
index cb100c63dbb..be2fc6469e2 100644
--- a/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-modelManager/pom.xml
+++ b/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-modelManager/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-language-pure
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-language-pure-modelManager
diff --git a/legend-engine-core/legend-engine-core-language-pure/legend-engine-protocol-api/pom.xml b/legend-engine-core/legend-engine-core-language-pure/legend-engine-protocol-api/pom.xml
index cd1308df5be..41ee6422e0c 100644
--- a/legend-engine-core/legend-engine-core-language-pure/legend-engine-protocol-api/pom.xml
+++ b/legend-engine-core/legend-engine-core-language-pure/legend-engine-protocol-api/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-language-pure
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-protocol-api
diff --git a/legend-engine-core/legend-engine-core-language-pure/legend-engine-protocol-generation-pure/pom.xml b/legend-engine-core/legend-engine-core-language-pure/legend-engine-protocol-generation-pure/pom.xml
index 8f3724d88f5..366fed6b963 100644
--- a/legend-engine-core/legend-engine-core-language-pure/legend-engine-protocol-generation-pure/pom.xml
+++ b/legend-engine-core/legend-engine-core-language-pure/legend-engine-protocol-generation-pure/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-language-pure
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-protocol-generation-pure
diff --git a/legend-engine-core/legend-engine-core-language-pure/legend-engine-protocol-generation/pom.xml b/legend-engine-core/legend-engine-core-language-pure/legend-engine-protocol-generation/pom.xml
index 41e0e0a9a99..823790e4a7a 100644
--- a/legend-engine-core/legend-engine-core-language-pure/legend-engine-protocol-generation/pom.xml
+++ b/legend-engine-core/legend-engine-core-language-pure/legend-engine-protocol-generation/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-language-pure
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-protocol-generation
diff --git a/legend-engine-core/legend-engine-core-language-pure/legend-engine-protocol-pure/pom.xml b/legend-engine-core/legend-engine-core-language-pure/legend-engine-protocol-pure/pom.xml
index c2de39358a9..934ff2bfd97 100644
--- a/legend-engine-core/legend-engine-core-language-pure/legend-engine-protocol-pure/pom.xml
+++ b/legend-engine-core/legend-engine-core-language-pure/legend-engine-protocol-pure/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-language-pure
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-protocol-pure
diff --git a/legend-engine-core/legend-engine-core-language-pure/legend-engine-protocol/pom.xml b/legend-engine-core/legend-engine-core-language-pure/legend-engine-protocol/pom.xml
index 665296998e4..f63fd2764a6 100644
--- a/legend-engine-core/legend-engine-core-language-pure/legend-engine-protocol/pom.xml
+++ b/legend-engine-core/legend-engine-core-language-pure/legend-engine-protocol/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-language-pure
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-protocol
diff --git a/legend-engine-core/legend-engine-core-language-pure/pom.xml b/legend-engine-core/legend-engine-core-language-pure/pom.xml
index 4a20dce6c5c..970dbd37fe8 100644
--- a/legend-engine-core/legend-engine-core-language-pure/pom.xml
+++ b/legend-engine-core/legend-engine-core-language-pure/pom.xml
@@ -18,7 +18,7 @@
org.finos.legend.engine
legend-engine-core
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
diff --git a/legend-engine-core/legend-engine-core-query-pure/legend-engine-query-pure/pom.xml b/legend-engine-core/legend-engine-core-query-pure/legend-engine-query-pure/pom.xml
index 361b5f3ed17..e55e7b0532b 100644
--- a/legend-engine-core/legend-engine-core-query-pure/legend-engine-query-pure/pom.xml
+++ b/legend-engine-core/legend-engine-core-query-pure/legend-engine-query-pure/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-query-pure
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-query-pure
diff --git a/legend-engine-core/legend-engine-core-query-pure/pom.xml b/legend-engine-core/legend-engine-core-query-pure/pom.xml
index d871a339550..10be27ceb23 100644
--- a/legend-engine-core/legend-engine-core-query-pure/pom.xml
+++ b/legend-engine-core/legend-engine-core-query-pure/pom.xml
@@ -18,7 +18,7 @@
org.finos.legend.engine
legend-engine-core
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
diff --git a/legend-engine-core/legend-engine-core-shared/legend-engine-shared-core/pom.xml b/legend-engine-core/legend-engine-core-shared/legend-engine-shared-core/pom.xml
index 1f59eba5072..15d8c371a6e 100644
--- a/legend-engine-core/legend-engine-core-shared/legend-engine-shared-core/pom.xml
+++ b/legend-engine-core/legend-engine-core-shared/legend-engine-shared-core/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-shared
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-shared-core
diff --git a/legend-engine-core/legend-engine-core-shared/legend-engine-shared-javaCompiler/pom.xml b/legend-engine-core/legend-engine-core-shared/legend-engine-shared-javaCompiler/pom.xml
index d3322c19d8c..c6a67446138 100644
--- a/legend-engine-core/legend-engine-core-shared/legend-engine-shared-javaCompiler/pom.xml
+++ b/legend-engine-core/legend-engine-core-shared/legend-engine-shared-javaCompiler/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-shared
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-shared-javaCompiler
diff --git a/legend-engine-core/legend-engine-core-shared/pom.xml b/legend-engine-core/legend-engine-core-shared/pom.xml
index c027315e943..235b224f155 100644
--- a/legend-engine-core/legend-engine-core-shared/pom.xml
+++ b/legend-engine-core/legend-engine-core-shared/pom.xml
@@ -18,7 +18,7 @@
org.finos.legend.engine
legend-engine-core
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
diff --git a/legend-engine-core/legend-engine-core-test/legend-engine-test-data-generation/pom.xml b/legend-engine-core/legend-engine-core-test/legend-engine-test-data-generation/pom.xml
index 9217dfcf3df..99a284088ed 100644
--- a/legend-engine-core/legend-engine-core-test/legend-engine-test-data-generation/pom.xml
+++ b/legend-engine-core/legend-engine-core-test/legend-engine-test-data-generation/pom.xml
@@ -3,7 +3,7 @@
org.finos.legend.engine
legend-engine-core-test
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
diff --git a/legend-engine-core/legend-engine-core-test/legend-engine-test-runner-mapping/pom.xml b/legend-engine-core/legend-engine-core-test/legend-engine-test-runner-mapping/pom.xml
index 4b46db9c1b0..ef911453207 100644
--- a/legend-engine-core/legend-engine-core-test/legend-engine-test-runner-mapping/pom.xml
+++ b/legend-engine-core/legend-engine-core-test/legend-engine-test-runner-mapping/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-test
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
diff --git a/legend-engine-core/legend-engine-core-test/legend-engine-test-runner-shared/pom.xml b/legend-engine-core/legend-engine-core-test/legend-engine-test-runner-shared/pom.xml
index eda15403a64..05c819f64a9 100644
--- a/legend-engine-core/legend-engine-core-test/legend-engine-test-runner-shared/pom.xml
+++ b/legend-engine-core/legend-engine-core-test/legend-engine-test-runner-shared/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-test
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-test-runner-shared
diff --git a/legend-engine-core/legend-engine-core-test/legend-engine-test-server-shared/pom.xml b/legend-engine-core/legend-engine-core-test/legend-engine-test-server-shared/pom.xml
index 8eb6a0982af..512449b9849 100644
--- a/legend-engine-core/legend-engine-core-test/legend-engine-test-server-shared/pom.xml
+++ b/legend-engine-core/legend-engine-core-test/legend-engine-test-server-shared/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-test
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-test-server-shared
diff --git a/legend-engine-core/legend-engine-core-test/legend-engine-testable/pom.xml b/legend-engine-core/legend-engine-core-test/legend-engine-testable/pom.xml
index 7fb35544c79..9a034b49bcc 100644
--- a/legend-engine-core/legend-engine-core-test/legend-engine-testable/pom.xml
+++ b/legend-engine-core/legend-engine-core-test/legend-engine-testable/pom.xml
@@ -19,7 +19,7 @@
org.finos.legend.engine
legend-engine-core-test
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
legend-engine-testable
diff --git a/legend-engine-core/legend-engine-core-test/legend-engine-testable/src/main/java/org/finos/legend/engine/testable/assertion/TestAssertionEvaluator.java b/legend-engine-core/legend-engine-core-test/legend-engine-testable/src/main/java/org/finos/legend/engine/testable/assertion/TestAssertionEvaluator.java
index 8738cf297a2..83b7daa2e1d 100644
--- a/legend-engine-core/legend-engine-core-test/legend-engine-testable/src/main/java/org/finos/legend/engine/testable/assertion/TestAssertionEvaluator.java
+++ b/legend-engine-core/legend-engine-core-test/legend-engine-testable/src/main/java/org/finos/legend/engine/testable/assertion/TestAssertionEvaluator.java
@@ -48,13 +48,23 @@ public AssertionStatus visit(TestAssertion testAssertion)
{
if (testAssertion instanceof EqualTo)
{
- if (!(result instanceof ConstantResult))
+
+ Object actual;
+ Object expected = ((EqualTo) testAssertion).expected.accept(new PrimitiveValueSpecificationToObjectVisitor());;
+ if (result instanceof ConstantResult)
+ {
+ actual = ((ConstantResult) result).getValue();
+ }
+ else if (result instanceof StreamingResult)
+ {
+ actual = ((StreamingResult) result).flush(((StreamingResult) result).getSerializer(this.serializationFormat));
+ }
+
+ else
{
throw new UnsupportedOperationException("Result type - " + result.getClass().getSimpleName() + " not supported with EqualTo Assert !!");
}
- Object expected = ((EqualTo) testAssertion).expected.accept(new PrimitiveValueSpecificationToObjectVisitor());
- Object actual = ((ConstantResult) result).getValue();
AssertionStatus assertionStatus;
if (expected.equals(actual))
diff --git a/legend-engine-core/legend-engine-core-test/pom.xml b/legend-engine-core/legend-engine-core-test/pom.xml
index 6ff6e63d86e..9d9af090890 100644
--- a/legend-engine-core/legend-engine-core-test/pom.xml
+++ b/legend-engine-core/legend-engine-core-test/pom.xml
@@ -18,7 +18,7 @@
org.finos.legend.engine
legend-engine-core
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
diff --git a/legend-engine-core/pom.xml b/legend-engine-core/pom.xml
index ed0f8c97ee0..5d32e53982a 100644
--- a/legend-engine-core/pom.xml
+++ b/legend-engine-core/pom.xml
@@ -18,7 +18,7 @@
org.finos.legend.engine
legend-engine
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
4.0.0
diff --git a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/pom.xml b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/pom.xml
index dfcf4e7eb36..c1878c5dbc9 100644
--- a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/pom.xml
+++ b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/pom.xml
@@ -22,7 +22,7 @@
org.finos.legend.engine
legend-engine-pure-code
- 4.30.1-SNAPSHOT
+ 4.30.3-SNAPSHOT
legend-engine-pure-code-compiled-core
diff --git a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/legend/test/handlersTest.pure b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/legend/test/handlersTest.pure
index 2c6f06c0352..48d8a454c6e 100644
--- a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/legend/test/handlersTest.pure
+++ b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/legend/test/handlersTest.pure
@@ -382,6 +382,7 @@ Class meta::legend::test::handlers::model::TestString
replace(){$this.string->replace($this.string, $this.string)}:String[1];
reverseString(){$this.string->reverseString()}:String[1];
split(){$this.string->split($this.string)}:String[*];
+ splitPart(){$this.string->splitPart($this.string, 0)}:String[*];
rtrim(){$this.string->rtrim()}:String[1];
substringTwo(){$this.string->substring(1,2)}:String[1];
substring(){$this.string->substring(1)}:String[1];
diff --git a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/corefunctions/stringExtension.pure b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/corefunctions/stringExtension.pure
index c1e9bc5da32..2ec81292d02 100644
--- a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/corefunctions/stringExtension.pure
+++ b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/corefunctions/stringExtension.pure
@@ -167,6 +167,14 @@ function {doc.doc = 'Un-camel case / humanize the provided string using provided
->joinStrings(' ');
}
+function {doc.doc = 'Split the string and select the part'}
+ meta::pure::functions::string::splitPart(str:String[0..1], token:String[1], part:Integer[1]):String[0..1]
+{
+ if ($str->isEmpty(),
+ | [],
+ | $str->toOne()->split($token)->at($part));
+}
+
function {doc.doc = 'Split the proivded string on camel case'}
meta::pure::functions::string::splitOnCamelCase(str:String[1]):String[*]
{
diff --git a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/corefunctions/tests/stringExtension.pure b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/corefunctions/tests/stringExtension.pure
index ac993d65cf9..92134809154 100644
--- a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/corefunctions/tests/stringExtension.pure
+++ b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/corefunctions/tests/stringExtension.pure
@@ -110,6 +110,14 @@ function <> {test.excludePlatform = 'Java compiled'} meta::pure::func
assertEquals('abab', repeatString('ab', 2));
}
+function <> meta::pure::functions::string::tests::testSplitPart():Boolean[1]
+{
+ assertEquals([], splitPart([], 'a', 1));
+ assertEquals('abc', splitPart('abc', 'd', 0));
+ assertEquals('a', splitPart('abc', 'b', 0));
+ assertEquals('c', splitPart('abc', 'b', 1));
+}
+
function <> meta::pure::functions::string::tests::testSplitOnCamelCase():Boolean[1]
{
let pairs = [
diff --git a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/protocol/vX_X_X/transfers/valueSpecification.pure b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/protocol/vX_X_X/transfers/valueSpecification.pure
index be571b393fa..b62703c5df5 100644
--- a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/protocol/vX_X_X/transfers/valueSpecification.pure
+++ b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/protocol/vX_X_X/transfers/valueSpecification.pure
@@ -693,7 +693,8 @@ function meta::protocols::pure::vX_X_X::transformation::fromPureGraph::toPureGra
->concatenate([
pair(meta::pure::mapping::from_TabularDataSet_1__Mapping_1__Runtime_1__TabularDataSet_1_.name->toOne(), meta::pure::mapping::from_TabularDataSet_1__Mapping_1__Runtime_1__TabularDataSet_1_),
pair(meta::pure::mapping::from_TabularDataSet_1__Mapping_1__Runtime_1__ExecutionContext_1__TabularDataSet_1_.name->toOne(), meta::pure::mapping::from_TabularDataSet_1__Mapping_1__Runtime_1__ExecutionContext_1__TabularDataSet_1_),
- pair(meta::pure::runtime::currentUserId__String_1_.name->toOne(), meta::pure::runtime::currentUserId__String_1_)
+ pair(meta::pure::runtime::currentUserId__String_1_.name->toOne(), meta::pure::runtime::currentUserId__String_1_),
+ pair(meta::pure::functions::hash::hash_String_1__HashType_1__String_1_.name->toOne(), meta::pure::functions::hash::hash_String_1__HashType_1__String_1_)
])
->removeDuplicatesBy(p | $p.second)
->newMultiValueMap();
diff --git a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/preeval/preeval.pure b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/preeval/preeval.pure
index 0b3a399c4f4..c132f44d392 100644
--- a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/preeval/preeval.pure
+++ b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/preeval/preeval.pure
@@ -1,1090 +1,1092 @@
-// Copyright 2023 Goldman Sachs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-import meta::pure::router::preeval::*;
-import meta::pure::extension::*;
-import meta::pure::metamodel::path::*;
-import meta::pure::router::extension::*;
-import meta::pure::router::utils::*;
-
-Class meta::pure::router::preeval::State
-{
- inScopeVars : Map>[1];
- rollingInScopeVars : Map>[1];
- inScopeTypeParams : Map[1];
-
- debug : DebugContext[1];
- depth : Integer[0..1];
- path : FunctionDefinition[*];
-
- shouldInlineFxn : FunctionDefinition<{Function[1] -> Boolean[1]}>[1];
- stopPreeval : Function<{Any[1] -> Boolean[1]}>[1];
-
- toString() { $this->simpleToString() }:String[1];
-}
-
-Class meta::pure::router::preeval::PrevalWrapper
-{
- canPreval : Boolean[1];
- value : T[1];
- openVars : String[*];
- modified : Boolean[1];
-
- toString() { $this->simpleToString() }:String[1];
-}
-
-
-// ====================================================================================================================================================================
-// Public Apis
-// ====================================================================================================================================================================
-
-function <> meta::pure::router::preeval::preval(f:FunctionDefinition[1], extensions:Extension[*]):FunctionDefinition[1]
-{
- preval($f, $extensions, noDebug());
-}
-
-function <> meta::pure::router::preeval::preval(f:FunctionDefinition[1], extensions:Extension[*], debug:DebugContext[1]):FunctionDefinition[1]
-{
- preval($f, newMap([]->cast(@Pair)), $f->openVariableValues(), $extensions, $debug).value->toOne()->cast($f);
-}
-
-function <> meta::pure::router::preeval::preval(f : FunctionDefinition[1], vars:Map[1], inScopeVars:Map>[1], extensions:Extension[*]):PrevalWrapper>[1]
-{
- preval($f, $vars, $inScopeVars, $extensions, noDebug());
-}
-
-function <> meta::pure::router::preeval::preval(f : FunctionDefinition[1], vars:Map[1], inScopeVars:Map>[1], extensions:Extension[*], debug:DebugContext[1]):PrevalWrapper>[1]
-{
- let state = ^meta::pure::router::preeval::State(inScopeVars = $inScopeVars,
- shouldInlineFxn = defaultFunctionInlineStrategy($extensions),
- stopPreeval = defaultPreevalStopStrategy($extensions),
- rollingInScopeVars = $inScopeVars,
- debug = $debug,
- inScopeTypeParams = ^Map());
- preval($f, $state, $extensions);
-}
-
-function <> meta::pure::router::preeval::preval(f : FunctionDefinition[1], state:State[1], extensions:Extension[*]):PrevalWrapper>[1]
-{
- let r = prevalInternal($f->evaluateAndDeactivate(), $state, $extensions)->toOne()->cast(@PrevalWrapper>);
-
- if(!$r->anyModified(),
- |
- $state->printDebug(|'No changes made for: ');
- $state->printDebug(|$f->meta::protocols::pure::vX_X_X::transformation::fromPureGraph::valueSpecification::transformFunctionBody($extensions)->meta::protocols::pure::vX_X_X::transformation::fromPureGraph::toPureGrammar::toPure($extensions));,
- |
- let res = $r.value->toOne();
-
- // $state->printDebug('Transformed From:');
- // $state->printDebug(|$f->meta::protocols::pure::vX_X_X::transformation::fromPureGraph::valueSpecification::transformFunctionBody($extensions)->meta::json::toJSON(50000));
- // $state->printDebug(|$f->meta::protocols::pure::vX_X_X::transformation::fromPureGraph::valueSpecification::transformFunctionBody($extensions)->meta::protocols::pure::vX_X_X::transformation::toPureGrammar::toPure($extensions));
-
- $state->printDebug('Transformed To:');
- $state->printDebug(|$res->meta::protocols::pure::vX_X_X::transformation::fromPureGraph::valueSpecification::transformFunctionBody($extensions)->meta::json::toJSON(50000));
- $state->printDebug(|$res->meta::protocols::pure::vX_X_X::transformation::fromPureGraph::valueSpecification::transformFunctionBody($extensions)->meta::protocols::pure::vX_X_X::transformation::fromPureGraph::toPureGrammar::toPure($extensions));
-
- $state->printDebug($res);
- );
-
- $r;
-}
-
-function <> meta::pure::router::preeval::preval(f : FunctionExpression[1], inScopeVars:Map>[1], extensions:Extension[*], debug:DebugContext[1]):ValueSpecification[1]
-{
- let state = ^meta::pure::router::preeval::State(inScopeVars = $inScopeVars,
- shouldInlineFxn = defaultFunctionInlineStrategy($extensions),
- stopPreeval = defaultPreevalStopStrategy($extensions),
- rollingInScopeVars = $inScopeVars,
- debug = $debug,
- inScopeTypeParams = ^Map());
- prevalInternal($f, $state, $extensions).value->cast(@ValueSpecification);
-}
-
-// ====================================================================================================================================================================
-// Processor Functions
-// ====================================================================================================================================================================
-
-function <> meta::pure::router::preeval::prevalInternal(item : Any[1], origState : meta::pure::router::preeval::State[1], extensions:Extension[*]):PrevalWrapper[1]
-{
- let state = ^$origState(depth = if($origState.depth->isEmpty(), | 0, | $origState.depth->toOne() + 1),
- path = if(!$item->instanceOf(FunctionDefinition), | $origState.path, | $origState.path->concatenate($item->cast(@FunctionDefinition))));
-
-
- $state->printDebugWithDepth(|'Processing ' + $item->type()->makeString() + ' '
- + $item->evaluateAndDeactivate()
- ->match([
- iv:InstanceValue[1] | $iv.values->map(x|$x->type())->makeString(),
- sfe:SimpleFunctionExpression[1] | '(' + $sfe.func->elementToPath() + ')',
- ve:VariableExpression[1] | '(' + $ve.name + ')',
- a:Any[*]|'']
- )
- + ', inScopeVars: ' + $state.inScopeVars->keys()->joinStrings('[', ',', ']'));
-
- let newItem = $item->evaluateAndDeactivate()
- ->match([
- {lambda : LambdaFunction[1]|
- let fnArgNames = $lambda->functionType().parameters.name;
- let fnOpenVariables = $lambda->openVariableValues()->putAll($state.inScopeVars->keyValues()->filter(kv | !$kv.first->in($fnArgNames))->newMap());
-
- $lambda->prevalFunctionDefinition(^$state(inScopeVars = $fnOpenVariables), $extensions);
- },
- {fd : FunctionDefinition[1]|
- $fd->prevalFunctionDefinition(^$state(inScopeVars = newMap([])), $extensions); // Assigning empty map to inScopeVars as function definition can't have openVars
- },
- {sfe : SimpleFunctionExpression[1]|
- let handlers = [
- // Avoid handling known 'false' case (which may not be evalulatable / have runtime issues, e.g. a toOne() after an isNotEmpty condition)
- ^Pair, LambdaFunction<{->PrevalWrapper[1]}>>(first = if_Boolean_1__Function_1__Function_1__T_m_, second = {|
- let conditionPreVal = $sfe.parametersValues->at(0)->prevalInternal($state, $extensions);
- if($conditionPreVal.value->toOne()->cast(@ValueSpecification)->isInstanceValue($state.inScopeVars),
- | let valueValueSpecification = if($conditionPreVal.value->cast(@InstanceValue).values == true,
- | $sfe.parametersValues->at(1),
- | $sfe.parametersValues->at(2)
- );
- let newSfe = ^$sfe(func = eval_Function_1__V_m_, parametersValues = $valueValueSpecification);
-
- $newSfe->prevalInternal($state, $extensions)->markModified();,
- | prevalGenericSimpleFunctionExpression($sfe, $state, $extensions);
- );
- }),
-
- // Avoid handling conditions after the first false (which may not be evalulatable / have runtime issues, e.g. a toOne() after an isNotEmpty condition)
- ^Pair, LambdaFunction<{->PrevalWrapper[1]}>>(first = meta::pure::functions::boolean::and_Boolean_1__Boolean_1__Boolean_1_, second = {|
- prevalBooleanSimpleFunctionExpression($sfe, $state, $extensions);
- }),
-
- // Avoid handling conditions after the first true (which may not be evalulatable / have runtime issues, e.g. a toOne() after an isEmpty condition)
- ^Pair, LambdaFunction<{->PrevalWrapper[1]}>>(first = meta::pure::functions::boolean::or_Boolean_1__Boolean_1__Boolean_1_, second = {|
- prevalBooleanSimpleFunctionExpression($sfe, $state, $extensions);
- })
-
- // TODO:
- // 1. Optimise and_Boolean_MANY__Boolean_1_ and or_Boolean_$1_MANY$__Boolean_1_
- // 1. Optimise plus(many), minus(many) and times(many) (plus_String_MANY__String_1_, plus_Float_MANY__Float_1_, times_Number_MANY__Number_1_, minus_Float_MANY__Float_1_)
- ];
-
- let handler = $handlers->filter(p|$p.first == $sfe.func).second;
-
- if($handler->isNotEmpty(),
- | $handler->toOne()->eval(),
- | prevalGenericSimpleFunctionExpression($sfe, $state, $extensions));
- },
- {ve : VariableExpression[1]|
- let varValue = $state.inScopeVars->get($ve.name).values;
- let iv = if($state.inScopeVars->get($ve.name)->isEmpty(),
- | ^PrevalWrapper(value = $ve, canPreval = true, modified = false, openVars = [$ve.name]),
- | $varValue->match([
- n : Nil[0]| ^InstanceValue(multiplicity = $ve.multiplicity, genericType = $ve.genericType, values = $varValue)->evaluateAndDeactivate(),
- iv : InstanceValue[1]| $iv,
- ve : VariableExpression[1]| $ve->evaluateAndDeactivate(),
- sfe : SimpleFunctionExpression[1]| $sfe,
- a : meta::pure::tds::AggregateValue[*]| ^InstanceValue(multiplicity = $ve.multiplicity, genericType = $ve.genericType, values = $varValue)->evaluateAndDeactivate(),
- a : meta::pure::functions::collection::AggregateValue[*]| ^InstanceValue(multiplicity = $ve.multiplicity, genericType = $ve.genericType, values = $varValue)->evaluateAndDeactivate(),
- a : meta::pure::tds::BasicColumnSpecification[*]| ^InstanceValue(multiplicity = $ve.multiplicity, genericType = $ve.genericType, values = $varValue)->evaluateAndDeactivate(),
- r : meta::pure::graphFetch::RootGraphFetchTree[1]| ^InstanceValue(multiplicity = $ve.multiplicity, genericType = $ve.genericType, values = $varValue)->evaluateAndDeactivate();,
- b : meta::external::format::shared::binding::Binding[1]| ^InstanceValue(multiplicity = $ve.multiplicity, genericType = $ve.genericType, values = $varValue)->evaluateAndDeactivate();,
- s : meta::pure::store::Store[1]| ^InstanceValue(multiplicity = $ve.multiplicity, genericType = $ve.genericType, values = $varValue)->evaluateAndDeactivate();,
- a : Any[*]| assert($state.stopPreeval->eval($a), | 'Unsupported type: ' + $a->type()->match([pe:PackageableElement[1]|$pe->elementToPath(), t:Type[1]|$t->makeString()]));
- ^InstanceValue(multiplicity = $ve.multiplicity, genericType = $ve.genericType, values = $varValue)->evaluateAndDeactivate();
- ])
- ->map(x|
- let newState = ^$state(inScopeVars = $state.inScopeVars->keyValues()->filter(p|$p.first != $ve.name)->newMap());
- $x->prevalInternal($newState, $extensions);
- )
- ->markModified()
- );
- },
- {iv : InstanceValue[1]|
- let subVals = $iv.values->map(x|$x->prevalInternal($state, $extensions));
- let r = if(!$subVals->anyModified(),
- | pair(false, $iv),
- | let cleanIv = ^$iv(values = $subVals.value->map(x|$x->match([subIv:InstanceValue[1]|if($subIv.values->size() == 1, |$subIv.values, |$subIv), a:Any[*]|$a])));
- let cleanIv2 = ^$cleanIv(genericType = $cleanIv.genericType->resolveGenericType($state).value,
- multiplicity = if($cleanIv.multiplicity == PureOne && $cleanIv.values->isEmpty(),
- | $cleanIv.multiplicity, //This seems to be a quirk of Cast(@ABC)
- | $cleanIv.values->size()->toMultiplicity())
- );
- pair(true, $cleanIv2);
- );
- ^PrevalWrapper(value = $r.second, canPreval = $subVals->canPreval(), openVars = $subVals->openVars($state.inScopeVars), modified = $r.first);
- },
- {k : KeyExpression[1]|
- let e = $k.expression->prevalInternal($state, $extensions)->toOne();
- let ke = if(!$e->anyModified(),
- | pair(false, $k),
- | pair(true, ^$k(expression = $e.value->cast(@ValueSpecification)->toOne())));
-
- ^PrevalWrapper(value = $ke.second, canPreval = $e.canPreval, openVars = $e->openVars($state.inScopeVars), modified = $ke.first);
- },
- {p : ColumnSpecification[1]|
- $p->match([
- bcs : BasicColumnSpecification[1]|
- let f = $bcs.func->evaluateAndDeactivate();
- let newFuncWrapper = prevalInternal($f, ^$state(inScopeTypeParams = ^Map(), inScopeVars = $state.inScopeVars->putAll($f->openVariableValues())), $extensions);
-
- if(!$newFuncWrapper->anyModified(),
- | ^PrevalWrapper(value = $bcs, canPreval = true, modified = false),
- | ^PrevalWrapper(value = ^$bcs(func = $newFuncWrapper.value->cast($f)), canPreval = true, modified = true);
- );,
- o:ColumnSpecification[1] | ^PrevalWrapper(value = $o, canPreval = true, modified = false);
- ]);
-
- },
- {av : meta::pure::tds::AggregateValue[1]|
- let mapFn = $av.mapFn->evaluateAndDeactivate();
- let aggFn = $av.aggregateFn->evaluateAndDeactivate();
-
- let newFuncWrapper_map = prevalInternal($mapFn, $state, $extensions);
- let newFuncWrapper_agg = prevalInternal($aggFn, $state, $extensions);
-
- if(![$newFuncWrapper_map, $newFuncWrapper_agg]->anyModified(),
- | ^PrevalWrapper(value = $av, canPreval = true, modified = false),
- | ^PrevalWrapper(value = ^$av(mapFn = $newFuncWrapper_map.value->cast($mapFn), aggregateFn = $newFuncWrapper_agg.value->cast($aggFn)), canPreval = true, modified = true);
- );
- },
- {av : meta::pure::functions::collection::AggregateValue[1]|
- let mapFn = $av.mapFn->evaluateAndDeactivate();
- let aggFn = $av.aggregateFn->evaluateAndDeactivate();
-
- let newFuncWrapper_map = prevalInternal($mapFn, $state, $extensions);
- let newFuncWrapper_agg = prevalInternal($aggFn, $state, $extensions);
-
- if(![$newFuncWrapper_map, $newFuncWrapper_agg]->anyModified(),
- | ^PrevalWrapper(value = $av, canPreval = true, modified = false),
- | ^PrevalWrapper(value = ^$av(mapFn = $newFuncWrapper_map.value->cast($mapFn), aggregateFn = $newFuncWrapper_agg.value->cast($aggFn)), canPreval = true, modified = true);
- );
- },
- {r: meta::pure::graphFetch::RootGraphFetchTree[1] | ^PrevalWrapper(value = $r, canPreval = true, modified = false);},
- {b: meta::external::format::shared::binding::Binding[1] | ^PrevalWrapper(value = $b, canPreval = true, modified = false);},
- {s: meta::pure::store::Store[1] | ^PrevalWrapper(value = $s, canPreval = true, modified = false);},
- {a : Any[1]|
- assert($state.stopPreeval->eval($a), | 'Unsupported type: ' + $a->type()->match([pe:PackageableElement[1]|$pe->elementToPath(), t:Type[1]|$t->makeString()]));
- ^PrevalWrapper(value = $a, canPreval = true, modified = false);
- }
- ]);
-
- $state->printDebugWithDepth(|'Returning ' + $newItem.value->type()->makeString() + ' ' + $newItem.value->match([iv:InstanceValue[1]|$iv.values->map(x|$x->type())->makeString(), sfe:SimpleFunctionExpression[1]|'(' + $sfe.func->elementToPath() + ')', ve : VariableExpression[1]|'(' + $ve.name + ')', a:Any[*]|'']) + ' ' + $newItem.toString());
- $newItem;
-}
-
-function <> meta::pure::router::preeval::prevalFunctionDefinition(fd : FunctionDefinition[1], origState : meta::pure::router::preeval::State[1], extensions:Extension[*]):PrevalWrapper[1]
-{
- let items = $fd.expressionSequence;
-
- let r = range($items->size())
- ->fold({index, p|
- let item = $items->at($index);
- let state = $p.first;
-
- let isLastExpression = ($index == ($items->size()-1));
-
- if(!$isLastExpression && !$item->isLetFunction(),
- |
- $state->printDebugWithDepth(|'Dropping non-variable assignement non-return statement: ' + $item->type()->makeString() + ' '
- + $item->match([
- iv:InstanceValue[1]|$iv.values->map(x|$x->type())->makeString(),
- sfe:SimpleFunctionExpression[1]|'(' + $sfe.func->elementToPath() + ')',
- ve : VariableExpression[1]|'(' + $ve.name + ')',
- a:Any[*]|''
- ])
- + ', inScopeVars: ' + $state.inScopeVars->keys()->joinStrings('[', ',', ']'));
-
- pair($state, $p.second);,
- |
- let r = $item->prevalInternal($state, $extensions);
-
- let isLetFunctionValueSpecification = $r.value->instanceOf(ValueSpecification) && $r.value->cast(@ValueSpecification)->isLetFunction();
-
- if(!$isLetFunctionValueSpecification,
- | pair($state, list(if($p.second.values->isEmpty(), | $r, | $p.second.values->concatenate($r)))),
- |
- let fe = $r.value->cast(@FunctionExpression);
-
- let varName = $fe.parametersValues->at(0)->reactivate($state.inScopeVars)->cast(@String)->toOne();
- let varValue = $fe.parametersValues->at(1)
- ->match([
- iv:InstanceValue[1]|$iv.values,
- fe:ValueSpecification[1]|$fe
- ]);
-
- $state->printDebugWithDepth(|'adding variable ' + $varName + ' to rolling scope, with value ' + $varValue->makeString());
-
- let shouldInlineVariableExpression = ($varValue->match([v:VariableExpression[1]|true, a: Any[*]|false]))
- || ($r->canPreval() && $r->areAllInScope($state.inScopeVars) && !$varValue->match([v:LambdaFunction[1]|true, a: Any[*]|false]));
-
- let newRollingInScopeVars = $state.rollingInScopeVars->put($varName, list($varValue));
- let newInScopeVars = if(!$shouldInlineVariableExpression,
- | $state.inScopeVars,
- | $state.inScopeVars->put($varName, list($varValue))
- );
- let newState = ^$state(inScopeVars = $newInScopeVars, rollingInScopeVars = $newRollingInScopeVars);
-
- let expValue = if($isLastExpression,
- | ^PrevalWrapper(canPreval = $r.canPreval, modified = true, openVars =$r.openVars, value = $varValue->match([vs:ValueSpecification[1]|$vs, a:Any[*]|^InstanceValue(genericType = $fe.genericType, multiplicity = $a->size()->toMultiplicity(), values = $a)])),
- | if($shouldInlineVariableExpression,
- | [],
- | $r
- )
- );
- if($expValue->isEmpty(),
- | pair($newState, $p.second),
- | pair($newState, list(if($p.second.values->isEmpty(), | $expValue, | $p.second.values->concatenate($expValue))))
- );
- );
- );
- }, [pair($origState, list([]->cast(@PrevalWrapper)))]
- ).second.values;
-
-
- /*
- This should not be necessary, but seems to be required otherwise fold can end up wrapping InstanceValues in InstanceValues,
- which map doesn't seem to
- */
- let newExpressionSequncePrevalWrappers = $r->evaluateAndDeactivate()
- ->match([
- iv:InstanceValue[1]|$iv.values->cast(@PrevalWrapper),
- a:PrevalWrapper[*]|$a
- ]);
-
- let value = if(($newExpressionSequncePrevalWrappers->size() == $items->size()) && !$newExpressionSequncePrevalWrappers->anyModified(),
- | pair(false, $fd),
- | let newFd = ^$fd(expressionSequence = $newExpressionSequncePrevalWrappers.value->cast(@ValueSpecification)->toOneMany())
- ->match([
- lf : LambdaFunction[1]| ^$lf(openVariables = $lf.openVariables->map(v|$v->resolveVariable($origState))
- ->distinct()
- ->intersection($newExpressionSequncePrevalWrappers.openVars->map(v|$v->resolveVariable($origState)))),
- fd2:FunctionDefinition[1]| $fd2
- ]);
- pair(true, $newFd);
- );
-
- ^PrevalWrapper>(
- value = $value.second,
- canPreval = $newExpressionSequncePrevalWrappers->canPreval(),
- openVars = $fd->match([lf : LambdaFunction[1]|$value.second->cast(@LambdaFunction).openVariables, fd:FunctionDefinition[1]|[]]),
- modified = $value.first
- );
-}
-
-function <> meta::pure::router::preeval::prevalBooleanSimpleFunctionExpression(sfe : SimpleFunctionExpression[1], state : meta::pure::router::preeval::State[1], extensions:Extension[*]):PrevalWrapper[1]
-{
- assert($sfe.func->in([and_Boolean_1__Boolean_1__Boolean_1_, or_Boolean_1__Boolean_1__Boolean_1_]));
- assertEquals(2, $sfe.parametersValues->size());
-
- let shortcutVal = !($sfe.func == and_Boolean_1__Boolean_1__Boolean_1_);
-
- let newParam1Wrapper = $sfe.parametersValues->at(0)->prevalInternal($state, $extensions);
-
- if($newParam1Wrapper.value->toOne()->isInstanceValue($state.inScopeVars),
- | if(($newParam1Wrapper.value->cast(@InstanceValue).values == $shortcutVal),
- | $newParam1Wrapper->markModified(),
- | let newParam2Wrapper = $sfe.parametersValues->at(1)->prevalInternal($state, $extensions);
- $newParam2Wrapper->markModified();),
- | let newParam2Wrapper = $sfe.parametersValues->at(1)->prevalInternal($state, $extensions);
-
- if($newParam2Wrapper.value->toOne()->isInstanceValue($state.inScopeVars),
- | if($newParam2Wrapper.value->cast(@InstanceValue).values != $shortcutVal,
- | $newParam1Wrapper->markModified(),
- | $newParam2Wrapper->markModified()),
- | let newParamWrappers = [$newParam1Wrapper, $newParam2Wrapper];
- ^PrevalWrapper(
- value = ^$sfe(parametersValues = $newParamWrappers.value->cast(@ValueSpecification)),
- canPreval = $newParamWrappers->canPreval(),
- openVars = $newParamWrappers->openVars($state.inScopeVars),
- modified = $newParamWrappers->size() != $sfe.parametersValues->size() || $newParamWrappers->anyModified()
- );
- );
- );
-}
-
-function <> meta::pure::router::preeval::prevalGenericSimpleFunctionExpression(sfe : SimpleFunctionExpression[1], state : meta::pure::router::preeval::State[1], extensions:Extension[*]):PrevalWrapper[1]
-{
- let newParamWrappers = if($sfe.parametersValues->isEmpty(),
- | [],
- | $sfe.func->match([p:Property[1]|'this', f:Function[1]|$f->functionType().parameters.name])
- ->zip($sfe.parametersValues)
- ->evaluateAndDeactivate()
- ->map(p| $state->printDebugWithDepth(|'Processing parameter: ' + $p.first);
- let r = $p.second->prevalInternal($state, $extensions);
- $state->printDebugWithDepth(|'Completed processing parameter: ' + $p.first);
- $r;)
- );
- let newSfeModified = $newParamWrappers->anyModified();
-
- let newSfe = if($newSfeModified,
- | ^$sfe(parametersValues = $newParamWrappers.value->cast(@ValueSpecification)
- ->map(pv|^$pv(genericType = $pv.genericType->resolveGenericType($state).value)),
- genericType = $sfe.genericType->resolveGenericType($state).value),
- | $sfe);
-
- let canPrevalFunc = !($newSfe.func->hasStereotype('SideEffectFunction', functionType) || $newSfe.func->hasStereotype('NotImplementedFunction', functionType) || $state.stopPreeval->eval($newSfe));
-
- if(!$canPrevalFunc,
- | $state->printDebugWithDepth(|'Unable to perform preval: ' + $newSfe.func->elementToPath() + ' (' + $newSfe.func->instanceOf(NativeFunction)->makeString() + ')');
-
- ^PrevalWrapper(
- value = $newSfe,
- canPreval = ($canPrevalFunc || ($newSfe.func == letFunction_String_1__T_m__T_m_)) && $newParamWrappers->canPreval(),
- openVars = $newParamWrappers->openVars($state.inScopeVars),
- modified = $newSfeModified
- );,
- | if(shouldInline($newSfe.func, $state),
- |
- $state->printDebugWithDepth(|'Inlining: ' + $newSfe.func->elementToPath());
- assert($newSfe.func->instanceOf(FunctionDefinition) && $newSfe.func->cast(@FunctionDefinition).expressionSequence->size() == 1);
-
- let newState = $newSfe->addToScope($state)->map(s|^$s(path = $state.path->concatenate($newSfe.func->cast(@FunctionDefinition))));
-
- let subSfe1 = $newSfe.func->cast(@FunctionDefinition).expressionSequence->toOne()->evaluateAndDeactivate();
- let subSfe = ^$subSfe1(genericType = $subSfe1.genericType->resolveGenericType($newState).value);
-
- let sPreValWrapper = $subSfe->prevalInternal($newState, $extensions);
-
- $sPreValWrapper->markModified();,
- | if($newSfe->canInlineEvalFunctionExpression(),
- |
- $state->printDebugWithDepth(|'Expanding eval: ' + $newSfe.func->elementToPath());
-
- let func = $newSfe.parametersValues->at(0)->match([
- iv:InstanceValue[1]|$iv.values->toOne(),
- vs:ValueSpecification[*]|$vs
- ])->cast(@FunctionDefinition)->toOne();
-
- let newState = $newSfe->addToScope($state)->addToScope($func, $sfe.resolvedTypeParameters, $sfe.parametersValues->drop(1));
-
- let subSfe1 = $func.expressionSequence->toOne()->evaluateAndDeactivate();
- let subSfe = ^$subSfe1(genericType = $subSfe1.genericType->resolveGenericType($newState).value);
-
- let sPreValWrapper = $subSfe->prevalInternal($newState, $extensions);
- $sPreValWrapper->markModified();,
- |
- let notPrevalReason = if($newSfe.parametersValues->exists(pv|!$pv->isInstanceValue($state.inScopeVars)),
- | 'params are not instance values';,
- | if (!$newParamWrappers->canPreval(),
- | 'params can not preval';,
- | if(!$newParamWrappers->areAllInScope($state.inScopeVars),
- | 'open variables not in scope',
- | if($newSfe.func == meta::pure::functions::lang::cast_Any_m__T_1__T_m_ && $newParamWrappers.value->at(0)->map(x|$x->instanceOf(InstanceValue) && $x->cast(@InstanceValue).values->isEmpty()),
- | 'cast of empty collection',
- | []
- )
- );
- )
- );
- if($notPrevalReason->isNotEmpty(),
- |
- let handlers = []
- ->cast(@PairBoolean[1]}>, Function<{SimpleFunctionExpression[1]->PrevalWrapper[1]}>>)
- ->concatenate([
- pair(
- {theSfe:SimpleFunctionExpression[1]|
- $newSfe.func.name == 'columns'
- && $newSfe.func->instanceOf(AbstractProperty)
- && $newSfe.func->cast(@AbstractProperty).owner == TabularDataSet
- && $newParamWrappers->areAllInScope($state.rollingInScopeVars)
- },
- {theSfe:SimpleFunctionExpression[1]|
- /*
- Simplistically we could just re-activate the expression here as well, however there are some
- TDS functions that are not implemented in the "Pure" implementation and only work in relational
- queries. Therefore we have to specifically redirect to a helper function to resolve the schema
- instead
- */
- let val = meta::pure::tds::schema::resolveSchema($newSfe.parametersValues->toOne(), $state.rollingInScopeVars, $extensions);
-
- let iv = ^InstanceValue(genericType = $newSfe.genericType,multiplicity = $val->size()->toMultiplicity(), values = $val)->evaluateAndDeactivate();
- ^PrevalWrapper(value = $iv, canPreval = true, modified = true);
- }),
- pair(
- {theSfe:SimpleFunctionExpression[1]|$newSfe.func->in([map_T_m__Function_1__V_m_, map_T_$0_1$__Function_1__V_$0_1$_, map_T_MANY__Function_1__V_MANY_]) && $newSfe.parametersValues->forAll(pv|$pv->isInstanceValue($state.inScopeVars))},
- {theSfe:SimpleFunctionExpression[1]|
- // This special handling is required to cover cases where 'fixed'/ InstanceValue inputs are being mapped
- // using a function that can't be pre-evalled (because it has external input), so wouldn't normally be modified.
- // However we can actually just expand the lambda applied to each of the inputs, to elimniate the Map.
-
- $state->printDebugWithDepth(|'Expanding: ' + $newSfe.func->elementToPath());
-
- let inputVals = $newSfe.parametersValues->at(0)->reactivate($state.inScopeVars)
- ->map(v|$v->match([
- vs:ValueSpecification[1]|$vs,
- a:Any[*]| ^InstanceValue(
- genericType = $newSfe.parametersValues->at(0).genericType,
- multiplicity = PureOne,
- values = $v->toOne()
- )->evaluateAndDeactivate()
- ]));
-
- let lambda = $newSfe.parametersValues->at(1)->cast(@InstanceValue).values->toOne()->cast(@FunctionDefinition);
- //TODO: This should really be pre-checked as part of the If condition to get here (so that the assertion never fails)
- assert($lambda->instanceOf(FunctionDefinition) && $lambda->cast(@FunctionDefinition).expressionSequence->size() == 1);
-
- let paramName = $lambda->functionType().parameters->toOne().name;
-
- let resultValWrappers = $inputVals->map(v|
- let newState = $state->addToScope($lambda, [], $v);
-
- let subSfe1 = $lambda.expressionSequence->toOne()->evaluateAndDeactivate();
- let subSfe = ^$subSfe1(genericType = $sfe.genericType->resolveGenericType($newState).value);
-
- $subSfe->prevalInternal($newState, $extensions);
- );
-
- let resultVals = $resultValWrappers.value->map(v|$v->match([iv:InstanceValue[0..1]|$iv->evaluateAndDeactivate().values, a:Any[*]|$a]));
-
- let r = ^InstanceValue(
- genericType = $newSfe.genericType,
- multiplicity = $resultVals->size()->toMultiplicity(),
- values = $resultVals
- )->evaluateAndDeactivate();
-
- ^PrevalWrapper(
- value = $r,
- canPreval = $resultValWrappers->canPreval(),
- openVars = $resultValWrappers->openVars($state.inScopeVars),
- modified = true
- );
- }),
- pair(
- {theSfe:SimpleFunctionExpression[1]|$newSfe.func == fold_T_MANY__Function_1__V_m__V_m_ && $newSfe.parametersValues->forAll(pv|$pv->isInstanceValue($state.inScopeVars))},
- {theSfe:SimpleFunctionExpression[1]|
- // This special handling is required to cover cases where 'fixed'/ InstanceValue inputs are being folded
- // using a function that can't be pre-evalled (because it has external input), so wouldn't normally be modified.
- // However we can actually just repeat apply the lambda applied to each of the inputs, to elimniate the Fold.
- $state->printDebugWithDepth(|'Expanding: ' + $newSfe.func->elementToPath());
-
- let inputVals = $newSfe.parametersValues->at(0)->reactivate($state.inScopeVars)
- ->map(v| $v->match([
- vs:ValueSpecification[1]|$vs,
- a:Any[1]|
- ^InstanceValue(
- genericType = $newSfe.parametersValues->at(0).genericType,
- multiplicity = PureOne,
- values = $v->toOne()
- )
- ]));
-
- let lambda = $newSfe.parametersValues->at(1)->cast(@InstanceValue).values->toOne()->cast(@FunctionDefinition);//->evaluateAndDeactivate();
- //TODO: This should really be pre-checked as part of the If condition to get here (so that the assertion never fails)
- assert($lambda->instanceOf(FunctionDefinition) && $lambda->cast(@FunctionDefinition).expressionSequence->size() == 1);
-
- let intialAccumlatorVal = $newSfe.parametersValues->at(2);
-
- let resultVal = $inputVals->fold({v,a|
- let newState = $state->addToScope($lambda, [], $v->concatenate($a.value->cast(@ValueSpecification))->evaluateAndDeactivate());
-
- let subSfe1 = $lambda.expressionSequence->toOne();
- let subSfe = ^$subSfe1(genericType = $sfe.genericType->resolveGenericType($newState).value);
-
- $subSfe->prevalInternal($newState, $extensions);
- }, $intialAccumlatorVal->prevalInternal($state, $extensions));
-
- $resultVal->markModified();
- }),
- pair(
- {theSfe:SimpleFunctionExpression[1]|
- ($newSfe.func == concatenate_T_MANY__T_MANY__T_MANY_)
- && ($newSfe.parametersValues.multiplicity->forAll(m|$m->in([PureOne, PureZero]) || $m->isMultiplicityConcrete() && $m->hasUpperBound() && $m->hasLowerBound() && ($m.lowerBound.value == $m.upperBound.value)))
- /*
- This last condition should not be needed, but there are circumstances where the inferred type of some lambdas is incorrect.
- So this is guard to avoid trying to pre-optimise in those situations (where in the example below, we'd optimised to the lambda
- simply return $index because accumulator is detected as a PureZero)
-
- let input = {|
- [1,2]->fold({index, accumulator|
- $accumulator->concatenate($index);
- }, [])
- };
-
- let foldLambda = $input->evaluateAndDeactivate().expressionSequence->cast(@SimpleFunctionExpression).parametersValues->at(1)->cast(@InstanceValue).values->cast(@FunctionDefinition)->toOne();
- let foldLambdaAccumulatorParam = $foldLambda->functionType().parameters->at(1);
-
- assertEquals(ZeroMany, $input->functionReturnMultiplicity(), 'Original lambda return multiplicty expected (zero many)');
- assertEquals($foldLambda->functionReturnMultiplicity(), $input->functionReturnMultiplicity(), | 'Fold lambda return multiplicity matches the original function multiplicity');
- //fails
- assertEquals($foldLambda->functionReturnMultiplicity(), $foldLambdaAccumulatorParam.multiplicity, 'Accumulator parameter multiplicity matches the return multiplicty of the fold lambda: %r vs %r', [$foldLambda->functionReturnMultiplicity(), $foldLambdaAccumulatorParam.multiplicity]);
-
- assertEquals(Integer, $input->functionReturnType().rawType, | 'Original lambda return type expected (integer)');
- assertEquals($foldLambda->functionReturnType().rawType, $input->functionReturnType().rawType, | 'Fold lambda matchs original lambda return type');
- //fails
- assertEquals($foldLambda->functionReturnType().rawType, $foldLambdaAccumulatorParam.genericType.rawType, 'Accumulator parameter matches lambda return type: %r vs %r', [$foldLambda->functionReturnType().rawType->toOne(), $foldLambdaAccumulatorParam.genericType.rawType->toOne()]);
-
- */
- && $newParamWrappers->filter(pw|$pw.value->match([v:VariableExpression[1]|$v.multiplicity == PureZero, a:Any[*]|false]))->areAllInScope($state.inScopeVars)
- },
- {theSfe:SimpleFunctionExpression[1]|
- $state->printDebugWithDepth(|'Handling expand: ' + $newSfe.func->elementToPath());
- $state->printDebugWithDepth(|'Parameter multiplicities: ' + $newSfe.parametersValues.multiplicity->map(x|$x->makeString())->joinStrings('[',',',']'));
-
- let r = if($newSfe.parametersValues->at(0).multiplicity == PureZero,
- | $newSfe.parametersValues->at(1);,
- | if($newSfe.parametersValues->at(1).multiplicity == PureZero,
- | $newSfe.parametersValues->at(0);,
- | let parametersValues = $newSfe.parametersValues
- ->map(x|$x->match([iv:InstanceValue[*]| $iv.values;, a:Any[*]| $a]));
-
- ^InstanceValue(
- genericType = $newSfe.genericType->resolveGenericType($state).value,
- multiplicity = $parametersValues->size()->toMultiplicity(),
- values = $parametersValues
- )->evaluateAndDeactivate()
- ->map(x|^$x(values = $parametersValues));
- )
- );
-
- ^PrevalWrapper(
- value = $r,
- canPreval = $newParamWrappers->canPreval(),
- openVars = $newParamWrappers->openVars($state.inScopeVars),
- modified = true
- );
- }),
- pair(
- {theSfe:SimpleFunctionExpression[1]|$newSfe.func == meta::pure::functions::lang::cast_Any_m__T_1__T_m_ && $newParamWrappers.value->at(0)->map(x|$x->instanceOf(InstanceValue) && $x->cast(@InstanceValue).values->isEmpty())},
- {theSfe:SimpleFunctionExpression[1]|
- //This special handling should not be required but []->cast(@MyType) seems to fail in compiled mode
-
- $state->printDebugWithDepth(|'Handling cast of empty collection: ' + $newSfe.func->elementToPath());
-
-
- let r = ^InstanceValue(
- genericType = $newSfe.genericType->resolveGenericType($state).value,
- multiplicity = $newSfe.multiplicity,
- values = []
- )->evaluateAndDeactivate();
-
- ^PrevalWrapper(
- value = $r,
- canPreval = true,
- openVars = [],
- modified = true
- );
- }),
- pair(
- {theSfe:SimpleFunctionExpression[1] |
- //TODO getAll check is only needed as router does not route FunctionDefinition wth constant result.
- isFilterFunctionReturningConstant($theSfe, false) && !isGetAll($theSfe.parametersValues->at(0))},
- {theSfe:SimpleFunctionExpression[1] |
- $state->printDebugWithDepth(|'Handling filter which returns false: ' + $newSfe.func->elementToPath());
-
- let r = ^InstanceValue(
- genericType = ^GenericType(rawType = Nil),
- multiplicity = PureZero
- )->evaluateAndDeactivate();
-
- ^PrevalWrapper(
- value = $r,
- canPreval = true,
- openVars = [],
- modified = true
- );
- }
- ),
- pair(
- {theSfe:SimpleFunctionExpression[1] | isFilterFunctionReturningConstant($theSfe, true)},
- {theSfe:SimpleFunctionExpression[1] |
- $state->printDebugWithDepth(|'Handling filter which returns true: ' + $newSfe.func->elementToPath());
-
- ^PrevalWrapper(
- value = $theSfe.parametersValues->at(0),
- canPreval = true,
- openVars = [],
- modified = true
- );
- }
- ),
- pair(
- {theSfe:SimpleFunctionExpression[1] | ($theSfe.func == toOneMany_T_MANY__T_$1_MANY$_) &&
- $theSfe.parametersValues->match([
- vs:ValueSpecification[1]|$vs.multiplicity->isMultiplicityConcrete() && $vs.multiplicity->hasLowerBound()
- && ($vs.multiplicity->getLowerBound() > 0),
- a:Any[*]|false
- ])},
- {theSfe:SimpleFunctionExpression[1] |
- $state->printDebugWithDepth(|'Handling toOneMany');
-
- $newParamWrappers->toOne()->map(pw|^$pw(modified=true));
- }
- ),
- pair(
- {theSfe:SimpleFunctionExpression[1] | ($theSfe.func == toOne_T_MANY__T_1_) &&
- $theSfe.parametersValues->match([
- vs:VariableExpression[1]|$vs.multiplicity->isMultiplicityConcrete()
- && $vs.multiplicity == PureOne,
- a:Any[*]|false
- ])},
- {theSfe:SimpleFunctionExpression[1] |
- $state->printDebugWithDepth(|'Handling toOne');
-
- $newParamWrappers->toOne()->map(pw|^$pw(modified=true));
- }
- )
- ]);
-
- let handler = $handlers->filter(p|$p.first->eval($newSfe))->first();
-
- if($handler->isNotEmpty(),
- | $handler->toOne().second->eval($newSfe),
- | $state->printDebugWithDepth(|'Not prevalling: ' + $newSfe.func->elementToPath() + ' (' + $notPrevalReason->toOne() + ')');
-
- ^PrevalWrapper(
- value = $newSfe,
- canPreval = $newParamWrappers->canPreval(),
- openVars = $newParamWrappers->openVars($state.inScopeVars),
- modified = $newSfeModified
- );
- );,
- |
- $state->printDebugWithDepth(|'Performing preval: ' + $newSfe.func->elementToPath() + ' (can recativate dynamically: '+ $newSfe->canReactivateDynamically()->makeString() + ')');
-
- let valX = $newSfe->reactivate($state.inScopeVars)->cast(@Any);
-
- let val = $valX->map(x|$x->match([
- {bcs : BasicColumnSpecification[1]| prevalInternal($bcs, ^$state(inScopeTypeParams = ^Map(), inScopeVars = ^Map>()), $extensions).value},
- {av : meta::pure::functions::collection::AggregateValue[1]| prevalInternal($av, ^$state(inScopeTypeParams = ^Map(), inScopeVars = ^Map>()), $extensions).value},
- {av : meta::pure::tds::AggregateValue[1]| prevalInternal($av, ^$state(inScopeTypeParams = ^Map(), inScopeVars = ^Map>()), $extensions).value},
- {a:Any[1]|$a}
- ]));
-
- let iv = $val->match([
- x : InstanceValue[1]| $x,
- a : Any[*]| ^InstanceValue(genericType = $newSfe.genericType,multiplicity = $val->size()->toMultiplicity(), values = $val);
- ])->evaluateAndDeactivate();
- ^PrevalWrapper(value = $iv, canPreval = true, modified = true);
- );
- );
- );
- );
-}
-
-function meta::pure::router::preeval::isGetAll(v:ValueSpecification[0..1]):Boolean[1]
-{
- $v->match([
- s:SimpleFunctionExpression[1] | meta::pure::router::routing::isGetAllFunction($s.func) || $s.parametersValues->first()->isGetAll(),
- a:Any[*] | false;
- ]);
-}
-
-function <> meta::pure::router::preeval::isFilterFunctionReturningConstant(sfe:SimpleFunctionExpression[1], value:Boolean[1]) : Boolean[1]
-{
- let isFilter = $sfe.func == filter_T_MANY__Function_1__T_MANY_;
-
- if ($isFilter,
- |
- let es = $sfe.parametersValues->last()->cast(@InstanceValue).values->cast(@LambdaFunction).expressionSequence->evaluateAndDeactivate();
- $es->last()->toOne()->instanceOf(InstanceValue) && $es->last()->toOne()->cast(@InstanceValue).values == $value;,
- | false);
-}
-
-// ====================================================================================================================================================================
-// State Building Functions
-// ====================================================================================================================================================================
-
-function <> meta::pure::router::preeval::defaultFunctionInlineStrategy(extensions:Extension[*]) : FunctionDefinition<{Function[1]->Boolean[1]}>[1]
-{
- {f:Function[1] | $f->in([col_Function_1__String_1__BasicColumnSpecification_1_,
- col_Function_1__String_1__String_1__BasicColumnSpecification_1_,
- // TODO: We should confirm presence of below 2 functions
- meta::pure::functions::date::mostRecentDayOfWeek_DayOfWeek_1__Date_1_,
- meta::pure::functions::date::previousDayOfWeek_DayOfWeek_1__Date_1_])
- || (!meta::pure::router::routing::shouldStop($f, $extensions) && !($f->instanceOf(NativeFunction)))}
-}
-
-function <> meta::pure::router::preeval::defaultPreevalStopStrategy(extensions:Extension[*]) : FunctionDefinition<{Any[1]->Boolean[1]}>[1]
-{
- {a:Any[1] | stopPreeval($a, $extensions)};
-}
-
-function meta::pure::router::preeval::getPreevalStateWithAdditionalStopInlineFunc(inScopeVars:Map>[1], extensions:meta::pure::extension::Extension[*], stopInlineFunctions:Function[*]):meta::pure::router::preeval::State[1]
-{
- ^meta::pure::router::preeval::State(inScopeVars = $inScopeVars,
- shouldInlineFxn = {f:Function[1] | meta::pure::router::preeval::defaultFunctionInlineStrategy($extensions)->eval($f)
- && !$f->in($stopInlineFunctions)},
- stopPreeval = meta::pure::router::preeval::defaultPreevalStopStrategy($extensions),
- rollingInScopeVars = $inScopeVars,
- debug = noDebug(),
- inScopeTypeParams = ^Map());
-}
-
-function <> meta::pure::router::preeval::stopPreeval(value : Any[*], extensions:Extension[*]) : Boolean[1]
-{
- $extensions.routerExtensions().shouldStopPreeval->exists(p | $p->eval($value)) ||
- $value->match([
- p : String[*]| true,
- p : Float[*]| true,
- p : Decimal[*] | true,
- p : Enum[*]| true,
- p : StrictDate[*]| true,
- p : LatestDate[*]| true,
- p : Integer[*]| true,
- p : Boolean[*]| true,
- p : DateTime[*]| true,
- p : SortInformation[*]| true,
- p : Enumeration[*]| true,
- p : Class[*]| true,
- p : Pair[*]| true,
- p : Property[*]| true,
- p : Type[*]| true,
- p : Path[*]|true,
- p : meta::pure::mapping::Mapping[1]| true,
- p : meta::pure::runtime::PackageableRuntime[1]| true,
- p : meta::pure::runtime::Runtime[1]| true,
- p : meta::pure::runtime::Connection[1] | true,
- p : meta::pure::runtime::ExecutionContext[1]| true,
- p : meta::pure::tds::TDSColumn[*]| true,
- p : TdsOlapRank[*]| true,
- p : TdsOlapAggregation[*]| true,
- p : meta::pure::graphFetch::execution::AlloySerializationConfig[1]| true,
- f : SimpleFunctionExpression[1]| $f.func->in([letFunction_String_1__T_m__T_m_]),
- a : Any[*]| $a->type()
- ->match([
- c:Class[1]|$c->isSimpleType(),
- o:Any[1]|false
- ])
- ]);
-}
-
-function <> meta::pure::router::preeval::isSimpleType(c : Class[1]) : Boolean[1]
-{
- $c->isSimpleType([]);
-}
-
-function <> meta::pure::router::preeval::isSimpleType(c : Class[1], visitedClasses : Class[*]) : Boolean[1]
-{
- let types = $c.properties->map(p|$p->functionReturnType().rawType)
- ->distinct()
- ->removeAll([String, Integer, Date, DateTime, StrictDate, LatestDate,Float])
- ->removeAll($visitedClasses)
- ->filter(x|!$x->instanceOf(Enumeration));
-
- let newClassTypes = $types->filter(x|$x->instanceOf(Class))->cast(@Class);
- let unsupporedBasicTypes = $types->removeAll($newClassTypes);
-
- $unsupporedBasicTypes->isEmpty() && $newClassTypes->forAll(newC|$newC->isSimpleType($visitedClasses->concatenate($newClassTypes)));
-}
-
-
-// ====================================================================================================================================================================
-// Utility Functions
-// ====================================================================================================================================================================
-
-function <> meta::pure::router::preeval::resolveGenericType(in : GenericType[1], state : meta::pure::router::preeval::State[1]):PrevalWrapper[1]
-{
- if($in.typeParameter->isEmpty(),
- |
- let newTypeArgsWrappers = $in.typeArguments->map(ta|$ta->resolveGenericType($state));
- if(!$newTypeArgsWrappers->anyModified(),
- | ^PrevalWrapper(value = $in, canPreval=true, modified = false),
- | let value = ^$in(typeArguments = $newTypeArgsWrappers.value);
- ^PrevalWrapper(value = $value, canPreval=$newTypeArgsWrappers->canPreval(), modified = $newTypeArgsWrappers->anyModified());
- );,
- |
- let value = $state.inScopeTypeParams->get($in.typeParameter->toOne().name);
- if($value->isEmpty(),
- | ^PrevalWrapper(value = $in, canPreval=true, modified = false),
- | ^PrevalWrapper(value = $value->toOne(), canPreval=true, modified = true)
- );
- );
-}
-
-function <> meta::pure::router::preeval::shouldInline(f:Function[1], state : meta::pure::router::preeval::State[1]):Boolean[1]
-{
- ($f->instanceOf(FunctionDefinition) && ($f->cast(@FunctionDefinition).expressionSequence->size() == 1 ))
- && !($f->instanceOf(QualifiedProperty) && $f->cast(@QualifiedProperty).owner == TDSRow)
- && !($f->instanceOf(AbstractProperty) && $f->cast(@AbstractProperty)->meta::pure::milestoning::hasGeneratedMilestoningPropertyStereotype())
- && ($state.shouldInlineFxn->eval($f))
- && ($state.path->filter(x|$x == $f)->isEmpty())
-}
-
-function <> meta::pure::router::preeval::canInlineEvalFunctionExpression(fe:SimpleFunctionExpression[1]):Boolean[1]
-{
- $fe.func->in([eval_Function_1__V_m_,
- eval_Function_1__T_n__V_m_,
- eval_Function_1__T_n__U_p__V_m_,
- eval_Function_1__T_n__U_p__W_q__V_m_,
- eval_Function_1__T_n__U_p__W_q__X_r__V_m_,
- eval_Function_1__T_n__U_p__W_q__X_r__Y_s__V_m_,
- eval_Function_1__T_n__U_p__W_q__X_r__Y_s__Z_t__V_m_,
- eval_Function_1__S_n__T_o__U_p__W_q__X_r__Y_s__Z_t__V_m_])
- && $fe.parametersValues->at(0)->match([
- iv:InstanceValue[1]|$iv.values->toOne(),
- vs:ValueSpecification[1]|$vs
- ])->instanceOf(FunctionDefinition)
- && $fe.parametersValues->at(0)->match([
- iv:InstanceValue[1]|$iv.values->toOne(),
- vs:ValueSpecification[1]|$vs
- ])->cast(@FunctionDefinition).expressionSequence->size() == 1
-}
-
-function <> meta::pure::router::preeval::toMultiplicity(size : Integer[1]) : Multiplicity[1]
-{
- if($size == 0,
- | PureZero,
- | if($size == 1,
- | PureOne,
- | ^Multiplicity(lowerBound = ^MultiplicityValue(value=$size), upperBound = ^MultiplicityValue(value=$size))
- );
- );
-}
-
-function <> meta::pure::router::preeval::addToScope(sfe : SimpleFunctionExpression[1], state : meta::pure::router::preeval::State[1]):meta::pure::router::preeval::State[1]
-{
- addToScope($state, $sfe.func, $sfe.resolvedTypeParameters, $sfe.parametersValues, true);
-}
-
-function <> meta::pure::router::preeval::addToScope(state : meta::pure::router::preeval::State[1], func : Function[1],resolvedTypeParameters : GenericType[*], parametersValues : ValueSpecification[*]):meta::pure::router::preeval::State[1]
-{
- addToScope($state, $func, $resolvedTypeParameters, $parametersValues, false)
-}
-
-function <> meta::pure::router::preeval::addToScope(state : meta::pure::router::preeval::State[1], func : Function[1],resolvedTypeParameters : GenericType[*], parametersValues : ValueSpecification[*], cleanupInScopeVarsAndTypeParams:Boolean[1]):meta::pure::router::preeval::State[1]
-{
- let typeParams = $func->functionType().typeParameters.name->zip($resolvedTypeParameters->map(x|$x->resolveGenericType($state).value));
-
- let newParams = $parametersValues;
-
- let funcParamNames = $func->functionType().parameters.name;
- let additionalInScopeVars = $funcParamNames
- ->zip($newParams->map(pv|list($pv)))
- ->map({p| let paramName = $p.first;
- let paramValue = $p.second;
-
- $paramValue.values->match([
- ve:VariableExpression[1]|
- if($ve.name == $paramName,
- | [], //We drop easy "circular" / self-reference parameter variables
- | $p
- ),
- vs:ValueSpecification[*]|
- $p;
- ]);
- });
-
- if($cleanupInScopeVarsAndTypeParams, |^$state(inScopeVars=newMap([]), inScopeTypeParams=newMap([])), |$state)->addToScope($additionalInScopeVars, $typeParams);
-}
-
-function <> meta::pure::router::preeval::addToScope(state : meta::pure::router::preeval::State[1], additionalInScopeVars : Pair>[*], typeParams : Pair[*]):meta::pure::router::preeval::State[1]
-{
- $state->printDebugWithDepth(|'Adding variables to scope: ' + $additionalInScopeVars.first->joinStrings('[', ',', ']'));
- $state->printDebugWithDepth(|'Adding type params to scope: ' + $typeParams.first->joinStrings('[', ',', ']'));
-
- let newInScopeVars = $state.inScopeVars->putAll($additionalInScopeVars);
- let newInScopeTypeParams = $state.inScopeTypeParams->putAll($typeParams);
-
- ^$state(inScopeVars = $newInScopeVars, inScopeTypeParams = $newInScopeTypeParams);
-}
-
-function <> meta::pure::router::preeval::resolveVariable(name : String[1], state : meta::pure::router::preeval::State[1]):String[1]
-{
- $state.inScopeVars->get($name).values->match([
- ve:VariableExpression[1]|assert($name != $ve.name, 'Circular variable reference: ' + $name); $ve.name->resolveVariable($state);,
- a:Any[*]|$name
- ]);
-}
-
-function <> meta::pure::router::preeval::canPreval(items : PrevalWrapper[*]):Boolean[1]
-{
- $items->forAll(p | $p.canPreval);
-}
-
-function <> meta::pure::router::preeval::markModified(item : PrevalWrapper[1]):PrevalWrapper[1]
-{
- if($item.modified,
- | $item,
- | ^$item(modified = true)
- );
-}
-
-function <> meta::pure::router::preeval::anyModified(items : PrevalWrapper[*]):Boolean[1]
-{
- $items.modified->contains(true);
-}
-
-function <> meta::pure::router::preeval::openVars(items : PrevalWrapper[*], inScopeVars:Map>[1]):String[*]
-{
- $items.openVars->openVars($inScopeVars);
-}
-
-function <> meta::pure::router::preeval::openVars(vars : String[*], inScopeVars:Map>[1]):String[*]
-{
- $vars->distinct()->filter(v|!$v->areAllInScope($inScopeVars))
-}
-
-function <> meta::pure::router::preeval::areAllInScope(items : PrevalWrapper[*], inScopeVars:Map>[1]):Boolean[1]
-{
- $items.openVars->distinct()->areAllInScope($inScopeVars);
-}
-
-function <> meta::pure::router::preeval::areAllInScope(vars : String[*], inScopeVars:Map>[1]):Boolean[1]
-{
- if($vars->isEmpty(),
- | true,
- | let unresolvedVars = $vars->map(v|let varVal = $inScopeVars->get($v);
-
- if($varVal->isEmpty(),
- | $v,
- | $varVal.values->match([
- varExp : VariableExpression[1]|$varExp.name,
- a : Any[*]|[]
- ])
- );
- )->distinct();
-
- let newVars = $unresolvedVars->removeAll($vars);
- !$unresolvedVars->containsAny($vars) && $newVars->areAllInScope($inScopeVars);
- );
-}
-
-function <> meta::pure::router::preeval::isInstanceValue(v: Any[1], inScopeVars:Map>[1]):Boolean[1]
-{
- $v->match([
- iv : InstanceValue[1]|
- $iv.values->forAll(subV|$subV->match([
- subVS : ValueSpecification[1]|$subVS->isInstanceValue($inScopeVars),
- a : Any[1]| true;
- ]));,
- ve : VariableExpression[1]|$inScopeVars->get($ve.name)->isNotEmpty(),
- sfe : SimpleFunctionExpression[1]|false;
- ])
-}
-
-function <> meta::pure::router::preeval::printDebugWithDepth(state: meta::pure::router::preeval::State[1], func:Function<{->String[1]}>[1]):Nil[0]
-{
- printDebug($state, | ('[' + toString($state.depth->orElse(''))->map(s|'0000'->substring(0, max(0, 3-$s->length())) + $s) + ']' + range($state.depth->orElse(0) + 1)->map(d|'')->joinStrings('', '-', ' ') + $func->eval()));
-}
-
-function <> meta::pure::router::preeval::printDebug(state: meta::pure::router::preeval::State[1], func:Function<{->Any[*]}>[1]):Nil[0]
-{
- printDebug($state.debug, $func);
-}
-
-function <> meta::pure::router::preeval::printDebug(debugContext : DebugContext[1], func:Function<{->Any[*]}>[1]):Nil[0]
-{
- if(!$debugContext.debug,
- | print(''),
- | printDebug($debugContext, $func->eval());
- );
-}
-
-function <> meta::pure::router::preeval::printDebug(state: meta::pure::router::preeval::State[1], param:Any[*]):Nil[0]
-{
- printDebug($state.debug, $param);
-}
-
-function <> meta::pure::router::preeval::printDebug(debugContext : DebugContext[1], param:Any[*]):Nil[0]
-{
- if(!$debugContext.debug,
- | print(''),
- | println($param);
- );
+// Copyright 2023 Goldman Sachs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import meta::pure::router::preeval::*;
+import meta::pure::extension::*;
+import meta::pure::metamodel::path::*;
+import meta::pure::router::extension::*;
+import meta::pure::router::utils::*;
+
+Class meta::pure::router::preeval::State
+{
+ inScopeVars : Map>[1];
+ rollingInScopeVars : Map>[1];
+ inScopeTypeParams : Map[1];
+
+ debug : DebugContext[1];
+ depth : Integer[0..1];
+ path : FunctionDefinition[*];
+
+ shouldInlineFxn : FunctionDefinition<{Function[1] -> Boolean[1]}>[1];
+ stopPreeval : Function<{Any[1] -> Boolean[1]}>[1];
+
+ toString() { $this->simpleToString() }:String[1];
+}
+
+Class meta::pure::router::preeval::PrevalWrapper
+{
+ canPreval : Boolean[1];
+ value : T[1];
+ openVars : String[*];
+ modified : Boolean[1];
+
+ toString() { $this->simpleToString() }:String[1];
+}
+
+
+// ====================================================================================================================================================================
+// Public Apis
+// ====================================================================================================================================================================
+
+function <> meta::pure::router::preeval::preval(f:FunctionDefinition[1], extensions:Extension[*]):FunctionDefinition[1]
+{
+ preval($f, $extensions, noDebug());
+}
+
+function <> meta::pure::router::preeval::preval(f:FunctionDefinition[1], extensions:Extension[*], debug:DebugContext[1]):FunctionDefinition[1]
+{
+ preval($f, newMap([]->cast(@Pair)), $f->openVariableValues(), $extensions, $debug).value->toOne()->cast($f);
+}
+
+function <> meta::pure::router::preeval::preval(f : FunctionDefinition[1], vars:Map[1], inScopeVars:Map>[1], extensions:Extension[*]):PrevalWrapper>[1]
+{
+ preval($f, $vars, $inScopeVars, $extensions, noDebug());
+}
+
+function <> meta::pure::router::preeval::preval(f : FunctionDefinition[1], vars:Map[1], inScopeVars:Map>[1], extensions:Extension[*], debug:DebugContext[1]):PrevalWrapper>[1]
+{
+ let state = ^meta::pure::router::preeval::State(inScopeVars = $inScopeVars,
+ shouldInlineFxn = defaultFunctionInlineStrategy($extensions),
+ stopPreeval = defaultPreevalStopStrategy($extensions),
+ rollingInScopeVars = $inScopeVars,
+ debug = $debug,
+ inScopeTypeParams = ^Map());
+ preval($f, $state, $extensions);
+}
+
+function <> meta::pure::router::preeval::preval(f : FunctionDefinition[1], state:State[1], extensions:Extension[*]):PrevalWrapper>[1]
+{
+ let r = prevalInternal($f->evaluateAndDeactivate(), $state, $extensions)->toOne()->cast(@PrevalWrapper>);
+
+ if(!$r->anyModified(),
+ |
+ $state->printDebug(|'No changes made for: ');
+ $state->printDebug(|$f->meta::protocols::pure::vX_X_X::transformation::fromPureGraph::valueSpecification::transformFunctionBody($extensions)->meta::protocols::pure::vX_X_X::transformation::fromPureGraph::toPureGrammar::toPure($extensions));,
+ |
+ let res = $r.value->toOne();
+
+ // $state->printDebug('Transformed From:');
+ // $state->printDebug(|$f->meta::protocols::pure::vX_X_X::transformation::fromPureGraph::valueSpecification::transformFunctionBody($extensions)->meta::json::toJSON(50000));
+ // $state->printDebug(|$f->meta::protocols::pure::vX_X_X::transformation::fromPureGraph::valueSpecification::transformFunctionBody($extensions)->meta::protocols::pure::vX_X_X::transformation::toPureGrammar::toPure($extensions));
+
+ $state->printDebug('Transformed To:');
+ $state->printDebug(|$res->meta::protocols::pure::vX_X_X::transformation::fromPureGraph::valueSpecification::transformFunctionBody($extensions)->meta::json::toJSON(50000));
+ $state->printDebug(|$res->meta::protocols::pure::vX_X_X::transformation::fromPureGraph::valueSpecification::transformFunctionBody($extensions)->meta::protocols::pure::vX_X_X::transformation::fromPureGraph::toPureGrammar::toPure($extensions));
+
+ $state->printDebug($res);
+ );
+
+ $r;
+}
+
+function <> meta::pure::router::preeval::preval(f : FunctionExpression[1], inScopeVars:Map