diff --git a/.github/workflows/sdt-duckdb.yml b/.github/workflows/sdt-duckdb.yml new file mode 100644 index 00000000000..4b815c46032 --- /dev/null +++ b/.github/workflows/sdt-duckdb.yml @@ -0,0 +1,77 @@ +# Copyright 2024 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. + +name: (SDT) DuckDB SQL Dialect Tests + +env: + CI_DEPLOY_USERNAME: ${{ secrets.CI_DEPLOY_USERNAME }} + CI_DEPLOY_PASSWORD: ${{ secrets.CI_DEPLOY_PASSWORD }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + PROJECT_DIR: legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Set up JDK + uses: actions/setup-java@v4 + with: + java-version: 11 + distribution: zulu + server-id: ossrh + server-username: CI_DEPLOY_USERNAME + server-password: CI_DEPLOY_PASSWORD + + - name: Check Java version + run: java -version + + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Build core_external_store_relational_sql_dialect_translation_duckdb + run: | + mvn -B -e -pl ${{ env.PROJECT_DIR }} clean install -am -DskipTests=true + + - name: Run SDT Test + run: | + mvn -B -e -pl ${{ env.PROJECT_DIR }} test -Dtest=Test_DuckDB_SDT + + - name: Upload Test Results + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results + path: ${{ env.PROJECT_DIR }}/target/surefire-reports/*.xml + + - name: Publish Test Results + uses: mikepenz/action-junit-report@v4 + if: always() + with: + report_paths: '${{ env.PROJECT_DIR }}/target/surefire-reports/*.xml' + fail_on_failure: true + summary: true + detailed_summary: true + include_passed: true + check_name: DuckDB SDT Report + job_name: DuckDB SDT Report + + - name: Upload CI Event + if: always() + uses: actions/upload-artifact@v4 + with: + name: event-file + path: ${{ github.event_path }} diff --git a/.github/workflows/sdt-postgres.yml b/.github/workflows/sdt-postgres.yml new file mode 100644 index 00000000000..762c487edb7 --- /dev/null +++ b/.github/workflows/sdt-postgres.yml @@ -0,0 +1,77 @@ +# Copyright 2024 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. + +name: (SDT) Postgres SQL Dialect Tests + +env: + CI_DEPLOY_USERNAME: ${{ secrets.CI_DEPLOY_USERNAME }} + CI_DEPLOY_PASSWORD: ${{ secrets.CI_DEPLOY_PASSWORD }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + PROJECT_DIR: legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Set up JDK + uses: actions/setup-java@v4 + with: + java-version: 11 + distribution: zulu + server-id: ossrh + server-username: CI_DEPLOY_USERNAME + server-password: CI_DEPLOY_PASSWORD + + - name: Check Java version + run: java -version + + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Build core_external_store_relational_sdt + run: | + mvn -B -e -pl ${{ env.PROJECT_DIR }} clean install -am -DskipTests=true + + - name: Run SDT Test + run: | + mvn -B -e -pl ${{ env.PROJECT_DIR }} test -Dtest=Test_Postgres_SDT + + - name: Upload Test Results + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results + path: ${{ env.PROJECT_DIR }}/target/surefire-reports/*.xml + + - name: Publish Test Results + uses: mikepenz/action-junit-report@v4 + if: always() + with: + report_paths: '${{ env.PROJECT_DIR }}/target/surefire-reports/*.xml' + fail_on_failure: true + summary: true + detailed_summary: true + include_passed: true + check_name: Postgres SDT Report + job_name: Postgres SDT Report + + - name: Upload CI Event + if: always() + uses: actions/upload-artifact@v4 + with: + name: event-file + path: ${{ github.event_path }} 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 de3b2b1a7e0..386d5935190 100644 --- a/legend-engine-config/legend-engine-extensions-collection-generation/pom.xml +++ b/legend-engine-config/legend-engine-extensions-collection-generation/pom.xml @@ -356,6 +356,11 @@ legend-engine-xt-relationalStore-sqlDialectTranslation-pure runtime + + org.finos.legend.engine + legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure + runtime + 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 2522ab7a88f..f7d70e917e9 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 @@ -586,6 +586,7 @@ protected Iterable getExpectedCodeRepositories() .with("core_nonrelational_mongodb_java_platform_binding") .with("core_external_store_relational_sql_planning") .with("core_external_store_relational_sql_dialect_translation") + .with("core_external_store_relational_sql_dialect_translation_duckdb") ; } } diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/pom.xml b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/pom.xml index 6389d630a6c..1b763bc9fad 100644 --- a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/pom.xml +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/pom.xml @@ -278,6 +278,11 @@ runtime ${project.version} + + org.finos.legend.engine + legend-engine-xt-relationalStore-SDT-pure + runtime + diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/java/org/finos/legend/engine/ide/PureIDELight.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/java/org/finos/legend/engine/ide/PureIDELight.java index 805e1a346eb..d1c989912e2 100644 --- a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/java/org/finos/legend/engine/ide/PureIDELight.java +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/java/org/finos/legend/engine/ide/PureIDELight.java @@ -122,6 +122,8 @@ protected MutableList buildRepositories(SourceLocationCon .with(this.buildCore("legend-engine-xts-dataquality/legend-engine-xt-dataquality-pure", "dataquality")) .with(this.buildCore("legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-sqlPlanning-pure", "external-store-relational-sql-planning")) .with(this.buildCore("legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-sqlDialectTranslation-pure", "external-store-relational-sql-dialect-translation")) + .with(this.buildCore("legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure", "external-store-relational-sdt")) + .with(this.buildCore("legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure", "external-store-relational-sql-dialect-translation-duckdb")) ; } diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure/pom.xml new file mode 100644 index 00000000000..a6e2f35f9ed --- /dev/null +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure/pom.xml @@ -0,0 +1,181 @@ + + + + + + org.finos.legend.engine + legend-engine-xt-relationalStore-duckdb + 4.63.2-SNAPSHOT + + 4.0.0 + + legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure + jar + Legend Engine - XT - Relational Store - DuckDB - SQL Dialect Translation - Pure + + + + + org.finos.legend.pure + legend-pure-maven-generation-par + + ${project.basedir}/src/main/resources + ${legend.pure.version} + + core_external_store_relational_sql_dialect_translation_duckdb + + + ${project.basedir}/src/main/resources/core_external_store_relational_sql_dialect_translation_duckdb.definition.json + + + + + generate-sources + + build-pure-jar + + + + + + org.finos.legend.engine + legend-engine-xt-relationalStore-sqlDialectTranslation-pure + ${project.version} + + + org.finos.legend.pure + legend-pure-m2-dsl-diagram-grammar + ${legend.pure.version} + + + + + org.finos.legend.pure + legend-pure-maven-generation-java + + + compile + + build-pure-compiled-jar + + + true + true + modular + true + + core_external_store_relational_sql_dialect_translation_duckdb + + + + + + + org.finos.legend.engine + legend-engine-xt-relationalStore-sqlDialectTranslation-pure + ${project.version} + + + org.finos.legend.pure + legend-pure-m2-dsl-diagram-grammar + ${legend.pure.version} + + + + + + maven-surefire-plugin + + false + + **/Test_DuckDB_SDT*.java + **/SdtTestSuiteBuilder*.java + + + + + + + + + + org.finos.legend.pure + legend-pure-m4 + + + org.finos.legend.pure + legend-pure-m3-core + + + org.finos.legend.pure + legend-pure-runtime-java-engine-compiled + + + + + + org.finos.legend.engine + legend-engine-pure-platform-java + + + org.finos.legend.engine + legend-engine-pure-code-compiled-core + + + org.finos.legend.engine + legend-engine-xt-relationalStore-postgresSqlModel-pure + + + org.finos.legend.engine + legend-engine-xt-relationalStore-sqlDialectTranslation-pure + + + + + org.eclipse.collections + eclipse-collections + + + org.eclipse.collections + eclipse-collections-api + + + + + junit + junit + + + org.finos.legend.engine + legend-engine-xt-relationalStore-SDT-pure + test + + + org.finos.legend.engine + legend-engine-xt-relationalStore-duckdb-PCT + test + + + org.finos.legend.engine + legend-engine-xt-relationalStore-SDT-pure + test-jar + ${project.version} + test + + + + diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure/src/main/java/org/finos/legend/pure/code/core/CoreExternalStoreRelationalSqlDialectTranslationDuckDBCodeRepositoryProvider.java b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure/src/main/java/org/finos/legend/pure/code/core/CoreExternalStoreRelationalSqlDialectTranslationDuckDBCodeRepositoryProvider.java new file mode 100644 index 00000000000..1897b4045cf --- /dev/null +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure/src/main/java/org/finos/legend/pure/code/core/CoreExternalStoreRelationalSqlDialectTranslationDuckDBCodeRepositoryProvider.java @@ -0,0 +1,29 @@ +// Copyright 2024 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.pure.code.core; + +import org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepository; +import org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepositoryProvider; +import org.finos.legend.pure.m3.serialization.filesystem.repository.GenericCodeRepository; + +public class CoreExternalStoreRelationalSqlDialectTranslationDuckDBCodeRepositoryProvider implements CodeRepositoryProvider +{ + @Override + public CodeRepository repository() + { + return GenericCodeRepository.build("core_external_store_relational_sql_dialect_translation_duckdb.definition.json"); + } +} + diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure/src/main/resources/META-INF/services/org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepositoryProvider b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure/src/main/resources/META-INF/services/org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepositoryProvider new file mode 100644 index 00000000000..03f3448f973 --- /dev/null +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure/src/main/resources/META-INF/services/org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepositoryProvider @@ -0,0 +1 @@ +org.finos.legend.pure.code.core.CoreExternalStoreRelationalSqlDialectTranslationDuckDBCodeRepositoryProvider \ No newline at end of file diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure/src/main/resources/core_external_store_relational_sql_dialect_translation_duckdb.definition.json b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure/src/main/resources/core_external_store_relational_sql_dialect_translation_duckdb.definition.json new file mode 100644 index 00000000000..3fc3c5aee00 --- /dev/null +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure/src/main/resources/core_external_store_relational_sql_dialect_translation_duckdb.definition.json @@ -0,0 +1,19 @@ +{ + "name": "core_external_store_relational_sql_dialect_translation_duckdb", + "pattern": "(meta::external::store::relational::sqlDialectTranslation::duckDB)(::.*)?", + "dependencies": [ + "platform", + "platform_dsl_store", + "platform_dsl_mapping", + "platform_dsl_path", + "platform_dsl_graph", + "platform_dsl_diagram", + "platform_store_relational", + "core_functions_standard", + "core_functions_unclassified", + "core_functions_json", + "core", + "core_external_store_relational_postgres_sql_model", + "core_external_store_relational_sql_dialect_translation" + ] +} \ No newline at end of file diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure/src/main/resources/core_external_store_relational_sql_dialect_translation_duckdb/duckDBSqlDialect.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure/src/main/resources/core_external_store_relational_sql_dialect_translation_duckdb/duckDBSqlDialect.pure new file mode 100644 index 00000000000..1603ac173b1 --- /dev/null +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure/src/main/resources/core_external_store_relational_sql_dialect_translation_duckdb/duckDBSqlDialect.pure @@ -0,0 +1,162 @@ +// Copyright 2024 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::external::query::sql::metamodel::*; +import meta::external::store::relational::sqlDialectTranslation::*; +import meta::external::store::relational::sqlDialectTranslation::defaults::*; +import meta::external::store::relational::sqlDialectTranslation::duckDB::*; +import meta::external::store::relational::sqlDialectTranslation::utils::*; +import meta::pure::extension::*; + +function meta::external::store::relational::sqlDialectTranslation::duckDB::duckDBSqlDialect(): SqlDialect[1] +{ + ^SqlDialect + ( + dbType = 'DuckDB', + quoteConfig = duckDBQuoteConfiguration(), + nodeProcessors = duckDBDialectNodeProcessors(), + identifierProcessor = duckDBIdentifierProcessor(), + expressionPrecedenceComparator = duckDBExpressionPrecedenceComparator(), + keywords = duckDBKeywords() + ) +} + + +function meta::external::store::relational::sqlDialectTranslation::duckDB::duckDBSqlDialectExtension(): Extension[1] +{ + ^Extension + ( + type = 'DuckDBSqlDialectExtension', + moduleExtensions = [ + ^SqlDialectTranslationModuleExtension + ( + module = sqlDialectTranslationModuleExtensionName(), + extraSqlDialects = duckDBSqlDialect() + ) + ] + ) +} + +function <> meta::external::store::relational::sqlDialectTranslation::duckDB::duckDBQuoteConfiguration(): QuoteConfiguration[1] +{ + ^QuoteConfiguration + ( + start = '"', + end = '"', + escape = '""' + ) +} + +function <> meta::external::store::relational::sqlDialectTranslation::duckDB::duckDBDialectNodeProcessors(): Map, NodeProcessor>[1] +{ + newMap( + duckDBDialectStatementProcessors() + ->concatenate( + duckDBDialectRelationProcessors() + ) + ->concatenate( + duckDBDialectExpressionProcessors() + ) + ->concatenate( + duckDBDialectLiteralProcessors() + ) + ->concatenate( + duckDBDialectSelectItemProcessors() + ) + ->concatenate( + duckDBDialectOtherNodeProcessors() + ) + ->map(n | pair($n.nodeType, $n)) + ) +} + +function <> meta::external::store::relational::sqlDialectTranslation::duckDB::duckDBDialectStatementProcessors(): NodeProcessor[*] +{ + [ + queryProcessor_default(), + windowProcessor_default() + ] +} + +function <> meta::external::store::relational::sqlDialectTranslation::duckDB::duckDBDialectRelationProcessors(): NodeProcessor[*] +{ + [ + tableProcessor_default(), + aliasedRelationProcessor_default(), + joinProcessor_default(), + querySpecificationProcessor_default(), + unionProcessor_default() + ] +} + +function <> meta::external::store::relational::sqlDialectTranslation::duckDB::duckDBDialectExpressionProcessors(): NodeProcessor[*] +{ + [ + comparisonExpressionNodeProcessor_default(), + logicalBinaryExpressionNodeProcessor_default(), + notExpressionNodeProcessor_default(), + arithmeticExpressionNodeProcessor_default(), + columnTypeProcessor_default(), + castProcessor_default() + ] +} + +function <> meta::external::store::relational::sqlDialectTranslation::duckDB::duckDBDialectLiteralProcessors(): NodeProcessor[*] +{ + [ + integerLiteralNodeProcessor_default(), + stringLiteralNodeProcessor_default(), + booleanLiteralNodeProcessor_default(), + longLiteralNodeProcessor_default(), + doubleLiteralNodeProcessor_default(), + nullLiteralNodeProcessor_default() + ] +} + +function <> meta::external::store::relational::sqlDialectTranslation::duckDB::duckDBDialectSelectItemProcessors(): NodeProcessor[*] +{ + [ + allColumnsNodeProcessor_default(), + singleColumnNodeProcessor_default() + ] +} + +function <> meta::external::store::relational::sqlDialectTranslation::duckDB::duckDBDialectOtherNodeProcessors(): NodeProcessor[*] +{ + [ + sortItemProcessor_default(), + selectProcessor_default() + ] +} + +function <> meta::external::store::relational::sqlDialectTranslation::duckDB::duckDBIdentifierProcessor(): IdentifierProcessor[1] +{ + identifierProcessor_default() +} + +function <> meta::external::store::relational::sqlDialectTranslation::duckDB::duckDBExpressionPrecedenceComparator(): ExpressionPrecedenceComparator[1] +{ + ^ExpressionPrecedenceComparator( + findOperatorType = findOperatorType_default_Expression_1__String_1_, + operatorPrecedence = operatorPrecedence_default() + ) +} + +function <> meta::external::store::relational::sqlDialectTranslation::duckDB::duckDBKeywords(): String[*] +{ + [ + // TODO: Update + 'date' + ] +} diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure/src/test/java/org/finos/legend/engine/relational/sdt/duckdb/Test_DuckDB_SDT.java b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure/src/test/java/org/finos/legend/engine/relational/sdt/duckdb/Test_DuckDB_SDT.java new file mode 100644 index 00000000000..d6e840bbcb5 --- /dev/null +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure/src/test/java/org/finos/legend/engine/relational/sdt/duckdb/Test_DuckDB_SDT.java @@ -0,0 +1,35 @@ +// Copyright 2024 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.relational.sdt.duckdb; + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.eclipse.collections.api.factory.Lists; +import org.eclipse.collections.api.factory.Maps; +import org.finos.legend.engine.relational.test.sdt.SdtTestSuiteBuilder; + +import static org.finos.legend.pure.generated.core_external_store_relational_sql_dialect_translation_duckdb_duckDBSqlDialect.Root_meta_external_store_relational_sqlDialectTranslation_duckDB_duckDBSqlDialectExtension__Extension_1_; + +public class Test_DuckDB_SDT extends TestSuite +{ + public static Test suite() + { + return SdtTestSuiteBuilder.buildSdtTestSuite( + "DuckDB", + es -> Lists.immutable.of(Root_meta_external_store_relational_sqlDialectTranslation_duckDB_duckDBSqlDialectExtension__Extension_1_(es)), + Maps.mutable.empty() + ); + } +} diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure/src/test/java/org/finos/legend/pure/code/core/Test_Pure_ExternalStoreRelationalSqlDialectTranslationDuckDB.java b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure/src/test/java/org/finos/legend/pure/code/core/Test_Pure_ExternalStoreRelationalSqlDialectTranslationDuckDB.java new file mode 100644 index 00000000000..63b90f9b6dd --- /dev/null +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure/src/test/java/org/finos/legend/pure/code/core/Test_Pure_ExternalStoreRelationalSqlDialectTranslationDuckDB.java @@ -0,0 +1,32 @@ +// Copyright 2024 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.pure.code.core; + +import junit.framework.TestSuite; +import org.finos.legend.pure.m3.execution.test.PureTestBuilder; +import org.finos.legend.pure.m3.execution.test.TestCollection; +import org.finos.legend.pure.runtime.java.compiled.execution.CompiledExecutionSupport; +import org.finos.legend.pure.runtime.java.compiled.testHelper.PureTestBuilderCompiled; + +public class Test_Pure_ExternalStoreRelationalSqlDialectTranslationDuckDB +{ + public static TestSuite suite() + { + CompiledExecutionSupport executionSupport = PureTestBuilderCompiled.getClassLoaderExecutionSupport(); + TestSuite suite = new TestSuite(); + suite.addTest(PureTestBuilderCompiled.buildSuite(TestCollection.collectTests("meta::external::store::relational::sqlDialectTranslation::duckDB", executionSupport.getProcessorSupport(), fn -> PureTestBuilderCompiled.generatePureTestCollection(fn, executionSupport), ci -> PureTestBuilder.satisfiesConditions(ci, executionSupport.getProcessorSupport())), executionSupport)); + return suite; + } +} diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/pom.xml index 1fafd936735..f27d3ae5b10 100644 --- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/pom.xml +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/pom.xml @@ -18,6 +18,7 @@ legend-engine-xt-relationalStore-duckdb-grammar legend-engine-xt-relationalStore-duckdb-protocol legend-engine-xt-relationalStore-duckdb-pure + legend-engine-xt-relationalStore-duckdb-sqlDialectTranslation-pure diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan/pom.xml index df6d7ac3a9c..cc48a627922 100644 --- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan/pom.xml +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan/pom.xml @@ -294,11 +294,6 @@ legend-pure-m2-dsl-mapping-grammar test - - org.finos.legend.engine - legend-engine-configuration-contract-extension-pure - test - org.finos.legend.engine legend-engine-xt-javaPlatformBinding-pure diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/pom.xml new file mode 100644 index 00000000000..f04e7dc6bfd --- /dev/null +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/pom.xml @@ -0,0 +1,245 @@ + + + + + + org.finos.legend.engine + legend-engine-xt-relationalStore-pure + 4.63.2-SNAPSHOT + + 4.0.0 + + legend-engine-xt-relationalStore-SDT-pure + jar + Legend Engine - XT - Relational Store - SDT - PAR/JAVA + + + + + org.finos.legend.pure + legend-pure-maven-generation-par + + src/main/resources + ${legend.pure.version} + + core_external_store_relational_sdt + + + ${project.basedir}/src/main/resources/core_external_store_relational_sdt.definition.json + + + + + generate-sources + + build-pure-jar + + + + + + org.finos.legend.pure + legend-pure-m2-dsl-diagram-grammar + ${legend.pure.version} + + + org.finos.legend.engine + legend-engine-pure-code-compiled-core + ${project.version} + + + org.finos.legend.engine + legend-engine-xt-relationalStore-postgresSqlModel-pure + ${project.version} + + + org.finos.legend.engine + legend-engine-xt-relationalStore-sqlDialectTranslation-pure + ${project.version} + + + + + org.finos.legend.pure + legend-pure-maven-generation-java + + + compile + + build-pure-compiled-jar + + + true + true + modular + true + + core_external_store_relational_sdt + + + + + + + org.finos.legend.pure + legend-pure-m2-dsl-diagram-grammar + ${legend.pure.version} + + + org.finos.legend.engine + legend-engine-pure-code-compiled-core + ${project.version} + + + org.finos.legend.engine + legend-engine-xt-relationalStore-postgresSqlModel-pure + ${project.version} + + + org.finos.legend.engine + legend-engine-xt-relationalStore-sqlDialectTranslation-pure + ${project.version} + + + + + maven-surefire-plugin + + false + + **/Test_Postgres_SDT*.java + **/SdtTestSuiteBuilder*.java + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + test-jar + + + + + + + + + + + org.finos.legend.pure + legend-pure-m4 + + + org.finos.legend.pure + legend-pure-m3-core + + + org.finos.legend.pure + legend-pure-runtime-java-engine-compiled + + + org.finos.legend.pure + legend-pure-runtime-java-engine-interpreted + + + org.finos.legend.pure + legend-pure-m2-store-relational-pure + + + org.finos.legend.pure + legend-pure-runtime-java-extension-interpreted-store-relational + + + org.finos.legend.pure + legend-pure-runtime-java-extension-compiled-store-relational + + + + + + org.finos.legend.engine + legend-engine-pure-platform-java + + + org.finos.legend.engine + legend-engine-pure-platform-store-relational-java + + + org.finos.legend.engine + legend-engine-pure-runtime-java-extension-compiled-functions-unclassified + + + org.finos.legend.engine + legend-engine-pure-code-compiled-core + + + org.finos.legend.engine + legend-engine-xt-relationalStore-postgresSqlModel-pure + + + org.finos.legend.engine + legend-engine-xt-relationalStore-sqlDialectTranslation-pure + + + org.finos.legend.engine + legend-engine-xt-relationalStore-protocol + + + org.finos.legend.engine + legend-engine-xt-relationalStore-executionPlan + + + org.finos.legend.engine + legend-engine-xt-relationalStore-executionPlan-connection + + + org.finos.legend.engine + legend-engine-xt-relationalStore-executionPlan-connection-authentication-default + + + + + org.eclipse.collections + eclipse-collections + + + org.eclipse.collections + eclipse-collections-api + + + + + junit + junit + + + org.finos.legend.engine + legend-engine-test-framework + test + + + org.finos.legend.engine + legend-engine-xt-relationalStore-postgres-PCT + test + + + + + \ No newline at end of file diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/java/org/finos/legend/engine/pure/runtime/relational/sdt/RunSqlDialectTestQueryHelper.java b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/java/org/finos/legend/engine/pure/runtime/relational/sdt/RunSqlDialectTestQueryHelper.java new file mode 100644 index 00000000000..baf051e5c95 --- /dev/null +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/java/org/finos/legend/engine/pure/runtime/relational/sdt/RunSqlDialectTestQueryHelper.java @@ -0,0 +1,96 @@ +// Copyright 2024 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.pure.runtime.relational.sdt; + +import org.eclipse.collections.api.RichIterable; +import org.eclipse.collections.api.block.function.Function; +import org.finos.legend.engine.authentication.LegendDefaultDatabaseAuthenticationFlowProvider; +import org.finos.legend.engine.authentication.LegendDefaultDatabaseAuthenticationFlowProviderConfiguration; +import org.finos.legend.engine.plan.execution.stores.relational.config.TemporaryTestDbConfiguration; +import org.finos.legend.engine.plan.execution.stores.relational.connection.manager.ConnectionManagerSelector; +import org.finos.legend.engine.plan.execution.stores.relational.connection.tests.api.TestConnectionIntegration; +import org.finos.legend.engine.plan.execution.stores.relational.connection.tests.api.TestConnectionIntegrationLoader; +import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.store.relational.connection.DatabaseType; +import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.store.relational.connection.RelationalDatabaseConnection; +import org.finos.legend.pure.m3.exception.PureExecutionException; + +import javax.security.auth.Subject; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Collections; +import java.util.Optional; + +public class RunSqlDialectTestQueryHelper +{ + private RunSqlDialectTestQueryHelper() + { + + } + + public static T runTestQueryAndTransformResultSet(String dbType, String testQuery, RichIterable setupSqls, RichIterable teardownSqls, Function resultSetTransformFunction) throws SQLException + { + TestConnectionIntegration found = TestConnectionIntegrationLoader.extensions().select(c -> c.getDatabaseType() == DatabaseType.valueOf(dbType)).getFirst(); + if (found == null) + { + throw new PureExecutionException("Can't find a TestConnectionIntegration for dbType " + dbType + ". Available ones are " + TestConnectionIntegrationLoader.extensions().collect(c -> c.getDatabaseType().name())); + } + RelationalDatabaseConnection relationalDatabaseConnection = found.getConnection(); + + Connection connection = null; + Statement statement = null; + try + { + LegendDefaultDatabaseAuthenticationFlowProvider flowProvider = new LegendDefaultDatabaseAuthenticationFlowProvider(); + flowProvider.configure(new LegendDefaultDatabaseAuthenticationFlowProviderConfiguration()); + ConnectionManagerSelector connectionManagerSelector = new ConnectionManagerSelector(new TemporaryTestDbConfiguration(-1), Collections.emptyList(), Optional.of(flowProvider)); + connection = connectionManagerSelector.getDatabaseConnection((Subject) null, relationalDatabaseConnection); + statement = connection.createStatement(); + + for (String s : setupSqls) + { + statement.execute(s); + } + + try (ResultSet resultSet = statement.executeQuery(testQuery)) + { + return resultSetTransformFunction.apply(resultSet); + } + } + finally + { + if (statement != null) + { + for (String s : teardownSqls) + { + try + { + statement.execute(s); + } + catch (Exception e) + { + // Run remaining teardown stmts without failing + System.out.println(e.getMessage()); + } + } + + statement.close(); + connection.close(); + } + } + } +} diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/java/org/finos/legend/engine/pure/runtime/relational/sdt/compiled/RunSqlDialectTestQueryCompiledExtension.java b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/java/org/finos/legend/engine/pure/runtime/relational/sdt/compiled/RunSqlDialectTestQueryCompiledExtension.java new file mode 100644 index 00000000000..7e525996f55 --- /dev/null +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/java/org/finos/legend/engine/pure/runtime/relational/sdt/compiled/RunSqlDialectTestQueryCompiledExtension.java @@ -0,0 +1,120 @@ +// Copyright 2024 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.pure.runtime.relational.sdt.compiled; + +import org.eclipse.collections.api.RichIterable; +import org.eclipse.collections.api.block.function.Function; +import org.eclipse.collections.api.factory.Lists; +import org.eclipse.collections.api.list.ListIterable; +import org.eclipse.collections.api.list.MutableList; +import org.eclipse.collections.impl.list.mutable.FastList; +import org.finos.legend.engine.pure.runtime.relational.sdt.RunSqlDialectTestQueryHelper; +import org.finos.legend.pure.generated.Root_meta_relational_metamodel_SQLNull_Impl; +import org.finos.legend.pure.generated.Root_meta_relational_metamodel_execute_ResultSet; +import org.finos.legend.pure.generated.Root_meta_relational_metamodel_execute_ResultSet_Impl; +import org.finos.legend.pure.generated.Root_meta_relational_metamodel_execute_Row; +import org.finos.legend.pure.generated.Root_meta_relational_metamodel_execute_Row_Impl; +import org.finos.legend.pure.m3.coreinstance.meta.relational.metamodel.SQLNull; +import org.finos.legend.pure.m3.exception.PureExecutionException; +import org.finos.legend.pure.m4.coreinstance.CoreInstance; +import org.finos.legend.pure.runtime.java.compiled.execution.CompiledExecutionSupport; +import org.finos.legend.pure.runtime.java.compiled.extension.BaseCompiledExtension; +import org.finos.legend.pure.runtime.java.compiled.generation.ProcessorContext; +import org.finos.legend.pure.runtime.java.compiled.generation.processors.natives.AbstractNative; +import org.finos.legend.pure.runtime.java.extension.store.relational.compiled.RelationalNativeImplementation; +import org.finos.legend.pure.runtime.java.extension.store.relational.compiled.natives.ResultSetValueHandlers; + +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.util.GregorianCalendar; +import java.util.TimeZone; + +public class RunSqlDialectTestQueryCompiledExtension extends BaseCompiledExtension +{ + public RunSqlDialectTestQueryCompiledExtension() + { + super( + "core_external_store_relational_sdt", + () -> Lists.fixedSize.with(new RunSqlDialectTestQuery()), + Lists.fixedSize.with(), + Lists.fixedSize.empty(), + Lists.fixedSize.empty()); + } + + public static class RunSqlDialectTestQuery extends AbstractNative + { + public RunSqlDialectTestQuery() + { + super("runSqlDialectTestQuery_String_1__String_1__String_MANY__String_MANY__ResultSet_1_"); + } + + @Override + public String build(CoreInstance topLevelElement, CoreInstance functionExpression, ListIterable transformedParams, ProcessorContext processorContext) + { + return "org.finos.legend.engine.pure.runtime.relational.sdt.compiled.RunSqlDialectTestQueryCompiledExtension.RunSqlDialectTestQuery.compileExec(" + + transformedParams.get(0) + ", " + // DB Type + transformedParams.get(1) + ", " + // Test Query + transformedParams.get(2) + ", " + // Setup Sqls + transformedParams.get(3) + ", " + // Teardown Sqls + "(CompiledExecutionSupport) es)"; + } + + public static Root_meta_relational_metamodel_execute_ResultSet compileExec(String dbType, String testQuery, RichIterable setupSqls, RichIterable teardownSqls, CompiledExecutionSupport es) + { + Function transformer = (resultSet) -> + { + try + { + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + Root_meta_relational_metamodel_execute_ResultSet pureResult = new Root_meta_relational_metamodel_execute_ResultSet_Impl(""); + SQLNull sqlNull = new Root_meta_relational_metamodel_SQLNull_Impl("SQLNull"); + + int count = resultSetMetaData.getColumnCount(); + MutableList columns = FastList.newList(count); + for (int i = 1; i <= count; i++) + { + String column = resultSetMetaData.getColumnLabel(i); + columns.add(column); + } + pureResult._columnNames(columns); + + ListIterable handlers = ResultSetValueHandlers.getHandlers(resultSetMetaData); + MutableList rows = FastList.newList(); + while (resultSet.next()) + { + MutableList rowValues = RelationalNativeImplementation.processRow(resultSet, handlers, sqlNull, new GregorianCalendar(TimeZone.getTimeZone("UTC"))); + rows.add((new Root_meta_relational_metamodel_execute_Row_Impl(""))._valuesAddAll(rowValues)._parent(pureResult)); + } + pureResult._rows(rows); + return pureResult; + } + catch (SQLException e) + { + throw new PureExecutionException(e); + } + }; + + try + { + return RunSqlDialectTestQueryHelper.runTestQueryAndTransformResultSet(dbType, testQuery, setupSqls, teardownSqls, transformer); + } + catch (SQLException e) + { + throw new PureExecutionException(e); + } + } + } +} diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/java/org/finos/legend/engine/pure/runtime/relational/sdt/interpreted/RunSqlDialectTestQueryInterpretedExtension.java b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/java/org/finos/legend/engine/pure/runtime/relational/sdt/interpreted/RunSqlDialectTestQueryInterpretedExtension.java new file mode 100644 index 00000000000..30ec8afd39a --- /dev/null +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/java/org/finos/legend/engine/pure/runtime/relational/sdt/interpreted/RunSqlDialectTestQueryInterpretedExtension.java @@ -0,0 +1,96 @@ +// Copyright 2024 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.pure.runtime.relational.sdt.interpreted; + +import org.eclipse.collections.api.block.function.Function; +import org.eclipse.collections.api.factory.Lists; +import org.eclipse.collections.api.list.ListIterable; +import org.eclipse.collections.api.map.MutableMap; +import org.eclipse.collections.impl.tuple.Tuples; +import org.finos.legend.engine.pure.runtime.relational.sdt.RunSqlDialectTestQueryHelper; +import org.finos.legend.pure.m3.compiler.Context; +import org.finos.legend.pure.m3.exception.PureExecutionException; +import org.finos.legend.pure.m3.navigation.Instance; +import org.finos.legend.pure.m3.navigation.M3Properties; +import org.finos.legend.pure.m3.navigation.ProcessorSupport; +import org.finos.legend.pure.m3.navigation.ValueSpecificationBootstrap; +import org.finos.legend.pure.m4.ModelRepository; +import org.finos.legend.pure.m4.coreinstance.CoreInstance; +import org.finos.legend.pure.runtime.java.extension.store.relational.interpreted.natives.ExecuteInDb; +import org.finos.legend.pure.runtime.java.interpreted.ExecutionSupport; +import org.finos.legend.pure.runtime.java.interpreted.FunctionExecutionInterpreted; +import org.finos.legend.pure.runtime.java.interpreted.VariableContext; +import org.finos.legend.pure.runtime.java.interpreted.extension.BaseInterpretedExtension; +import org.finos.legend.pure.runtime.java.interpreted.natives.InstantiationContext; +import org.finos.legend.pure.runtime.java.interpreted.natives.NativeFunction; +import org.finos.legend.pure.runtime.java.interpreted.profiler.Profiler; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Stack; + +public class RunSqlDialectTestQueryInterpretedExtension extends BaseInterpretedExtension +{ + public RunSqlDialectTestQueryInterpretedExtension() + { + super(Lists.fixedSize.with( + Tuples.pair("runSqlDialectTestQuery_String_1__String_1__String_MANY__String_MANY__ResultSet_1_", RunSqlDialectTestQuery::new) + )); + } + + public static class RunSqlDialectTestQuery extends NativeFunction + { + private final ModelRepository repository; + + public RunSqlDialectTestQuery(FunctionExecutionInterpreted functionExecution, ModelRepository repository) + { + this.repository = repository; + } + + @Override + public CoreInstance execute(ListIterable params, Stack> resolvedTypeParameters, Stack> resolvedMultiplicityParameters, VariableContext variableContext, CoreInstance functionExpressionToUseInStack, Profiler profiler, InstantiationContext instantiationContext, ExecutionSupport executionSupport, Context context, ProcessorSupport processorSupport) throws PureExecutionException + { + String dbType = Instance.getValueForMetaPropertyToOneResolved(params.get(0), M3Properties.values, processorSupport).getName(); + String testQuery = Instance.getValueForMetaPropertyToOneResolved(params.get(1), M3Properties.values, processorSupport).getName(); + ListIterable setupSqls = Instance.getValueForMetaPropertyToManyResolved(params.get(2), M3Properties.values, processorSupport).collect(CoreInstance::getName); + ListIterable teardownSqls = Instance.getValueForMetaPropertyToManyResolved(params.get(3), M3Properties.values, processorSupport).collect(CoreInstance::getName); + + Function transformer = (resultSet) -> + { + CoreInstance pureResult = repository.newAnonymousCoreInstance(functionExpressionToUseInStack.getSourceInformation(), processorSupport.package_getByUserPath("meta::relational::metamodel::execute::ResultSet")); + CoreInstance rowClassifier = processorSupport.package_getByUserPath("meta::relational::metamodel::execute::Row"); + Instance.addValueToProperty(pureResult, "connectionAcquisitionTimeInNanoSecond", this.repository.newIntegerCoreInstance(-1), processorSupport); + try + { + ExecuteInDb.createPureResultSetFromDatabaseResultSet(pureResult, resultSet, functionExpressionToUseInStack, rowClassifier, "UTC", repository, System.nanoTime(), 200, processorSupport); + return ValueSpecificationBootstrap.wrapValueSpecification(pureResult, true, processorSupport); + } + catch (SQLException e) + { + throw new PureExecutionException(functionExpressionToUseInStack.getSourceInformation(), e); + } + }; + + try + { + return RunSqlDialectTestQueryHelper.runTestQueryAndTransformResultSet(dbType, testQuery, setupSqls, teardownSqls, transformer); + } + catch (SQLException e) + { + throw new PureExecutionException(functionExpressionToUseInStack.getSourceInformation(), e); + } + } + } +} diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/java/org/finos/legend/pure/code/core/CoreExternalStoreRelationalSDTCodeRepositoryProvider.java b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/java/org/finos/legend/pure/code/core/CoreExternalStoreRelationalSDTCodeRepositoryProvider.java new file mode 100644 index 00000000000..43de61b8d9e --- /dev/null +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/java/org/finos/legend/pure/code/core/CoreExternalStoreRelationalSDTCodeRepositoryProvider.java @@ -0,0 +1,28 @@ +// Copyright 2024 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.pure.code.core; + +import org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepository; +import org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepositoryProvider; +import org.finos.legend.pure.m3.serialization.filesystem.repository.GenericCodeRepository; + +public class CoreExternalStoreRelationalSDTCodeRepositoryProvider implements CodeRepositoryProvider +{ + @Override + public CodeRepository repository() + { + return GenericCodeRepository.build("core_external_store_relational_sdt.definition.json"); + } +} diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/resources/META-INF/services/org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepositoryProvider b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/resources/META-INF/services/org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepositoryProvider new file mode 100644 index 00000000000..820cb9c5a7d --- /dev/null +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/resources/META-INF/services/org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepositoryProvider @@ -0,0 +1 @@ +org.finos.legend.pure.code.core.CoreExternalStoreRelationalSDTCodeRepositoryProvider \ No newline at end of file diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/resources/META-INF/services/org.finos.legend.pure.runtime.java.compiled.extension.CompiledExtension b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/resources/META-INF/services/org.finos.legend.pure.runtime.java.compiled.extension.CompiledExtension new file mode 100644 index 00000000000..80dbf8bd3fc --- /dev/null +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/resources/META-INF/services/org.finos.legend.pure.runtime.java.compiled.extension.CompiledExtension @@ -0,0 +1 @@ +org.finos.legend.engine.pure.runtime.relational.sdt.compiled.RunSqlDialectTestQueryCompiledExtension \ No newline at end of file diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/resources/META-INF/services/org.finos.legend.pure.runtime.java.interpreted.extension.InterpretedExtension b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/resources/META-INF/services/org.finos.legend.pure.runtime.java.interpreted.extension.InterpretedExtension new file mode 100644 index 00000000000..00470d693b3 --- /dev/null +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/resources/META-INF/services/org.finos.legend.pure.runtime.java.interpreted.extension.InterpretedExtension @@ -0,0 +1 @@ +org.finos.legend.engine.pure.runtime.relational.sdt.interpreted.RunSqlDialectTestQueryInterpretedExtension \ No newline at end of file diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/resources/core_external_store_relational_sdt.definition.json b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/resources/core_external_store_relational_sdt.definition.json new file mode 100644 index 00000000000..506802b8793 --- /dev/null +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/resources/core_external_store_relational_sdt.definition.json @@ -0,0 +1,19 @@ +{ + "name": "core_external_store_relational_sdt", + "pattern": "(meta::external::store::relational::sdt)(::.*)?", + "dependencies": [ + "platform", + "platform_dsl_store", + "platform_dsl_mapping", + "platform_dsl_path", + "platform_dsl_graph", + "platform_dsl_diagram", + "platform_store_relational", + "core_functions_standard", + "core_functions_unclassified", + "core_functions_json", + "core", + "core_external_store_relational_postgres_sql_model", + "core_external_store_relational_sql_dialect_translation" + ] +} \ No newline at end of file diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/resources/core_external_store_relational_sdt/sdtFramework.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/resources/core_external_store_relational_sdt/sdtFramework.pure new file mode 100644 index 00000000000..75a0898a3dc --- /dev/null +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/resources/core_external_store_relational_sdt/sdtFramework.pure @@ -0,0 +1,131 @@ +// Copyright 2024 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::external::query::sql::metamodel::*; +import meta::external::store::relational::sqlDialectTranslation::*; +import meta::external::store::relational::sdt::framework::*; +import meta::pure::extension::*; +import meta::pure::functions::meta::*; +import meta::json::*; + +// SDT - SQL Dialect Test + +native function meta::external::store::relational::sdt::framework::runSqlDialectTestQuery(dbType: String[1], testQuery: String[1], setupSqls: String[*], teardownSqls: String[*]): meta::relational::metamodel::execute::ResultSet[1]; + +function meta::external::store::relational::sdt::framework::runSqlDialect(sdt: SqlDialectTest[1], dbType: String[1], extensions: Extension[*]): Boolean[1] +{ + let testQuery = $sdt->generateTestSqlForSdtTestCase($dbType, $extensions); + let setupSqls = $sdt->generateSetupSqlsForSdtTestCase($dbType, $extensions); + let teardownSqls = $sdt->generateTeardownSqlsForSdtTestCase($dbType, $extensions); + let result = $dbType->runSqlDialectTestQuery($testQuery, $setupSqls, $teardownSqls)->testResultFromResultSet(); + $sdt->assertSdtTestPasses($result); +} + +Profile meta::external::store::relational::sdt::framework::SDT +{ + stereotypes : [test]; +} + +Class meta::external::store::relational::sdt::framework::SqlDialectTest +{ + setupStatements: Statement[*]; + teardownStatements: Statement[*]; + testQuery: Query[1]; + expectedResult: TestResult[1]; +} + +Class meta::external::store::relational::sdt::framework::TestResult +{ + <> columnNames: String[*]; + <> rows: TestResultRow[*]; +} + +Class meta::external::store::relational::sdt::framework::TestResultRow +{ + <> values: Any[*]; +} + +function meta::external::store::relational::sdt::framework::collectSDTTestsInPackage(pkg: String[1]): ConcreteFunctionDefinition<{->SqlDialectTest[1]}>[*] +{ + getAllPackageElements($pkg->pathToElement()->cast(@Package), true) + ->filter(x | $x->hasStereotype('test', SDT)) + ->map(x | $x->match([ + f: ConcreteFunctionDefinition<{->SqlDialectTest[1]}>[1] | $f, + a: Any[*] | $x->elementToPath() + ' element with stereotype SDT.test not a concrete function definition returning SqlDialectTest[1]'; []; + ])); +} + +function meta::external::store::relational::sdt::framework::getSqlDialectTest(func: ConcreteFunctionDefinition<{->SqlDialectTest[1]}>[1]): SqlDialectTest[1] +{ + $func->eval() +} + +function <> meta::external::store::relational::sdt::framework::generateSetupSqlsForSdtTestCase(sdt: SqlDialectTest[1], dbType: String[1], extensions: Extension[*]): String[*] +{ + $sdt.setupStatements->map(s | $s->generateSqlDialectForStatement(sdtTestSqlDialectTranslationConfig($dbType), $extensions)) +} + +function <> meta::external::store::relational::sdt::framework::generateTestSqlForSdtTestCase(sdt: SqlDialectTest[1], dbType: String[1], extensions: Extension[*]): String[1] +{ + $sdt.testQuery->generateSqlDialectForStatement(sdtTestSqlDialectTranslationConfig($dbType), $extensions); +} + +function <> meta::external::store::relational::sdt::framework::generateTeardownSqlsForSdtTestCase(sdt: SqlDialectTest[1], dbType: String[1], extensions: Extension[*]): String[*] +{ + $sdt.teardownStatements->map(s | $s->generateSqlDialectForStatement(sdtTestSqlDialectTranslationConfig($dbType), $extensions)) +} + +function <> meta::external::store::relational::sdt::framework::testResultFromResultSet(rs: meta::relational::metamodel::execute::ResultSet[1]): TestResult[1] +{ + ^TestResult + ( + columnNames = $rs.columnNames, + rows = $rs.rows->map(r | ^TestResultRow(values = $r.values)) + ) +} + +function <> meta::external::store::relational::sdt::framework::assertSdtTestPasses(sdt: SqlDialectTest[1], actualResult: TestResult[1]): Boolean[1] +{ + assertEquals($sdt.expectedResult, $actualResult, | 'Expected - ' + $sdt.expectedResult->toJSON(100) + '\n' + 'Actual - ' + $actualResult->toJSON(100)); +} + +function meta::external::store::relational::sdt::framework::testConfigForSimpleExpression(expression: meta::external::query::sql::metamodel::Expression[1], expected: Any[1]): SqlDialectTest[1] +{ + ^SqlDialectTest( + testQuery = ^Query( + queryBody = ^QuerySpecification( + select = ^Select( + distinct = false, + selectItems = ^SingleColumn( + expression = $expression, + alias = 'result' + ) + ) + ) + ), + expectedResult = ^TestResult( + columnNames = ['result'], + rows = [^TestResultRow(values = $expected)] + ) + ) +} + +function <> meta::external::store::relational::sdt::framework::sdtTestSqlDialectTranslationConfig(dbType: String[1]): SqlDialectTranslationConfig[1] +{ + ^SqlDialectTranslationConfig + ( + dbConfig = ^DbConfig(dbType = $dbType), + formatConfig = ^FormatConfig(pretty = false, upperCaseKeywords = true) + ) +} diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/resources/core_external_store_relational_sdt/sdtSuite/numberArithmeticSdtSuite.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/resources/core_external_store_relational_sdt/sdtSuite/numberArithmeticSdtSuite.pure new file mode 100644 index 00000000000..c3bf8b760d1 --- /dev/null +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/main/resources/core_external_store_relational_sdt/sdtSuite/numberArithmeticSdtSuite.pure @@ -0,0 +1,87 @@ +// Copyright 2024 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::external::query::sql::metamodel::*; +import meta::external::store::relational::sdt::framework::*; + +function <> meta::external::store::relational::sdt::suite::numberArithmetic::add(): SqlDialectTest[1] +{ + testConfigForSimpleExpression( + ^ArithmeticExpression(left = ^IntegerLiteral(value = 101), right = ^IntegerLiteral(value = 202), type = ArithmeticType.ADD), + 303 + ) +} + +function <> meta::external::store::relational::sdt::suite::numberArithmetic::subtract(): SqlDialectTest[1] +{ + testConfigForSimpleExpression( + ^ArithmeticExpression(left = ^IntegerLiteral(value = 101), right = ^IntegerLiteral(value = 202), type = ArithmeticType.SUBTRACT), + -101 + ) +} + +function <> meta::external::store::relational::sdt::suite::numberArithmetic::multiply(): SqlDialectTest[1] +{ + testConfigForSimpleExpression( + ^ArithmeticExpression(left = ^IntegerLiteral(value = 101), right = ^IntegerLiteral(value = 202), type = ArithmeticType.MULTIPLY), + 20402 + ) +} + +function <> meta::external::store::relational::sdt::suite::numberArithmetic::divide(): SqlDialectTest[1] +{ + testConfigForSimpleExpression( + ^ArithmeticExpression(left = ^IntegerLiteral(value = 101), right = ^IntegerLiteral(value = 202), type = ArithmeticType.DIVIDE), + 0.5 + ) +} + +function <> meta::external::store::relational::sdt::suite::numberArithmetic::divideComplexCase1(): SqlDialectTest[1] +{ + // 101 / (202 * 1.0) => 0.5 + testConfigForSimpleExpression( + ^ArithmeticExpression( + left = ^IntegerLiteral(value = 101), + right = ^ArithmeticExpression(left = ^IntegerLiteral(value = 202), right = ^DoubleLiteral(value = 1.0), type = ArithmeticType.MULTIPLY), + type = ArithmeticType.DIVIDE + ), + 0.5 + ) +} + +function <> meta::external::store::relational::sdt::suite::numberArithmetic::precedence1(): SqlDialectTest[1] +{ + // (2 * 3) + 4 => 10 + testConfigForSimpleExpression( + ^ArithmeticExpression( + left = ^ArithmeticExpression(left = ^IntegerLiteral(value = 2), right = ^IntegerLiteral(value = 3), type = ArithmeticType.MULTIPLY), + right = ^IntegerLiteral(value = 4), + type = ArithmeticType.ADD + ), + 10 + ) +} + +function <> meta::external::store::relational::sdt::suite::numberArithmetic::precedence2(): SqlDialectTest[1] +{ + // 2 * (3 + 4) => 14 + testConfigForSimpleExpression( + ^ArithmeticExpression( + left = ^IntegerLiteral(value = 2), + right = ^ArithmeticExpression(left = ^IntegerLiteral(value = 3), right = ^IntegerLiteral(value = 4), type = ArithmeticType.ADD), + type = ArithmeticType.MULTIPLY + ), + 14 + ) +} diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/test/java/org/finos/legend/engine/pure/code/core/Test_Pure_ExternalStoreRelationalSDT.java b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/test/java/org/finos/legend/engine/pure/code/core/Test_Pure_ExternalStoreRelationalSDT.java new file mode 100644 index 00000000000..c405e76a06c --- /dev/null +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/test/java/org/finos/legend/engine/pure/code/core/Test_Pure_ExternalStoreRelationalSDT.java @@ -0,0 +1,32 @@ +// Copyright 2024 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.pure.code.core; + +import junit.framework.TestSuite; +import org.finos.legend.pure.m3.execution.test.PureTestBuilder; +import org.finos.legend.pure.runtime.java.compiled.testHelper.PureTestBuilderCompiled; +import org.finos.legend.pure.m3.execution.test.TestCollection; +import org.finos.legend.pure.runtime.java.compiled.execution.CompiledExecutionSupport; + +public class Test_Pure_ExternalStoreRelationalSDT +{ + public static TestSuite suite() + { + CompiledExecutionSupport executionSupport = PureTestBuilderCompiled.getClassLoaderExecutionSupport(); + TestSuite suite = new TestSuite(); + suite.addTest(PureTestBuilderCompiled.buildSuite(TestCollection.collectTests("meta::external::store::relational::sdt", executionSupport.getProcessorSupport(), fn -> PureTestBuilderCompiled.generatePureTestCollection(fn, executionSupport), ci -> PureTestBuilder.satisfiesConditions(ci, executionSupport.getProcessorSupport())), executionSupport)); + return suite; + } +} diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/test/java/org/finos/legend/engine/relational/test/sdt/SdtTestSuiteBuilder.java b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/test/java/org/finos/legend/engine/relational/test/sdt/SdtTestSuiteBuilder.java new file mode 100644 index 00000000000..f752ded415e --- /dev/null +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/test/java/org/finos/legend/engine/relational/test/sdt/SdtTestSuiteBuilder.java @@ -0,0 +1,119 @@ +// Copyright 2024 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.relational.test.sdt; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import org.eclipse.collections.api.RichIterable; +import org.eclipse.collections.api.factory.Lists; +import org.eclipse.collections.api.factory.Sets; +import org.finos.legend.engine.plan.execution.stores.relational.connection.tests.api.TestConnectionIntegrationLoader; +import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.store.relational.connection.DatabaseType; +import org.finos.legend.engine.test.shared.framework.TestServerResource; +import org.finos.legend.pure.generated.*; +import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.function.ConcreteFunctionDefinition; +import org.finos.legend.pure.runtime.java.compiled.execution.CompiledExecutionSupport; +import org.junit.Assert; + +import java.util.Map; +import java.util.Set; +import java.util.function.Function; + +import static org.finos.legend.engine.test.shared.framework.PureTestHelperFramework.getClassLoaderExecutionSupport; +import static org.finos.legend.engine.test.shared.framework.PureTestHelperFramework.wrapSuite; +import static org.finos.legend.pure.generated.core_external_store_relational_sdt_sdtFramework.*; +import static org.finos.legend.pure.generated.platform_pure_essential_meta_graph_elementToPath.*; + +public class SdtTestSuiteBuilder +{ + private static final Set SDT_TEST_PACKAGES = Sets.fixedSize.of( + "meta::external::store::relational::sdt::suite" + ); + + public static Test buildSdtTestSuite(String dbType, Function> extensionsFunc, Map expectedErrors) + { + final CompiledExecutionSupport es = getClassLoaderExecutionSupport(); + RichIterable extensions = extensionsFunc.apply(es); + TestSuite suite = new TestSuite(); + SDT_TEST_PACKAGES.forEach(pkg -> + { + RichIterable> sdtTestInPackage = Root_meta_external_store_relational_sdt_framework_collectSDTTestsInPackage_String_1__ConcreteFunctionDefinition_MANY_(pkg, es); + sdtTestInPackage.forEach(x -> suite.addTest(new SDTTestCase(x, dbType, extensions, es, null))); + }); + return wrapSuite( + () -> true, + () -> suite, + () -> false, + Lists.mutable.with((TestServerResource) TestConnectionIntegrationLoader.extensions().select(c -> c.getDatabaseType() == DatabaseType.valueOf(dbType)).getFirst()) + ); + } + + public static final class SDTTestCase extends TestCase + { + ConcreteFunctionDefinition func; + String dbType; + RichIterable extensions; + CompiledExecutionSupport es; + String expectedError; + + public SDTTestCase() + { + } + + public SDTTestCase(ConcreteFunctionDefinition func, String dbType, RichIterable extensions, CompiledExecutionSupport es, String expectedError) + { + super(Root_meta_pure_functions_meta_elementToPath_PackageableElement_1__String_1_(func, es)); + this.dbType = dbType; + this.extensions = extensions; + this.func = func; + this.es = es; + this.expectedError = expectedError; + } + + @Override + protected void runTest() throws Throwable + { + System.out.print("EXECUTING " + this.getName() + " ... "); + long start = System.nanoTime(); + + boolean testPass = false; + try + { + Root_meta_external_store_relational_sdt_framework_runSqlDialect_SqlDialectTest_1__String_1__Extension_MANY__Boolean_1_( + Root_meta_external_store_relational_sdt_framework_getSqlDialectTest_ConcreteFunctionDefinition_1__SqlDialectTest_1_(this.func, this.es), + this.dbType, + this.extensions, + this.es + ); + testPass = true; + } + catch (Exception e) + { + if (expectedError != null) + { + Assert.assertEquals(expectedError, e.getMessage()); + testPass = true; + return; + } + throw e; + } + finally + { + System.out.format("%s (%.6fs)\n", (testPass ? "DONE" : "FAIL"), (System.nanoTime() - start) / 1_000_000_000.0); + } + } + } +} diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/test/java/org/finos/legend/engine/relational/test/sdt/postgres/Test_Postgres_SDT.java b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/test/java/org/finos/legend/engine/relational/test/sdt/postgres/Test_Postgres_SDT.java new file mode 100644 index 00000000000..a498466e0f9 --- /dev/null +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-SDT-pure/src/test/java/org/finos/legend/engine/relational/test/sdt/postgres/Test_Postgres_SDT.java @@ -0,0 +1,35 @@ +// Copyright 2024 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.relational.test.sdt.postgres; + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.eclipse.collections.api.factory.Lists; +import org.eclipse.collections.api.factory.Maps; +import org.finos.legend.engine.relational.test.sdt.SdtTestSuiteBuilder; + +import static org.finos.legend.pure.generated.core_external_store_relational_sql_dialect_translation_postgres_postgresSqlDialect.*; + +public class Test_Postgres_SDT extends TestSuite +{ + public static Test suite() + { + return SdtTestSuiteBuilder.buildSdtTestSuite( + "Postgres", + es -> Lists.immutable.of(Root_meta_external_store_relational_sqlDialectTranslation_postgres_postgresSqlDialectExtension__Extension_1_(es)), + Maps.mutable.empty() + ); + } +} diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-sqlDialectTranslation-pure/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-sqlDialectTranslation-pure/pom.xml index c51587fd897..9f7a1a726d7 100644 --- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-sqlDialectTranslation-pure/pom.xml +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-sqlDialectTranslation-pure/pom.xml @@ -123,13 +123,17 @@ org.finos.legend.pure legend-pure-runtime-java-engine-compiled + + + org.finos.legend.engine legend-engine-pure-platform-java - - - + + org.finos.legend.engine + legend-engine-pure-runtime-java-extension-compiled-functions-unclassified + org.finos.legend.engine legend-engine-pure-code-compiled-core diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-sqlDialectTranslation-pure/src/main/resources/core_external_store_relational_sql_dialect_translation.definition.json b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-sqlDialectTranslation-pure/src/main/resources/core_external_store_relational_sql_dialect_translation.definition.json index a79c88db8b3..649ebfe67ab 100644 --- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-sqlDialectTranslation-pure/src/main/resources/core_external_store_relational_sql_dialect_translation.definition.json +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-sqlDialectTranslation-pure/src/main/resources/core_external_store_relational_sql_dialect_translation.definition.json @@ -3,6 +3,15 @@ "pattern": "(meta::external::store::relational::sqlDialectTranslation)(::.*)?", "dependencies": [ "platform", + "platform_dsl_store", + "platform_dsl_mapping", + "platform_dsl_path", + "platform_dsl_graph", + "platform_dsl_diagram", + "platform_store_relational", + "core_functions_standard", + "core_functions_unclassified", + "core_functions_json", "core", "core_external_store_relational_postgres_sql_model" ] diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-sqlDialectTranslation-pure/src/main/resources/core_external_store_relational_sql_dialect_translation/defaults/sqlDialectDefaults.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-sqlDialectTranslation-pure/src/main/resources/core_external_store_relational_sql_dialect_translation/defaults/sqlDialectDefaults.pure new file mode 100644 index 00000000000..36d4f06b74b --- /dev/null +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-sqlDialectTranslation-pure/src/main/resources/core_external_store_relational_sql_dialect_translation/defaults/sqlDialectDefaults.pure @@ -0,0 +1,729 @@ +// Copyright 2024 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::external::query::sql::metamodel::*; +import meta::external::store::relational::sqlDialectTranslation::*; +import meta::external::store::relational::sqlDialectTranslation::defaults::*; +import meta::external::store::relational::sqlDialectTranslation::utils::*; + +Enum meta::external::store::relational::sqlDialectTranslation::defaults::SqlOperatorTypes_default +{ + DOT, // . + TYPECAST, // :: + ARRAY_ELEMENT_SELECTION, // [] + UNARY_PLUS_MINUS, // + , - + COLLATE, + AT, + EXPONENTIATION, // ^ + MULTIPLICATION_DIVISION_MODULO, // * , /, % + ADDITION_SUBTRACTION, // + , - + OTHER_NATIVE_USER_DEFINED_OPERATOR, + BETWEEN, + IN, + STRING_MATCH, // Like, Similar, Regex + BASIC_COMPARISON, // < > = <= >= <> + IS_CHECK, // IS NULL, IS NOT NULL, IS DISTINCT FROM etc. + NOT, + AND, + OR +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::findOperatorType_default(e: meta::external::query::sql::metamodel::Expression[1]): String[1] +{ + $e->match([ + {c: ComparisonExpression[1] | + if( + [ + pair(|$c.operator == ComparisonOperator.EQUAL, | SqlOperatorTypes_default.BASIC_COMPARISON), + pair(|$c.operator == ComparisonOperator.NOT_EQUAL, | SqlOperatorTypes_default.BASIC_COMPARISON), + pair(|$c.operator == ComparisonOperator.LESS_THAN, | SqlOperatorTypes_default.BASIC_COMPARISON), + pair(|$c.operator == ComparisonOperator.LESS_THAN_OR_EQUAL, | SqlOperatorTypes_default.BASIC_COMPARISON), + pair(|$c.operator == ComparisonOperator.GREATER_THAN, | SqlOperatorTypes_default.BASIC_COMPARISON), + pair(|$c.operator == ComparisonOperator.GREATER_THAN_OR_EQUAL, | SqlOperatorTypes_default.BASIC_COMPARISON), + pair(|$c.operator == ComparisonOperator.IS_DISTINCT_FROM, | SqlOperatorTypes_default.IS_CHECK), + pair(|$c.operator == ComparisonOperator.IS_NOT_DISTINCT_FROM, | SqlOperatorTypes_default.IS_CHECK), + pair(|$c.operator == ComparisonOperator.REGEX_MATCH, | SqlOperatorTypes_default.STRING_MATCH), + pair(|$c.operator == ComparisonOperator.REGEX_MATCH_CI, | SqlOperatorTypes_default.STRING_MATCH), + pair(|$c.operator == ComparisonOperator.REGEX_NO_MATCH, | SqlOperatorTypes_default.STRING_MATCH), + pair(|$c.operator == ComparisonOperator.REGEX_NO_MATCH_CI, | SqlOperatorTypes_default.STRING_MATCH), + pair(|$c.operator == ComparisonOperator.LIKE, | SqlOperatorTypes_default.STRING_MATCH), + pair(|$c.operator == ComparisonOperator.ILIKE, | SqlOperatorTypes_default.STRING_MATCH), + pair(|$c.operator == ComparisonOperator.NOT_LIKE, | SqlOperatorTypes_default.STRING_MATCH), + pair(|$c.operator == ComparisonOperator.NOT_ILIKE, | SqlOperatorTypes_default.STRING_MATCH) + ], + | fail('Unhandled comparator type: ' + $c.operator->toString()); SqlOperatorTypes_default.OTHER_NATIVE_USER_DEFINED_OPERATOR; + ); + }, + {l: LogicalBinaryExpression[1] | + if( + [ + pair(|$l.type == LogicalBinaryType.AND, | SqlOperatorTypes_default.AND), + pair(|$l.type == LogicalBinaryType.OR, | SqlOperatorTypes_default.OR) + ], + | fail('Unhandled logical binary expression type: ' + $l.type->toString()); SqlOperatorTypes_default.OTHER_NATIVE_USER_DEFINED_OPERATOR; + ); + }, + {l: NotExpression[1] | SqlOperatorTypes_default.NOT}, + {a: ArithmeticExpression[1] | + if( + [ + pair(|$a.type == ArithmeticType.ADD, | SqlOperatorTypes_default.ADDITION_SUBTRACTION), + pair(|$a.type == ArithmeticType.SUBTRACT, | SqlOperatorTypes_default.ADDITION_SUBTRACTION), + pair(|$a.type == ArithmeticType.MULTIPLY, | SqlOperatorTypes_default.MULTIPLICATION_DIVISION_MODULO), + pair(|$a.type == ArithmeticType.DIVIDE, | SqlOperatorTypes_default.MULTIPLICATION_DIVISION_MODULO), + pair(|$a.type == ArithmeticType.MODULUS, | SqlOperatorTypes_default.MULTIPLICATION_DIVISION_MODULO), + pair(|$a.type == ArithmeticType.POWER, | SqlOperatorTypes_default.EXPONENTIATION) + ], + | fail('Unhandled arithemtic expression type: ' + $a.type->toString()); SqlOperatorTypes_default.OTHER_NATIVE_USER_DEFINED_OPERATOR; + ); + }, + {q: QualifiedNameReference[1] | SqlOperatorTypes_default.DOT}, + {i: IsNullPredicate[1] | SqlOperatorTypes_default.IS_CHECK}, + {i: IsNotNullPredicate[1] | SqlOperatorTypes_default.IS_CHECK}, + {i: NegativeExpression[1] | SqlOperatorTypes_default.UNARY_PLUS_MINUS}, + {i: InPredicate[1] | SqlOperatorTypes_default.IN}, + {b: BetweenPredicate[1] | SqlOperatorTypes_default.BETWEEN}, + a: meta::external::query::sql::metamodel::Expression[1] | fail('Unknown expression type - ' + $e->class()->elementToPath()); SqlOperatorTypes_default.OTHER_NATIVE_USER_DEFINED_OPERATOR; + ])->toString() +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::operatorPrecedence_default(): Map[1] +{ + // https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-PRECEDENCE + + let operatorPrecedenceOrder = [ + SqlOperatorTypes_default.DOT->toString(), + SqlOperatorTypes_default.TYPECAST->toString(), + SqlOperatorTypes_default.ARRAY_ELEMENT_SELECTION->toString(), + SqlOperatorTypes_default.UNARY_PLUS_MINUS->toString(), + SqlOperatorTypes_default.COLLATE->toString(), + SqlOperatorTypes_default.AT->toString(), + SqlOperatorTypes_default.EXPONENTIATION->toString(), + SqlOperatorTypes_default.MULTIPLICATION_DIVISION_MODULO->toString(), + SqlOperatorTypes_default.ADDITION_SUBTRACTION->toString(), + SqlOperatorTypes_default.OTHER_NATIVE_USER_DEFINED_OPERATOR->toString(), + SqlOperatorTypes_default.BETWEEN->toString(), + SqlOperatorTypes_default.IN->toString(), + SqlOperatorTypes_default.STRING_MATCH->toString(), + SqlOperatorTypes_default.BASIC_COMPARISON->toString(), + SqlOperatorTypes_default.IS_CHECK->toString(), + SqlOperatorTypes_default.NOT->toString(), + SqlOperatorTypes_default.AND->toString(), + SqlOperatorTypes_default.OR->toString() + ]; + + $operatorPrecedenceOrder->zip($operatorPrecedenceOrder->size()->range())->newMap(); +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::identifierProcessor_default(): IdentifierProcessor[1] +{ + identifierProcessor + ( + {sqlDialect, identifier, shouldQuote, state, config | + if ($shouldQuote || $identifier->in($sqlDialect.keywords), + | if ($sqlDialect.quoteConfig->isEmpty(), + | // Quoting configuration unknown. Hence returning the identifier as is + $identifier, + | let quoteCfg = $sqlDialect.quoteConfig->toOne(); + $quoteCfg.start + $identifier->replace($quoteCfg.end, $quoteCfg.escape) + $quoteCfg.end; + ), + | $identifier + ) + } + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::integerLiteralNodeProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + IntegerLiteral, + {sqlDialect, i, state, config | + $i.value->toString() + }, + {n | true} + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::stringLiteralNodeProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + StringLiteral, + {sqlDialect, s, state, config | + '\'' + $s.value->replace('\'', '\'\'') + '\'' + }, + {n | true} + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::booleanLiteralNodeProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + BooleanLiteral, + {sqlDialect, s, state, config | + $sqlDialect->keyword(if($s.value , | 'true', | 'false'), $state, $config) + }, + {n | true} + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::longLiteralNodeProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + LongLiteral, + {sqlDialect, l, state, config | + $l.value->toString() + }, + {n | true} + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::doubleLiteralNodeProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + DoubleLiteral, + {sqlDialect, d, state, config | + $d.value->toString() + }, + {n | true} + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::nullLiteralNodeProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + NullLiteral, + {sqlDialect, d, state, config | + $sqlDialect->keyword('null', $state, $config) + }, + {n | true} + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::allColumnsNodeProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + AllColumns, + {sqlDialect, a, state, config | + let prefix = if ($a.prefix->isNotEmpty(), | $sqlDialect->executeIdentifierProcessor($a.prefix->toOne(), false, $state, $config) + '.', | ''); + $prefix + '*'; + } + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::singleColumnNodeProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + SingleColumn, + {sqlDialect, s, state, config | + let suffix = if ($s.alias->isNotEmpty(), + | ' ' + $sqlDialect->keyword('as', $state, $config) + ' ' + $sqlDialect->executeIdentifierProcessor($s.alias->toOne(), false, $state, $config), + | '' + ); + $sqlDialect->executeNodeProcessor($s.expression, $state, $config) + $suffix; + } + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::comparisonExpressionNodeProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + ComparisonExpression, + {sqlDialect, c, state, config | + let leftExpr = $sqlDialect->executeNodeProcessor($c.left, $c, $state, $config); + let rightExpr = $sqlDialect->executeNodeProcessor($c.right, $c, $state, $config); + let comparator = if( + [ + pair(|$c.operator == ComparisonOperator.EQUAL, | '='), + pair(|$c.operator == ComparisonOperator.NOT_EQUAL, | '<>'), + pair(|$c.operator == ComparisonOperator.LESS_THAN, | '<'), + pair(|$c.operator == ComparisonOperator.LESS_THAN_OR_EQUAL, | '<='), + pair(|$c.operator == ComparisonOperator.GREATER_THAN, | '>'), + pair(|$c.operator == ComparisonOperator.GREATER_THAN_OR_EQUAL, | '>='), + pair(|$c.operator == ComparisonOperator.IS_DISTINCT_FROM, | $sqlDialect->keyword('is distinct from', $state, $config)), + pair(|$c.operator == ComparisonOperator.IS_NOT_DISTINCT_FROM, | $sqlDialect->keyword('is not distinct from', $state, $config)), + pair(|$c.operator == ComparisonOperator.REGEX_MATCH, | '~'), + pair(|$c.operator == ComparisonOperator.REGEX_MATCH_CI, | '~*'), + pair(|$c.operator == ComparisonOperator.REGEX_NO_MATCH, | '!~'), + pair(|$c.operator == ComparisonOperator.REGEX_NO_MATCH_CI, | '!~*'), + pair(|$c.operator == ComparisonOperator.LIKE, | '~~'), + pair(|$c.operator == ComparisonOperator.ILIKE, | '~~*'), + pair(|$c.operator == ComparisonOperator.NOT_LIKE, | '!~~'), + pair(|$c.operator == ComparisonOperator.NOT_ILIKE, | '!~~*') + ], + | failWithMessage('Unhandled comparator type: ' + $c.operator->toString()) + ); + + $leftExpr + ' ' + $comparator + ' ' + $rightExpr; + } + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::logicalBinaryExpressionNodeProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + LogicalBinaryExpression, + {sqlDialect, l, state, config | + let leftExpr = $sqlDialect->executeNodeProcessor($l.left, $l, $state, $config); + let rightExpr = $sqlDialect->executeNodeProcessor($l.right, $l, $state, $config); + if( + [ + pair(|$l.type == LogicalBinaryType.AND, | $leftExpr + ' ' + $sqlDialect->keyword('and', $state, $config) + ' ' + $rightExpr;), + pair(|$l.type == LogicalBinaryType.OR, | $leftExpr + ' ' + $sqlDialect->keyword('or', $state, $config) + ' ' + $rightExpr;) + ], + | failWithMessage('Unhandled binary expression type: ' + $l.type->toString()) + ); + } + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::notExpressionNodeProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + NotExpression, + {sqlDialect, e, state, config | + $sqlDialect->keyword('not', $state, $config) + ' ' + $sqlDialect->executeNodeProcessor($e.value, $e, $state, $config) + } + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::arithmeticExpressionNodeProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + ArithmeticExpression, + {sqlDialect, a, state, config | + let isDivide = $a->isDivideExpr(); + let castAsDecimalIfDivide = {e: meta::external::query::sql::metamodel::Expression[1] | + if ($isDivide, | ^Cast(type = ^ColumnType(name = 'decimal'), expression = $e), | $e) + }; + let leftExpr = $sqlDialect->executeNodeProcessor($castAsDecimalIfDivide->eval($a.left), $a, $state, $config); + let rightExpr = $sqlDialect->executeNodeProcessor($castAsDecimalIfDivide->eval($a.right), $a, $state, $config); + let operator = if( + [ + pair(|$a.type == ArithmeticType.ADD, | '+'), + pair(|$a.type == ArithmeticType.SUBTRACT, | '-'), + pair(|$a.type == ArithmeticType.MULTIPLY, | '*'), + pair(|$a.type == ArithmeticType.DIVIDE, | '/'), + pair(|$a.type == ArithmeticType.MODULUS, | '%'), + pair(|$a.type == ArithmeticType.POWER, | '^') + ], + | failWithMessage('Unhandled arithmetic operator type: ' + $a.type->toString()) + ); + + $leftExpr + ' ' + $operator + ' ' + $rightExpr; + } + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::qualifiedNameReferenceNodeProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + QualifiedNameReference, + {sqlDialect, q, state, config | + $sqlDialect->qualifiedName($q.name, $state, $config) + } + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::isNullPredicateNodeProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + IsNullPredicate, + {sqlDialect, e, state, config | + $sqlDialect->executeNodeProcessor($e.value, $e, $state, $config) + ' ' + $sqlDialect->keyword('is null', $state, $config) + } + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::isNotNullPredicateNodeProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + IsNotNullPredicate, + {sqlDialect, e, state, config | + $sqlDialect->executeNodeProcessor($e.value, $e, $state, $config) + ' ' + $sqlDialect->keyword('is not null', $state, $config) + } + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::negativeNodeProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + NegativeExpression, + {sqlDialect, e, state, config | + '-' + $sqlDialect->executeNodeProcessor($e.value, $e, $state, $config) + } + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::currentTimeNodeProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + CurrentTime, + {sqlDialect, c, state, config | + let type = if( + [ + pair(|$c.type == CurrentTimeType.TIME, | $sqlDialect->keyword('current_time', $state, $config)), + pair(|$c.type == CurrentTimeType.TIMESTAMP, | $sqlDialect->keyword('current_timestamp', $state, $config)), + pair(|$c.type == CurrentTimeType.DATE, | $sqlDialect->keyword('current_date', $state, $config)) + ], + | failWithMessage('Unhandled current time type: ' + $c.type->toString()) + ); + let precision = if ($c.precision->isNotEmpty(), | '(' + $c.precision->toOne()->toString() + ')', | ''); + $type + $precision; + }, + {n | true} + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::whenClauseNodeProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + WhenClause, + {sqlDialect, w, state, config | + let sep0 = $state.separator(0, $config); + let sep1 = $state.separator(1, $config); + $sqlDialect->keyword('when', $state, $config) + $sep1 + $sqlDialect->executeNodeProcessor($w.operand, [], $state->increaseLevel(), $config) + + $sep0 + $sqlDialect->keyword('then', $state, $config) + $sep1 + $sqlDialect->executeNodeProcessor($w.result, [], $state->increaseLevel(), $config); + }, + {n | true} + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::searchedCaseExpressionNodeProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + SearchedCaseExpression, + {sqlDialect, c, state, config | + let sep0 = $state.separator(0, $config); + let sep1 = $state.separator(1, $config); + let sep2 = $state.separator(2, $config); + let default = if ($c.defaultValue->isNotEmpty(), + | $sep1 + $sqlDialect->keyword('else', $state, $config) + + $sep2 + $sqlDialect->executeNodeProcessor($c.defaultValue->toOne(), [], $state->increaseLevel()->increaseLevel(), $config), + | '' + ); + let whenClauses = $c.whenClauses->map(w | $sqlDialect->executeNodeProcessor($w, [], $state->increaseLevel(), $config))->joinStrings($sep1); + $sqlDialect->keyword('case', $state, $config) + $sep1 + $whenClauses + $default + $sep0 + $sqlDialect->keyword('end', $state, $config); + }, + {n | true} + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::columnTypeProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + ColumnType, + {sqlDialect, c, state, config | + $sqlDialect->keyword($c.name, $state, $config) + + if ($c.parameters->isNotEmpty(), | $c.parameters->map(p | $p->toString())->joinStrings('(', ', ', ')'), | ''); + }, + {n | true} + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::castProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + Cast, + {sqlDialect, c, state, config | + $sqlDialect->keyword('cast', $state, $config) + '(' + $sqlDialect->executeNodeProcessor($c.expression, [], $state, $config) + ' ' + + $sqlDialect->keyword('as', $state, $config) + ' ' + $sqlDialect->executeNodeProcessor($c.type, [], $state, $config) + ')' + }, + {n | true} + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::inListExpressionProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + InListExpression, + {sqlDialect, l, state, config | + let sep0 = $state.separator(0, $config); + let sep1 = $state.separator(1, $config); + let whenClauses = $l.values->map(v | $sqlDialect->executeNodeProcessor($v, [], $state->increaseLevel(), $config))->joinStrings(',' + $sep1); + '(' + $sep1 + $whenClauses + $sep0 + ')'; + }, + {n | true} + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::inPredicateProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + InPredicate, + {sqlDialect, i, state, config | + $sqlDialect->executeNodeProcessor($i.value, $i, $state, $config) + ' ' + $sqlDialect->keyword('in', $state, $config) + ' ' + + $sqlDialect->executeNodeProcessor($i.valueList, $i, $state, $config) + } + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::extractProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + Extract, + {sqlDialect, e, state, config | + $sqlDialect->keyword('extract', $state, $config) + '(' + $sqlDialect->keyword($e.field.name->toLower(), $state, $config) + ' ' + + $sqlDialect->keyword('from', $state, $config) + ' ' + $sqlDialect->executeNodeProcessor($e.expression, [], $state, $config) + ')'; + }, + {n | true} + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::betweenPredicateProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + BetweenPredicate, + {sqlDialect, b, state, config | + $sqlDialect->executeNodeProcessor($b.value, $b, $state, $config) + ' ' + $sqlDialect->keyword('between', $state, $config) + ' ' + + $sqlDialect->executeNodeProcessor($b.min, $b, $state, $config) + ' ' + $sqlDialect->keyword('and', $state, $config) + ' ' + $sqlDialect->executeNodeProcessor($b.max, $b, $state, $config); + } + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::sortItemProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + SortItem, + {sqlDialect, s, state, config | + $sqlDialect->executeNodeProcessor($s.sortKey, [], $state, $config) + ' ' + + if( + [ + pair(|$s.ordering == SortItemOrdering.ASCENDING, | $sqlDialect->keyword('asc', $state, $config)), + pair(|$s.ordering == SortItemOrdering.DESCENDING, | $sqlDialect->keyword('desc', $state, $config)) + ], + | failWithMessage('Unhandled sort item ordering type: ' + $s.ordering->toString()) + ) + + if( + [ + pair(|$s.nullOrdering == SortItemNullOrdering.FIRST, | ' ' + $sqlDialect->keyword('nulls first', $state, $config)), + pair(|$s.nullOrdering == SortItemNullOrdering.LAST, | ' ' + $sqlDialect->keyword('nulls last', $state, $config)), + pair(|$s.nullOrdering == SortItemNullOrdering.UNDEFINED, | '') + ], + | failWithMessage('Unhandled sort item null ordering type: ' + $s.nullOrdering->toString()) + ); + } + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::windowProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + meta::external::query::sql::metamodel::Window, + {sqlDialect, w, state, config | + let sep0 = $state.separator(0, $config); + let sep1 = $state.separator(1, $config); + if ($w.windowRef->isNotEmpty(), + | $w.windowRef->toOne(), + | let partitions = if ($w.partitions->isNotEmpty(), + | $sqlDialect->keyword('partition by', $state, $config) + $sep1 + $w.partitions->map(p | $sqlDialect->executeNodeProcessor($p, [], $state->increaseLevel(), $config))->joinStrings(',' + $sep1), + | '' + ); + let orderBy = if ($w.orderBy->isNotEmpty(), + | let sep = if ($w.partitions->isNotEmpty(), | $sep0, | ''); + $sep + $sqlDialect->keyword('order by', $state, $config) + $sep1 + $w.orderBy->map(o | $sqlDialect->executeNodeProcessor($o, [], $state->increaseLevel(), $config))->joinStrings(',' + $sep1);, + | '' + ); + assert($w.windowFrame->isEmpty(), | 'Window frame processing not implemented yet'); + $partitions + $orderBy; + ); + } + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::functionCallProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + FunctionCall, + {sqlDialect, f, state, config | + assert($f.distinct == false, | 'Distinct function call processing not implemented yet'); + assert($f.filter->isEmpty(), | 'Filtered function call processing not implemented yet'); + assert($f.group->isEmpty(), | 'Grouped function call processing not implemented yet'); + assert($f.orderBy->isEmpty(), | 'Sorted function call processing not implemented yet'); + + let sep0 = $state.separator(0, $config); + let sep1 = $state.separator(1, $config); + + $sqlDialect->qualifiedName($f.name, $state, $config) + '(' + if($f.arguments->isEmpty(), | '', | $sep1) + + $f.arguments->map(a | $sqlDialect->executeNodeProcessor($a, [], $state->increaseLevel(), $config))->joinStrings(',' + $sep1) + + + if($f.arguments->isEmpty(), | '', | $sep0) + ')' + + if ($f.window->isNotEmpty(), + | ' ' + $sqlDialect->keyword('over', $state, $config) + ' (' + $sep1 + $sqlDialect->executeNodeProcessor($f.window->toOne(), [], $state->increaseLevel(), $config) + $sep0 + ')', + | '' + ); + }, + {n | true} + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::tableProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + Table, + {sqlDialect, t, state, config | + $sqlDialect->qualifiedName($t.name, $state, $config) + } + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::aliasedRelationProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + AliasedRelation, + {sqlDialect, a, state, config | + $sqlDialect->executeNodeProcessor($a.relation, $state, $config) + ' ' + $sqlDialect->keyword('as', $state, $config) + ' ' + + $sqlDialect->executeIdentifierProcessor($a.alias, false, $state, $config) + } + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::joinProcessor_default(): NodeProcessor[1] +{ + nodeProcessor( + Join, + {sqlDialect, j, state, config | + let sep0 = $state.separator(0, $config); + let sep1 = $state.separator(1, $config); + let left = $sqlDialect->executeNodeProcessor($j.left, $state, $config); + let right = $sqlDialect->executeNodeProcessor($j.right, $state->increaseLevel(), $config); + let type = if( + [ + pair(|$j.type == JoinType.CROSS, | $sqlDialect->keyword('cross join', $state, $config)), + pair(|$j.type == JoinType.LEFT, | $sqlDialect->keyword('left outer join', $state, $config)), + pair(|$j.type == JoinType.RIGHT, | $sqlDialect->keyword('right outer join', $state, $config)), + pair(|$j.type == JoinType.INNER, | $sqlDialect->keyword('inner join', $state, $config)) + ], + | failWithMessage('Unhandled join type: ' + $j.type->toString()) + ); + let isNaturalJoin = $j.criteria->isNotEmpty() && $j.criteria->toOne()->instanceOf(NaturalJoin); + + $left + $sep0 + if($isNaturalJoin, | $sqlDialect->keyword('natural', $state, $config) + ' ', | '') + $type + + $sep1 + $right + + if ($j.criteria->isNotEmpty() && (!$isNaturalJoin), + | $sep1 + $sqlDialect->keyword('on', $state, $config) + ' ' + + $j.criteria->toOne()->match([ + o: JoinOn[1] | '(' + $sqlDialect->executeNodeProcessor($o.expression, $state, $config) + ')', + a: Any[*] | failWithMessage('Unhandled join criteria: ' + $a->class()->elementToPath()) + ]), + | '' + ); + } + ) +} + +function meta::external::store::relational::sqlDialectTranslation::defaults::selectProcessor_default(): NodeProcessor