diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cb4adb45..2b226161 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -51,7 +51,6 @@ jobs: with: path: | ${{ github.workspace }}/core/target/scala-${{ matrix.scalaShort }}/jacoco/report/jacoco.xml - ${{ github.workspace }}/examples/target/scala-${{ matrix.scalaShort }}/jacoco/report/jacoco.xml ${{ github.workspace }}/slick/target/scala-${{ matrix.scalaShort }}/jacoco/report/jacoco.xml ${{ github.workspace }}/doobie/target/scala-${{ matrix.scalaShort }}/jacoco/report/jacoco.xml key: ${{ runner.os }}-${{ matrix.scalaShort }}-${{ hashFiles('**/jacoco.xml') }} @@ -79,7 +78,6 @@ jobs: with: path: | ${{ github.workspace }}/core/target/scala-${{ matrix.scalaShort }}/jacoco/report/jacoco.xml - ${{ github.workspace }}/examples/target/scala-${{ matrix.scalaShort }}/jacoco/report/jacoco.xml ${{ github.workspace }}/slick/target/scala-${{ matrix.scalaShort }}/jacoco/report/jacoco.xml ${{ github.workspace }}/doobie/target/scala-${{ matrix.scalaShort }}/jacoco/report/jacoco.xml key: ${{ runner.os }}-${{ matrix.scalaShort }}-${{ hashFiles('**/jacoco.xml') }} @@ -95,7 +93,6 @@ jobs: ${{ github.workspace }}/core/target/scala-${{ matrix.scalaShort }}/jacoco/report/jacoco.xml, ${{ github.workspace }}/slick/target/scala-${{ matrix.scalaShort }}/jacoco/report/jacoco.xml, ${{ github.workspace }}/doobie/target/scala-${{ matrix.scalaShort }}/jacoco/report/jacoco.xml - # examples don't need code coverage - at least not now token: ${{ secrets.GITHUB_TOKEN }} min-coverage-overall: ${{ matrix.overall }} min-coverage-changed-files: ${{ matrix.changed }} diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml new file mode 100644 index 00000000..09bde58f --- /dev/null +++ b/.github/workflows/integration_tests.yml @@ -0,0 +1,61 @@ +# +# Copyright 2022 ABSA Group Limited +# +# 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: Run Integration Tests + +on: + pull_request: + branches: + - '**' + types: [ opened, synchronize, reopened ] + +jobs: + run-it: + runs-on: ubuntu-latest + services: + postgres: + image: postgres:15 + env: + POSTGRES_PASSWORD: postgres + POSTGRES_DB: movies + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 + strategy: + matrix: + scala: [ 2.12.17, 2.13.12 ] + steps: + - name: Checkout code + uses: actions/checkout@v2 + - uses: coursier/cache-action@v5 + + - name: Setup Scala + uses: olafurpg/setup-scala@v14 + with: + java-version: "adopt@1.8" + + - name: Prepare testing database + run: sbt flywayMigrate + + - name: Build and run IT tests for Doobie + run: sbt "project faDBDoobie" ++${{matrix.scala}} it:test + + - name: Build and run IT tests for Slick + run: sbt "project faDBSlick" ++${{matrix.scala}} it:test diff --git a/README.md b/README.md index f3622d12..6cb799cf 100644 --- a/README.md +++ b/README.md @@ -171,11 +171,11 @@ Code coverage will be generated on path: ### Integration tests -There are now integration tests as part of the project (at the time of writing they are in the _Slick_ module). +There are now integration tests as part of the project (at the time of writing they are in +the _Slick_ and _Doobie_ modules). -For the tests to work properly a running Postgres instance is needed. And then the following setup: -* execute (content of) all `*.sql` files within `it/resources/sql/` folder within a posgres query tool -* modify `it/resources/application.conf` to point to the database used in the previous point +For the tests to work properly a running Postgres instance is needed as well as all DB objects must be placed on the DB. +We automated this process, see `database/README.md` for more details. How to execute the tests: @@ -185,4 +185,4 @@ sbt it:test ## How to Release -Please see [this file](RELEASE.md) for more details. \ No newline at end of file +Please see [this file](RELEASE.md) for more details. diff --git a/build.sbt b/build.sbt index 494eb38e..f52fc254 100644 --- a/build.sbt +++ b/build.sbt @@ -48,8 +48,16 @@ lazy val commonJacocoReportSettings: JacocoReportSettings = JacocoReportSettings lazy val commonJacocoExcludes: Seq[String] = Seq( ) +enablePlugins(FlywayPlugin) +flywayUrl := FlywayConfiguration.flywayUrl +flywayUser := FlywayConfiguration.flywayUser +flywayPassword := FlywayConfiguration.flywayPassword +flywayLocations := FlywayConfiguration.flywayLocations +flywaySqlMigrationSuffixes := FlywayConfiguration.flywaySqlMigrationSuffixes +libraryDependencies ++= flywayDependencies + lazy val parent = (project in file(".")) - .aggregate(faDbCore, faDBSlick, faDBDoobie, faDBExamples) + .aggregate(faDbCore, faDBSlick, faDBDoobie) .settings( name := "root", libraryDependencies ++= rootDependencies(scalaVersion.value), @@ -102,18 +110,4 @@ lazy val faDBDoobie = (project in file("doobie")) jacocoExcludes := commonJacocoExcludes ) -lazy val faDBExamples = (project in file("examples")) - .configs(IntegrationTest) - .settings( - name := "examples", - libraryDependencies ++= examplesDependencies(scalaVersion.value), - Test / parallelExecution := false, - (Compile / compile) := ((Compile / compile) dependsOn printScalaVersion).value, // printScalaVersion is run with compile - publish / skip := true - ).dependsOn(faDbCore, faDBSlick) - .settings( - jacocoReportSettings := commonJacocoReportSettings.withTitle(s"fa-db:examples Jacoco Report - scala:${scalaVersion.value}"), - jacocoExcludes := commonJacocoExcludes - ) - sonatypeProfileName := "za.co.absa" diff --git a/demo_database/README.md b/demo_database/README.md new file mode 100644 index 00000000..a83bc41b --- /dev/null +++ b/demo_database/README.md @@ -0,0 +1,41 @@ +## About + +This module implements a simple database with many types of objects (tables, functions, data insertions, and more) +that will be used in integration tests in these modules: +* `doobie/src/it/` +* `slick/src/it/` + +## Deployment + +How to set up database for local testing + +### Using Docker + +```zsh +# start up postgres docker container (optional; instead you can create movies on your local postgres instance) +docker run --name=movies -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=movies -p 5432:5432 -d postgres:16 + +# migrate scripts +sbt flywayMigrate + +# kill & remove docker container (optional; only if using dockerized postgres instance) +docker kill aul_db +docker rm aul_db +``` + +### Using local postgres instance + +```zsh +# migrate scripts +sbt flywayMigrate +``` + +In case some structures are already present in the database, you can use +```zsh +sbt flywayClean +``` +to remove them or +```zsh +sbt flywayBaseline +``` +to set the current state as the baseline. diff --git a/demo_database/src/main/postgres/00_databases.ddl b/demo_database/src/main/postgres/00_databases.ddl new file mode 100644 index 00000000..389381a7 --- /dev/null +++ b/demo_database/src/main/postgres/00_databases.ddl @@ -0,0 +1,19 @@ +/* + * Copyright 2021 ABSA Group Limited + * + * 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. + */ + +CREATE DATABASE movies + WITH + ENCODING = 'UTF8' + CONNECTION LIMIT = -1; diff --git a/demo_database/src/main/postgres/V1.1.1__01_add_extensions.ddl b/demo_database/src/main/postgres/V1.1.1__01_add_extensions.ddl new file mode 100644 index 00000000..080b5751 --- /dev/null +++ b/demo_database/src/main/postgres/V1.1.1__01_add_extensions.ddl @@ -0,0 +1,18 @@ +/* + * Copyright 2021 ABSA Group Limited + * + * 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. + */ + +CREATE EXTENSION IF NOT EXISTS hstore; +CREATE EXTENSION IF NOT EXISTS ltree; +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- for function `uuid_generate_v4` diff --git a/demo_database/src/main/postgres/integration/V1.2.10__get_all_date_time_types.sql b/demo_database/src/main/postgres/integration/V1.2.10__get_all_date_time_types.sql new file mode 100644 index 00000000..8aab6fa7 --- /dev/null +++ b/demo_database/src/main/postgres/integration/V1.2.10__get_all_date_time_types.sql @@ -0,0 +1,44 @@ +/* + * Copyright 2022 ABSA Group Limited + * + * 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. + */ + +CREATE OR REPLACE FUNCTION integration.get_all_date_time_types(p_id INT) + RETURNS TABLE( + offset_date_time TIMESTAMPTZ, + instant TIMESTAMPTZ, + zoned_date_time TIMESTAMPTZ, + local_date_time TIMESTAMP, + local_date DATE, + local_time TIME, + sql_date DATE, + sql_time TIME, + sql_timestamp TIMESTAMP, + util_date TIMESTAMP + ) AS $$ +BEGIN + RETURN QUERY SELECT + T.offset_date_time, + T.instant, + T.zoned_date_time, + T.local_date_time, + T.local_date, + T.local_time, + T.sql_date, + T.sql_time, + T.sql_timestamp, + T.util_date + FROM integration.date_time_types T limit p_id; +END; +$$ LANGUAGE plpgsql; diff --git a/demo_database/src/main/postgres/integration/V1.2.11__insert_dates_times.sql b/demo_database/src/main/postgres/integration/V1.2.11__insert_dates_times.sql new file mode 100644 index 00000000..d222293c --- /dev/null +++ b/demo_database/src/main/postgres/integration/V1.2.11__insert_dates_times.sql @@ -0,0 +1,62 @@ +/* + * Copyright 2022 ABSA Group Limited + * + * 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. + */ + +CREATE OR REPLACE FUNCTION integration.insert_dates_times( + IN p_offset_date_time TIMESTAMPTZ, + IN p_instant TIMESTAMPTZ, + IN p_zoned_date_time TIMESTAMPTZ, + IN p_local_date_time TIMESTAMP, + IN p_local_date DATE, + IN p_local_time TIME, + IN p_sql_date DATE, + IN p_sql_time TIME, + IN p_sql_timestamp TIMESTAMP, + IN p_util_date DATE, + OUT status INTEGER, + OUT status_text TEXT, + OUT o_id INTEGER +) RETURNS record AS $$ +BEGIN + INSERT INTO integration.date_time_types ( + offset_date_time, + instant, + zoned_date_time, + local_date_time, + local_date, + local_time, + sql_date, + sql_time, + sql_timestamp, + util_date + ) VALUES ( + p_offset_date_time, + p_instant, + p_zoned_date_time, + p_local_date_time, + p_local_date, + p_local_time, + p_sql_date, + p_sql_time, + p_sql_timestamp, + p_util_date + ) RETURNING id INTO o_id; + + status := 11; + status_text := 'OK'; + + RETURN; +END; +$$ LANGUAGE plpgsql; diff --git a/doobie/src/it/database/other_types.sql b/demo_database/src/main/postgres/integration/V1.2.12__insert_other_types.sql similarity index 58% rename from doobie/src/it/database/other_types.sql rename to demo_database/src/main/postgres/integration/V1.2.12__insert_other_types.sql index df3359d1..29f94f8e 100644 --- a/doobie/src/it/database/other_types.sql +++ b/demo_database/src/main/postgres/integration/V1.2.12__insert_other_types.sql @@ -14,51 +14,7 @@ * limitations under the License. */ -CREATE TABLE runs.other_types ( - id INT PRIMARY KEY, - ltree_col LTREE, - inet_col INET, - macaddr_col MACADDR, - hstore_col HSTORE, - cidr_col CIDR, - json_col JSON, - jsonb_col JSONB, - uuid_col UUID, - array_col INT[] -); - -INSERT INTO runs.other_types VALUES ( - 1, - 'Top.Science.Astronomy', - '192.168.1.1', - '08:00:2b:01:02:03', - 'key=>value', - '192.168.1/24', - '{"key": "value"}', - '{"key": "value"}', - uuid_generate_v4(), - ARRAY[1,2,3] -); - -CREATE OR REPLACE FUNCTION runs.read_other_types(p_id INT) -RETURNS TABLE( - id INT, - ltree_col LTREE, - inet_col INET, - macaddr_col MACADDR, - hstore_col HSTORE, - cidr_col CIDR, - json_col JSON, - jsonb_col JSONB, - uuid_col UUID, - array_col INT[] -) AS $$ -BEGIN - RETURN QUERY SELECT * FROM runs.other_types T WHERE T.id = p_id; -END; -$$ LANGUAGE plpgsql; - -CREATE OR REPLACE FUNCTION runs.insert_other_types( +CREATE OR REPLACE FUNCTION integration.insert_other_types( p_id INT, p_ltree_col LTREE, p_inet_col INET, @@ -76,7 +32,7 @@ CREATE OR REPLACE FUNCTION runs.insert_other_types( ) AS $$ BEGIN BEGIN - INSERT INTO runs.other_types VALUES ( + INSERT INTO integration.other_types VALUES ( p_id, p_ltree_col, p_inet_col, diff --git a/demo_database/src/main/postgres/integration/V1.2.13__read_other_types.sql b/demo_database/src/main/postgres/integration/V1.2.13__read_other_types.sql new file mode 100644 index 00000000..05685899 --- /dev/null +++ b/demo_database/src/main/postgres/integration/V1.2.13__read_other_types.sql @@ -0,0 +1,33 @@ +/* + * Copyright 2022 ABSA Group Limited + * + * 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. + */ + +CREATE OR REPLACE FUNCTION integration.read_other_types(p_id INT) +RETURNS TABLE( + id INT, + ltree_col LTREE, + inet_col INET, + macaddr_col MACADDR, + hstore_col HSTORE, + cidr_col CIDR, + json_col JSON, + jsonb_col JSONB, + uuid_col UUID, + array_col INT[] +) AS $$ +BEGIN + RETURN QUERY SELECT * FROM integration.other_types T WHERE T.id = p_id; +END; +$$ LANGUAGE plpgsql; diff --git a/slick/src/it/resources/sql/test_function.sql b/demo_database/src/main/postgres/integration/V1.2.14__test_function.sql similarity index 81% rename from slick/src/it/resources/sql/test_function.sql rename to demo_database/src/main/postgres/integration/V1.2.14__test_function.sql index d7ff5a54..ed44acfc 100644 --- a/slick/src/it/resources/sql/test_function.sql +++ b/demo_database/src/main/postgres/integration/V1.2.14__test_function.sql @@ -14,12 +14,7 @@ * limitations under the License. */ - -CREATE EXTENSION IF NOT EXISTS hstore; - -CREATE EXTENSION IF NOT EXISTS ltree; - -CREATE OR REPLACE FUNCTION public.test_function( +CREATE OR REPLACE FUNCTION integration.test_function( IN i_uuid1 UUID, IN i_dateTime1 DATE, IN i_dateTime2 TIME, @@ -46,7 +41,7 @@ CREATE OR REPLACE FUNCTION public.test_function( OUT macaddr1 MACADDR ) RETURNS record AS $$ -------------------------------------------------------------------------------- + ------------------------------------------------------------------------------- -- -- Function: test_function(12) -- A function to test Fa-Db Slick Posgres special time enhancement. Function works as a mirror. Returns what came in. @@ -74,19 +69,4 @@ BEGIN RETURN; END; $$ -LANGUAGE plpgsql VOLATILE SECURITY DEFINER; - -GRANT EXECUTE ON FUNCTION test_function( - UUID, - DATE, - TIME, - TIMESTAMP WITHOUT TIME ZONE, - INTERVAL, - TIMESTAMP WITH TIME ZONE, - TIMESTAMP WITH TIME ZONE, - INT4RANGE, - LTREE, - HSTORE, - INET, - MACADDR - ) TO postgres; + LANGUAGE plpgsql VOLATILE SECURITY DEFINER; diff --git a/demo_database/src/main/postgres/integration/V1.2.1___.ddl b/demo_database/src/main/postgres/integration/V1.2.1___.ddl new file mode 100644 index 00000000..f2c15b10 --- /dev/null +++ b/demo_database/src/main/postgres/integration/V1.2.1___.ddl @@ -0,0 +1,16 @@ +/* + * Copyright 2021 ABSA Group Limited + * + * 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. + */ + +CREATE SCHEMA IF NOT EXISTS integration; diff --git a/doobie/src/it/database/actors.ddl b/demo_database/src/main/postgres/integration/V1.2.2__actors.ddl similarity index 94% rename from doobie/src/it/database/actors.ddl rename to demo_database/src/main/postgres/integration/V1.2.2__actors.ddl index 8e2c1c6a..a3f5112a 100644 --- a/doobie/src/it/database/actors.ddl +++ b/demo_database/src/main/postgres/integration/V1.2.2__actors.ddl @@ -14,7 +14,7 @@ * limitations under the License. */ -CREATE TABLE IF NOT EXISTS runs.actors( +CREATE TABLE IF NOT EXISTS integration.actors( actor_id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, first_name VARCHAR(150) NOT NULL, last_name VARCHAR(150) NOT NULL diff --git a/demo_database/src/main/postgres/integration/V1.2.3__date_time_types.ddl b/demo_database/src/main/postgres/integration/V1.2.3__date_time_types.ddl new file mode 100644 index 00000000..d66068a7 --- /dev/null +++ b/demo_database/src/main/postgres/integration/V1.2.3__date_time_types.ddl @@ -0,0 +1,29 @@ +/* + * Copyright 2022 ABSA Group Limited + * + * 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. + */ + +CREATE TABLE integration.date_time_types ( + id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + offset_date_time TIMESTAMPTZ, + instant TIMESTAMPTZ, + zoned_date_time TIMESTAMPTZ, + local_date_time TIMESTAMP, + local_date DATE, + local_time TIME, + sql_date DATE, + sql_time TIME, + sql_timestamp TIMESTAMP, + util_date TIMESTAMP +); diff --git a/demo_database/src/main/postgres/integration/V1.2.4__other_types.ddl b/demo_database/src/main/postgres/integration/V1.2.4__other_types.ddl new file mode 100644 index 00000000..2c160a10 --- /dev/null +++ b/demo_database/src/main/postgres/integration/V1.2.4__other_types.ddl @@ -0,0 +1,28 @@ +/* + * Copyright 2022 ABSA Group Limited + * + * 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. + */ + +CREATE TABLE integration.other_types ( + id INT PRIMARY KEY, + ltree_col LTREE, + inet_col INET, + macaddr_col MACADDR, + hstore_col HSTORE, + cidr_col CIDR, + json_col JSON, + jsonb_col JSONB, + uuid_col UUID, + array_col INT[] +); diff --git a/doobie/src/it/database/create_actor.sql b/demo_database/src/main/postgres/integration/V1.2.5__create_actor.sql similarity index 83% rename from doobie/src/it/database/create_actor.sql rename to demo_database/src/main/postgres/integration/V1.2.5__create_actor.sql index 24fb50fe..5fb07408 100644 --- a/doobie/src/it/database/create_actor.sql +++ b/demo_database/src/main/postgres/integration/V1.2.5__create_actor.sql @@ -14,8 +14,8 @@ * limitations under the License. */ --- Function: runs.create_actor(TEXT, TEXT) --- This function creates a new actor in the 'runs.actors' table. +-- Function: integration.create_actor(TEXT, TEXT) +-- This function creates a new actor in the 'integration.actors' table. -- Parameters: -- i_first_name (IN): The first name of the actor. @@ -29,9 +29,9 @@ -- A record containing the status and status text of the operation. -- Example: --- SELECT * FROM runs.create_actor('John', 'Doe'); +-- SELECT * FROM integration.create_actor('John', 'Doe'); -CREATE OR REPLACE FUNCTION runs.create_actor( +CREATE OR REPLACE FUNCTION integration.create_actor( IN i_first_name TEXT, IN i_last_name TEXT, OUT status INTEGER, @@ -40,7 +40,7 @@ CREATE OR REPLACE FUNCTION runs.create_actor( ) RETURNS record AS $$ BEGIN - INSERT INTO runs.actors(first_name, last_name) + INSERT INTO integration.actors(first_name, last_name) VALUES (i_first_name, i_last_name) RETURNING actor_id INTO o_actor_id; diff --git a/doobie/src/it/database/get_actors.sql b/demo_database/src/main/postgres/integration/V1.2.6__get_actors.sql similarity index 92% rename from doobie/src/it/database/get_actors.sql rename to demo_database/src/main/postgres/integration/V1.2.6__get_actors.sql index bdf11186..14238b0a 100644 --- a/doobie/src/it/database/get_actors.sql +++ b/demo_database/src/main/postgres/integration/V1.2.6__get_actors.sql @@ -14,7 +14,7 @@ * limitations under the License. */ -CREATE OR REPLACE FUNCTION runs.get_actors( +CREATE OR REPLACE FUNCTION integration.get_actors( i_first_name TEXT, i_last_name TEXT ) RETURNS TABLE ( @@ -25,7 +25,7 @@ CREATE OR REPLACE FUNCTION runs.get_actors( $$ BEGIN RETURN QUERY SELECT A.actor_id, A.first_name, A.last_name - FROM runs.actors A + FROM integration.actors A WHERE (i_first_name IS NULL OR A.first_name = i_first_name) AND diff --git a/demo_database/src/main/postgres/integration/V1.2.7__get_actors_by_lastname.sql b/demo_database/src/main/postgres/integration/V1.2.7__get_actors_by_lastname.sql new file mode 100644 index 00000000..9424c643 --- /dev/null +++ b/demo_database/src/main/postgres/integration/V1.2.7__get_actors_by_lastname.sql @@ -0,0 +1,64 @@ +/* + * Copyright 2022 ABSA Group Limited + * + * 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. + */ + +CREATE OR REPLACE FUNCTION integration.get_actors_by_lastname( + IN i_last_name TEXT, + IN i_first_name TEXT = NULL, + + OUT status INTEGER, + OUT status_text TEXT, + + OUT actor_id INT, + OUT first_name character varying(150), + OUT last_name character varying(150) +) RETURNS SETOF record AS +$$ +DECLARE +BEGIN + + IF i_first_name IS NULL THEN + status := 11; + status_text := 'OK, match on last name only'; + + RETURN QUERY + SELECT status, status_text, + A.actor_id, A.first_name, A.last_name + FROM integration.actors AS A + WHERE A.last_name = i_last_name; + + ELSE + status := 12; + status_text := 'OK, full match'; + + RETURN QUERY + SELECT status, status_text, + A.actor_id, A.first_name, A.last_name + FROM integration.actors AS A + WHERE A.first_name = i_first_name + AND A.last_name = i_last_name; + + END IF; + + IF NOT FOUND THEN + status := 41; + status_text := 'No actor found'; + RETURN NEXT; + RETURN; + END IF; + +END; +$$ +LANGUAGE plpgsql; diff --git a/doobie/src/it/database/get_actor_by_id.sql b/demo_database/src/main/postgres/integration/V1.2.8__get_actor_by_id.sql similarity index 82% rename from doobie/src/it/database/get_actor_by_id.sql rename to demo_database/src/main/postgres/integration/V1.2.8__get_actor_by_id.sql index 22df6fe0..64c81df7 100644 --- a/doobie/src/it/database/get_actor_by_id.sql +++ b/demo_database/src/main/postgres/integration/V1.2.8__get_actor_by_id.sql @@ -15,10 +15,10 @@ */ /* - * Function: runs.get_actor_by_id + * Function: integration.get_actor_by_id * * Description: - * This function retrieves an actor from the 'runs.actors' table by their ID. + * This function retrieves an actor from the 'integration.actors' table by their ID. * * Parameters: * i_actor_id - The ID of the actor to retrieve. @@ -30,11 +30,12 @@ * last_name - The last name of the actor. * * Example: - * SELECT * FROM runs.get_actor_by_id(1); + * SELECT * FROM integration.get_actor_by_id(1); * * This will return the actor with ID 1, if he/she exists. */ -CREATE OR REPLACE FUNCTION runs.get_actor_by_id( + +CREATE OR REPLACE FUNCTION integration.get_actor_by_id( i_actor_id INTEGER ) RETURNS TABLE ( actor_id INTEGER, @@ -44,7 +45,7 @@ CREATE OR REPLACE FUNCTION runs.get_actor_by_id( $$ BEGIN RETURN QUERY SELECT A.actor_id, A.first_name, A.last_name - FROM runs.actors A + FROM integration.actors A WHERE A.actor_id = i_actor_id; END; $$ diff --git a/demo_database/src/main/postgres/integration/V1.2.99__insert_test_data.sql b/demo_database/src/main/postgres/integration/V1.2.99__insert_test_data.sql new file mode 100644 index 00000000..a8351354 --- /dev/null +++ b/demo_database/src/main/postgres/integration/V1.2.99__insert_test_data.sql @@ -0,0 +1,49 @@ +/* + * Copyright 2022 ABSA Group Limited + * + * 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. + */ + +INSERT INTO integration.actors VALUES + (49, 'Pavel', 'Marek'), + (50, 'Liza', 'Simpson'); + + +INSERT INTO integration.other_types VALUES ( + 1, + 'Top.Science.Astronomy', + '192.168.1.1', + '08:00:2b:01:02:03', + 'key=>value', + '192.168.1/24', + '{"key": "value"}', + '{"key": "value"}', + 'b574cb0f-4790-4798-9b3f-824c7fab69dc', + ARRAY[1,2,3] +); + +INSERT INTO integration.date_time_types ( + offset_date_time, instant, zoned_date_time, local_date_time, local_date, local_time, + sql_date, sql_time, sql_timestamp, util_date +) VALUES ( + '2004-10-19 10:23:54+02', + '2004-10-19 10:23:54+02', + '2004-10-19 10:23:54+02', + '2004-10-19 10:23:54', + '2004-10-19', + '10:23:54', + '2004-10-19', + '10:23:54', + '2004-10-19 10:23:54', + '2004-10-19 10:23:54' +); diff --git a/doobie/src/it/database/error_if_not_one.sql b/demo_database/src/main/postgres/integration/V1.2.9__error_if_not_one.sql similarity index 93% rename from doobie/src/it/database/error_if_not_one.sql rename to demo_database/src/main/postgres/integration/V1.2.9__error_if_not_one.sql index 8f29a6af..dcef4093 100644 --- a/doobie/src/it/database/error_if_not_one.sql +++ b/demo_database/src/main/postgres/integration/V1.2.9__error_if_not_one.sql @@ -14,7 +14,7 @@ * limitations under the License. */ -CREATE OR REPLACE FUNCTION runs.error_if_not_one(p_input INT) +CREATE OR REPLACE FUNCTION integration.error_if_not_one(p_input INT) RETURNS TABLE( status INT, status_text TEXT, diff --git a/doobie/src/it/README.md b/doobie/src/it/README.md deleted file mode 100644 index b631da74..00000000 --- a/doobie/src/it/README.md +++ /dev/null @@ -1,6 +0,0 @@ -### How to do testing - -In order to execute tests in this module you need to: -- deploy all sql code from database folder into postgres instance of your choice -- make sure you have data in your tables as tests expect populated tables (unfortunately as this point this is not automated) -- set up connection to your database in DoobieTest trait \ No newline at end of file diff --git a/doobie/src/it/database/dates_times.sql b/doobie/src/it/database/dates_times.sql deleted file mode 100644 index 84602104..00000000 --- a/doobie/src/it/database/dates_times.sql +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2022 ABSA Group Limited - * - * 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. - */ - -CREATE TABLE runs.date_time_types ( - id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - offset_date_time TIMESTAMPTZ, - instant TIMESTAMPTZ, - zoned_date_time TIMESTAMPTZ, - local_date_time TIMESTAMP, - local_date DATE, - local_time TIME, - sql_date DATE, - sql_time TIME, - sql_timestamp TIMESTAMP, - util_date TIMESTAMP -); - -INSERT INTO runs.date_time_types ( - offset_date_time, instant, zoned_date_time, local_date_time, local_date, local_time, - sql_date, sql_time, sql_timestamp, util_date -) VALUES ( - '2004-10-19 10:23:54+02', - '2004-10-19 10:23:54+02', - '2004-10-19 10:23:54+02', - '2004-10-19 10:23:54', - '2004-10-19', - '10:23:54', - '2004-10-19', - '10:23:54', - '2004-10-19 10:23:54', - '2004-10-19 10:23:54' -); - - -CREATE OR REPLACE FUNCTION runs.get_all_date_time_types(p_id INT) - RETURNS TABLE( - offset_date_time TIMESTAMPTZ, - instant TIMESTAMPTZ, - zoned_date_time TIMESTAMPTZ, - local_date_time TIMESTAMP, - local_date DATE, - local_time TIME, - sql_date DATE, - sql_time TIME, - sql_timestamp TIMESTAMP, - util_date TIMESTAMP - ) AS $$ -BEGIN - RETURN QUERY SELECT - T.offset_date_time, - T.instant, - T.zoned_date_time, - T.local_date_time, - T.local_date, - T.local_time, - T.sql_date, - T.sql_time, - T.sql_timestamp, - T.util_date - FROM runs.date_time_types T limit p_id; -END; -$$ LANGUAGE plpgsql; - -CREATE OR REPLACE FUNCTION runs.insert_dates_times( - IN p_offset_date_time TIMESTAMPTZ, - IN p_instant TIMESTAMPTZ, - IN p_zoned_date_time TIMESTAMPTZ, - IN p_local_date_time TIMESTAMP, - IN p_local_date DATE, - IN p_local_time TIME, - IN p_sql_date DATE, - IN p_sql_time TIME, - IN p_sql_timestamp TIMESTAMP, - IN p_util_date DATE, - OUT status INTEGER, - OUT status_text TEXT, - OUT o_id INTEGER -) RETURNS record AS $$ -BEGIN - INSERT INTO runs.date_time_types ( - offset_date_time, - instant, - zoned_date_time, - local_date_time, - local_date, - local_time, - sql_date, - sql_time, - sql_timestamp, - util_date - ) VALUES ( - p_offset_date_time, - p_instant, - p_zoned_date_time, - p_local_date_time, - p_local_date, - p_local_time, - p_sql_date, - p_sql_time, - p_sql_timestamp, - p_util_date - ) RETURNING id INTO o_id; - - status := 11; - status_text := 'OK'; - - RETURN; -END; -$$ LANGUAGE plpgsql; diff --git a/doobie/src/it/scala/za/co/absa/fadb/doobie/DatesTimesTest.scala b/doobie/src/it/scala/za/co/absa/fadb/doobie/DatesTimesTest.scala index 65aff262..19a3f928 100644 --- a/doobie/src/it/scala/za/co/absa/fadb/doobie/DatesTimesTest.scala +++ b/doobie/src/it/scala/za/co/absa/fadb/doobie/DatesTimesTest.scala @@ -64,8 +64,8 @@ class DatesTimesTest extends AnyFunSuite with DoobieTest { override def fieldsToSelect: Seq[String] = super.fieldsToSelect ++ Seq("o_id") } - private val getAllDateTimeTypes = new GetAllDateTimeTypes()(Runs, new DoobieEngine(transactor)) - private val insertDatesTimes = new InsertDatesTimes()(Runs, new DoobieEngine(transactor)) + private val getAllDateTimeTypes = new GetAllDateTimeTypes()(Integration, new DoobieEngine(transactor)) + private val insertDatesTimes = new InsertDatesTimes()(Integration, new DoobieEngine(transactor)) test("Reading different date/time types from the database") { val offsetDateTime = java.time.OffsetDateTime.parse("2004-10-19T08:23:54Z") diff --git a/doobie/src/it/scala/za/co/absa/fadb/doobie/DoobieMultipleResultFunctionTest.scala b/doobie/src/it/scala/za/co/absa/fadb/doobie/DoobieMultipleResultFunctionTest.scala index 77a4f6bf..c2819d3a 100644 --- a/doobie/src/it/scala/za/co/absa/fadb/doobie/DoobieMultipleResultFunctionTest.scala +++ b/doobie/src/it/scala/za/co/absa/fadb/doobie/DoobieMultipleResultFunctionTest.scala @@ -49,7 +49,7 @@ class DoobieMultipleResultFunctionTest extends AnyFunSuite with DoobieTest { class GetActors(implicit schema: DBSchema, dbEngine: DoobieEngine[IO]) extends DoobieMultipleResultFunction[GetActorsQueryParameters, Actor, IO](combinedUsingSemigroup) - private val getActors = new GetActors()(Runs, new DoobieEngine(transactor)) + private val getActors = new GetActors()(Integration, new DoobieEngine(transactor)) test("Retrieving actor from database") { val expectedResultElem = Actor(49, "Pavel", "Marek") diff --git a/doobie/src/it/scala/za/co/absa/fadb/doobie/DoobieOptionalResultFunctionTest.scala b/doobie/src/it/scala/za/co/absa/fadb/doobie/DoobieOptionalResultFunctionTest.scala index e3682aa5..22fe00f3 100644 --- a/doobie/src/it/scala/za/co/absa/fadb/doobie/DoobieOptionalResultFunctionTest.scala +++ b/doobie/src/it/scala/za/co/absa/fadb/doobie/DoobieOptionalResultFunctionTest.scala @@ -28,11 +28,11 @@ class DoobieOptionalResultFunctionTest extends AnyFunSuite with DoobieTest { class GetActorById(implicit schema: DBSchema, dbEngine: DoobieEngine[IO]) extends DoobieOptionalResultFunction[Int, Actor, IO](id => Seq(fr"$id")) - private val createActor = new GetActorById()(Runs, new DoobieEngine(transactor)) + private val getActorById = new GetActorById()(Integration, new DoobieEngine(transactor)) test("Retrieve actor by id from database") { val expectedResult = Some(Actor(49, "Pavel", "Marek")) - val result = createActor(49).unsafeRunSync() + val result = getActorById(49).unsafeRunSync() assert(expectedResult == result) } diff --git a/doobie/src/it/scala/za/co/absa/fadb/doobie/DoobieOtherTypesTest.scala b/doobie/src/it/scala/za/co/absa/fadb/doobie/DoobieOtherTypesTest.scala index 042d856e..8c724536 100644 --- a/doobie/src/it/scala/za/co/absa/fadb/doobie/DoobieOtherTypesTest.scala +++ b/doobie/src/it/scala/za/co/absa/fadb/doobie/DoobieOtherTypesTest.scala @@ -68,8 +68,8 @@ class DoobieOtherTypesTest extends AnyFunSuite with DoobieTest { override def fieldsToSelect: Seq[String] = super.fieldsToSelect ++ Seq("o_id") } - private val readOtherTypes = new ReadOtherTypes()(Runs, new DoobieEngine(transactor)) - private val insertOtherTypes = new InsertOtherTypes()(Runs, new DoobieEngine(transactor)) + private val readOtherTypes = new ReadOtherTypes()(Integration, new DoobieEngine(transactor)) + private val insertOtherTypes = new InsertOtherTypes()(Integration, new DoobieEngine(transactor)) test("Reading other common data types from database") { val expectedData = OtherTypesData( @@ -101,7 +101,7 @@ class DoobieOtherTypesTest extends AnyFunSuite with DoobieTest { test("Writing other common data types to database") { val data = OtherTypesData( - id = 3, + id = 1, ltreeCol = "Top.Science.Astronomy", inetCol = InetAddress.getByName("192.168.1.1"), macaddrCol = "08:00:2b:01:02:03", diff --git a/doobie/src/it/scala/za/co/absa/fadb/doobie/DoobieSingleResultFunctionTest.scala b/doobie/src/it/scala/za/co/absa/fadb/doobie/DoobieSingleResultFunctionTest.scala index 4eb8f9d1..bd56a37e 100644 --- a/doobie/src/it/scala/za/co/absa/fadb/doobie/DoobieSingleResultFunctionTest.scala +++ b/doobie/src/it/scala/za/co/absa/fadb/doobie/DoobieSingleResultFunctionTest.scala @@ -35,7 +35,7 @@ class DoobieSingleResultFunctionTest extends AnyFunSuite with DoobieTest { override def fieldsToSelect: Seq[String] = super.fieldsToSelect ++ Seq("o_actor_id") } - private val createActor = new CreateActor()(Runs, new DoobieEngine(transactor)) + private val createActor = new CreateActor()(Integration, new DoobieEngine(transactor)) test("Inserting an actor into database & handling an error") { val result = createActor(CreateActorRequestBody("Pavel", "Marek")).handleErrorWith(_ => IO(Int.MaxValue)).unsafeRunSync() diff --git a/doobie/src/it/scala/za/co/absa/fadb/doobie/DoobieSingleResultFunctionWithStatusTest.scala b/doobie/src/it/scala/za/co/absa/fadb/doobie/DoobieSingleResultFunctionWithStatusTest.scala index ac0ffbc4..47fd926d 100644 --- a/doobie/src/it/scala/za/co/absa/fadb/doobie/DoobieSingleResultFunctionWithStatusTest.scala +++ b/doobie/src/it/scala/za/co/absa/fadb/doobie/DoobieSingleResultFunctionWithStatusTest.scala @@ -52,8 +52,8 @@ class DoobieSingleResultFunctionWithStatusTest extends AnyFunSuite with DoobieTe override def fieldsToSelect: Seq[String] = super.fieldsToSelect ++ Seq("input_value") } - private val createActor = new CreateActor()(Runs, new DoobieEngine(transactor)) - private val errorIfNotOne = new ErrorIfNotOne()(Runs, new DoobieEngine(transactor)) + private val createActor = new CreateActor()(Integration, new DoobieEngine(transactor)) + private val errorIfNotOne = new ErrorIfNotOne()(Integration, new DoobieEngine(transactor)) test("Creating actor within a function with status handling") { val requestBody = CreateActorRequestBody("Pavel", "Marek") @@ -72,14 +72,14 @@ class DoobieSingleResultFunctionWithStatusTest extends AnyFunSuite with DoobieTe } test("Unsuccessful function call with status handling. Asserting on error when Int wrapped in Option") { - val errorIfNotOne = new ErrorIfNotOneWithStatus("error_if_not_one")(Runs, new DoobieEngine(transactor)) + val errorIfNotOne = new ErrorIfNotOneWithStatus("error_if_not_one")(Integration, new DoobieEngine(transactor)) val result = errorIfNotOne(2).unsafeRunSync() assert(result.isLeft) } test("Successful function call with status handling. Asserting on success when Int wrapped in Option") { - val errorIfNotOne = new ErrorIfNotOneWithStatus("error_if_not_one")(Runs, new DoobieEngine(transactor)) + val errorIfNotOne = new ErrorIfNotOneWithStatus("error_if_not_one")(Integration, new DoobieEngine(transactor)) val result = errorIfNotOne(1).unsafeRunSync() result match { diff --git a/doobie/src/it/scala/za/co/absa/fadb/doobie/DoobieTest.scala b/doobie/src/it/scala/za/co/absa/fadb/doobie/DoobieTest.scala index 36f5c5f9..fe13f1aa 100644 --- a/doobie/src/it/scala/za/co/absa/fadb/doobie/DoobieTest.scala +++ b/doobie/src/it/scala/za/co/absa/fadb/doobie/DoobieTest.scala @@ -27,7 +27,7 @@ trait DoobieTest { case class CreateActorRequestBody(firstName: String, lastName: String) import za.co.absa.fadb.naming.implementations.SnakeCaseNaming.Implicits._ - object Runs extends DBSchema + object Integration extends DBSchema protected val transactor: Aux[IO, Unit] = Transactor.fromDriverManager[IO]( "org.postgresql.Driver", diff --git a/doobie/zio-setup.md b/doobie/zio-setup.md index 648205db..351d038b 100644 --- a/doobie/zio-setup.md +++ b/doobie/zio-setup.md @@ -22,7 +22,7 @@ object GetActorById { val layer: ZLayer[PostgresDatabaseProvider, Nothing, GetActorById] = ZLayer { for { dbProvider <- ZIO.service[PostgresDatabaseProvider] - } yield new GetActorById()(Runs, dbProvider.dbEngine) + } yield new GetActorById()(Integration, dbProvider.dbEngine) } } ``` diff --git a/examples/src/main/resources/application.conf b/examples/src/main/resources/application.conf deleted file mode 100644 index a1ffc09a..00000000 --- a/examples/src/main/resources/application.conf +++ /dev/null @@ -1,12 +0,0 @@ -menasdb = { - connectionPool = "HikariCP" //use HikariCP for our connection pool - dataSourceClass = "org.postgresql.ds.PGSimpleDataSource" //Simple datasource with no connection pooling. The connection pool has already been specified with HikariCP. - properties = { - serverName = "localhost" - portNumber = "5432" - databaseName = "menas_db" - user = "menas" - password = "menas" - } - numThreads = 10 -} diff --git a/examples/src/main/scala/za/co/absa/fadb/examples/enceladus/DatasetSchema.scala b/examples/src/main/scala/za/co/absa/fadb/examples/enceladus/DatasetSchema.scala deleted file mode 100644 index 1245184a..00000000 --- a/examples/src/main/scala/za/co/absa/fadb/examples/enceladus/DatasetSchema.scala +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2022 ABSA Group Limited - * - * 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 za.co.absa.fadb.examples.enceladus - -import cats.MonadError -import slick.jdbc.PostgresProfile.api._ -import slick.jdbc.{GetResult, SQLActionBuilder} -import za.co.absa.fadb.DBSchema -import za.co.absa.fadb.examples.enceladus.DatasetSchema._ -import za.co.absa.fadb.naming.implementations.SnakeCaseNaming.Implicits.namingConvention -import za.co.absa.fadb.slick.SlickFunction.{SlickMultipleResultFunction, SlickSingleResultFunctionWithStatus} -import za.co.absa.fadb.slick.SlickPgEngine -import za.co.absa.fadb.status.handling.implementations.UserDefinedStatusHandling - -import java.sql.Timestamp -import scala.concurrent.ExecutionContext.Implicits.global -import scala.concurrent.Future - -/* The Schema doesn't need the dBEngine directly, but it seems cleaner this way to hand it over to schema's functions */ -class DatasetSchema(implicit engine: SlickPgEngine) extends DBSchema { - - val addSchema = new AddSchema - val getSchema = new GetSchema - val list = new List -} - - -object DatasetSchema { - - case class SchemaInput(schemaName: String, - schemaVersion: Int, - schemaDescription: Option[String], - fields: Option[String], - userName: String) - - case class Schema(idSchemaVersion: Long, - schemaName: String, - schemaVersion: Int, - schemaDescription: Option[String], - fields: Option[String], - createdBy: String, - createdWhen: Timestamp, - updatedBy: String, - updatedWhen: Timestamp, - lockedBy: Option[String], - lockedWhen: Option[Timestamp], - deletedBy: Option[String], - deletedWhen: Option[Timestamp]) - - case class SchemaHeader(entityName: String, entityLatestVersion: Int) - - final class AddSchema(implicit override val schema: DBSchema, val dbEngine: SlickPgEngine) - extends SlickSingleResultFunctionWithStatus[SchemaInput, Long] - with UserDefinedStatusHandling { - - override protected def sql(values: SchemaInput): SQLActionBuilder = { - sql"""SELECT A.status, A.status_text, A.id_schema_version - FROM #$functionName(${values.schemaName}, ${values.schemaVersion}, ${values.schemaDescription}, - ${values.fields}::JSONB, ${values.userName} - ) A;""" - } - - override protected def slickConverter: GetResult[Long] = GetResult.GetLong - - override def OKStatuses: Set[Integer] = Set(201) - } - - final class GetSchema(implicit override val schema: DBSchema, val dbEngine: SlickPgEngine) - extends SlickSingleResultFunctionWithStatus[(String, Option[Int]), Schema] - with UserDefinedStatusHandling { - - /* This is an example of how to deal with overloaded DB functions - see different input type: Long vs what's in the class type: (String, Option[Int]) */ - def apply(id: Long): Future[Schema] = { - val sql = - sql"""SELECT A.* - FROM #$functionName($id) A;""" - - val slickQuery = new dBEngine.QueryType(sql, slickConverter) - dBEngine.fetchHead[Schema](slickQuery) - } - - override protected def sql(values: (String, Option[Int])): SQLActionBuilder = { - sql"""SELECT A.* - FROM #$functionName(${values._1}, ${values._2}) A;""" - } - - override protected val slickConverter: GetResult[Schema] = GetResult{r => - Schema(r.<<, r.<<, r.<<, r.<<, r.<<, r.<<, r.<<, r.<<, r.<<, r.<<, r.<<, r.<<, r.<<) - } - - override val OKStatuses: Set[Integer] = Set(200) - } - - final class List(implicit override val schema: DBSchema, val dbEngine: SlickPgEngine) - extends SlickMultipleResultFunction[Boolean, SchemaHeader] { - - override def apply(values: Boolean = false)(implicit me: MonadError[Future, Throwable]): Future[Seq[SchemaHeader]] = super.apply(values) - - override protected def sql(values: Boolean): SQLActionBuilder = { - sql"""SELECT A.entity_name, A.entity_latest_version - FROM #$functionName($values) as A;""" - } - - override protected val slickConverter: GetResult[SchemaHeader] = GetResult(r => {SchemaHeader(r.<<, r.<<)}) - } -} diff --git a/examples/src/test/resources/application.conf b/examples/src/test/resources/application.conf deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/src/test/scala/za/co/absa/fadb/examples/enceladus/DatasetSchemaSuite.scala b/examples/src/test/scala/za/co/absa/fadb/examples/enceladus/DatasetSchemaSuite.scala deleted file mode 100644 index 3acb5958..00000000 --- a/examples/src/test/scala/za/co/absa/fadb/examples/enceladus/DatasetSchemaSuite.scala +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2022 ABSA Group Limited - * - * 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 za.co.absa.fadb.examples.enceladus - -import org.scalatest.matchers.should.Matchers -import org.scalatest.wordspec.AnyWordSpec -import za.co.absa.fadb.examples.enceladus.DatasetSchema._ -import slick.jdbc.PostgresProfile.api._ -import za.co.absa.fadb.exceptions.StatusException -import za.co.absa.fadb.slick.SlickPgEngine - -import scala.concurrent.Await -import scala.concurrent.duration.Duration -import scala.concurrent.ExecutionContext.Implicits.global - -class DatasetSchemaSuite extends AnyWordSpec with Matchers { - private val db = Database.forConfig("menasdb") - private implicit val dbEngine: SlickPgEngine = new SlickPgEngine(db) - private val schemas = new DatasetSchema - - private def checkException(exception: StatusException): Unit = { - println(s"Requested failed with: ${exception.status.statusCode} - ${exception.status.statusText}") - } - - // test cases are set to be ignored now, as they are not idempotent and require other project's (Enceladus) data structures - - "listSchemas" ignore { - "list the schemas" should { - val ls = schemas.list() - val result = Await.result(ls, Duration.Inf) - result.foreach(println) - } - } - - "getSchema" ignore { - "return the particular schema" when { - "given name and version" should { - val ls = schemas.getSchema(("aaa", Option(1))) - val result = Await.result(ls, Duration.Inf) - println(result) - } - "given id" should { - val gs = schemas.getSchema(1000000000000051L) - val result = Await.result(gs, Duration.Inf) - println(result) - } - } - "return the latest schema version" when { - "only the schema name is given" should { - val ls = schemas.getSchema(("aaa", None)) - val result = Await.result(ls, Duration.Inf) - println(result) - } - } - "fail" when { - "schema does not exist" should { - val exception = intercept[StatusException] { - val gs = schemas.getSchema(("xxx", None)) - Await.result(gs, Duration.Inf) - } - checkException(exception) - } - "requested schema version does not exist" should { - val exception = intercept[StatusException] { - val gs = schemas.getSchema(("aaa", Some(1000))) - Await.result(gs, Duration.Inf) - } - checkException(exception) - } - } - } - - "addSchema" ignore { - "add a schema" should { - val schemaInput = SchemaInput( - schemaName = "bbe", - schemaVersion = 1, - schemaDescription = Option("Hello World"), - fields = Option("""{"lorem": "ipsum"}"""), - userName = "david" - ) - val result = Await.result(schemas.addSchema(schemaInput), Duration.Inf) - println(result) - } - "fail" when { - "Schema already exists" should { - val schemaInput = SchemaInput( - schemaName = "aaa", - schemaVersion = 2, - schemaDescription = Option("Updates"), - fields = Option("""{"foo": "bar"}"""), - userName = "david" - ) - val exception = intercept[StatusException] { - Await.result(schemas.addSchema(schemaInput), Duration.Inf) - } - checkException(exception) - } - "Schema version wrong" should { - val schemaInput = SchemaInput( - schemaName = "aaa", - schemaVersion = 1000, - schemaDescription = Option("Will fail"), - fields = Option("""{"not_getting_in": "1"}"""), - userName = "david" - ) - val exception = intercept[StatusException] { - Await.result(schemas.addSchema(schemaInput), Duration.Inf) - } - checkException(exception) - } - } - } -} diff --git a/project/Dependencies.scala b/project/Dependencies.scala index c1e9ca12..d9e1048d 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -19,8 +19,8 @@ import sbt._ object Dependencies { private def commonDependencies(scalaVersion: String): Seq[ModuleID] = Seq( - "org.typelevel" %% "cats-core" % "2.9.0", - "org.typelevel" %% "cats-effect" % "3.5.0", + "org.typelevel" %% "cats-core" % "2.9.0", + "org.typelevel" %% "cats-effect" % "3.5.0", "org.scalatest" %% "scalatest" % "3.1.0" % "test,it", "org.scalatest" %% "scalatest-flatspec" % "3.2.0" % "test,it", "org.scalatestplus" %% "mockito-1-10" % "3.1.0.0" % "test,it" @@ -51,7 +51,9 @@ object Dependencies { ) } - def examplesDependencies(scalaVersion: String): Seq[ModuleID] = { - slickDependencies(scalaVersion) + def flywayDependencies: Seq[ModuleID] = { + val postgresql = "org.postgresql" % "postgresql" % "42.6.0" + + Seq(postgresql) } } diff --git a/project/FlywayConfiguration.scala b/project/FlywayConfiguration.scala new file mode 100644 index 00000000..d3be4efe --- /dev/null +++ b/project/FlywayConfiguration.scala @@ -0,0 +1,28 @@ +/* + * Copyright 2021 ABSA Group Limited + * + * 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. + */ + +object FlywayConfiguration { + + private val port = 5432 + private val host = "localhost" + private val database = "movies" + val flywayUrl = s"jdbc:postgresql://$host:$port/$database" + val flywayUser = "postgres" + val flywayPassword = "postgres" + val flywayLocations: Seq[String] = Seq("filesystem:demo_database/src/main/postgres") + val flywaySqlMigrationSuffixes: Seq[String] = Seq(".sql",".ddl") + +} diff --git a/project/plugins.sbt b/project/plugins.sbt index 5357c675..832944e7 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -39,3 +39,5 @@ addSbtPlugin("org.ow2.asm" % "asm-tree" % ow2Version from ow2Url("asm-tree")) addSbtPlugin("za.co.absa.sbt" % "sbt-jacoco" % "3.4.1-absa.4" from "https://github.com/AbsaOSS/sbt-jacoco/releases/download/3.4.1-absa.3/sbt-jacoco-3.4.1-absa.3.jar") addSbtPlugin("com.thoughtworks.sbt-api-mappings" % "sbt-api-mappings" % "3.0.2") + +addSbtPlugin("io.github.davidmweber" % "flyway-sbt" % "7.4.0") diff --git a/slick/src/it/README.md b/slick/src/it/README.md deleted file mode 100644 index 8ae6da96..00000000 --- a/slick/src/it/README.md +++ /dev/null @@ -1,6 +0,0 @@ -### How to do testing - -In order to execute tests in this module you need to: -- deploy all sql code from database folder into postgres instance of your choice -- make sure you have data in your tables as tests expect populated tables (unfortunately as this point this is not automated) -- set up connection to your database in application.conf file in resources folder \ No newline at end of file diff --git a/slick/src/it/scala/za/co/absa/fadb/slick/FaDbPostgresProfileSuite.scala b/slick/src/it/scala/za/co/absa/fadb/slick/FaDbPostgresProfileSuite.scala index 8659cb7e..db56b553 100644 --- a/slick/src/it/scala/za/co/absa/fadb/slick/FaDbPostgresProfileSuite.scala +++ b/slick/src/it/scala/za/co/absa/fadb/slick/FaDbPostgresProfileSuite.scala @@ -89,7 +89,7 @@ class FaDbPostgresProfileSuite extends AsyncFlatSpec { } } - class TestSchema(implicit dBEngine: SlickPgEngine) extends DBSchema("public") { + class TestSchema(implicit dBEngine: SlickPgEngine) extends DBSchema("integration") { val testFunction = new TestFunction } @@ -171,7 +171,7 @@ class FaDbPostgresProfileSuite extends AsyncFlatSpec { } } - class TestSchema(implicit dBEngine: SlickPgEngine) extends DBSchema("public") { + class TestSchema(implicit dBEngine: SlickPgEngine) extends DBSchema("integration") { val testFunction = new TestFunction } diff --git a/slick/src/it/scala/za/co/absa/fadb/slick/SlickMultipleResultFunctionTest.scala b/slick/src/it/scala/za/co/absa/fadb/slick/SlickMultipleResultFunctionTest.scala index 7722b942..5ccd2d46 100644 --- a/slick/src/it/scala/za/co/absa/fadb/slick/SlickMultipleResultFunctionTest.scala +++ b/slick/src/it/scala/za/co/absa/fadb/slick/SlickMultipleResultFunctionTest.scala @@ -41,7 +41,7 @@ class SlickMultipleResultFunctionTest extends AnyFunSuite with SlickTest with Sc } } - private val getActors = new GetActors()(Runs, new SlickPgEngine(db)) + private val getActors = new GetActors()(Integration, new SlickPgEngine(db)) test("Retrieving actors from database") { val expectedResultElem = Actor(49, "Pavel", "Marek") diff --git a/slick/src/it/scala/za/co/absa/fadb/slick/SlickOptionalResultFunctionTest.scala b/slick/src/it/scala/za/co/absa/fadb/slick/SlickOptionalResultFunctionTest.scala index 25129eb2..3a39b531 100644 --- a/slick/src/it/scala/za/co/absa/fadb/slick/SlickOptionalResultFunctionTest.scala +++ b/slick/src/it/scala/za/co/absa/fadb/slick/SlickOptionalResultFunctionTest.scala @@ -38,7 +38,7 @@ class SlickOptionalResultFunctionTest extends AnyFunSuite with SlickTest with Sc } } - private val getActorById = new GetActorById()(Runs, new SlickPgEngine(db)) + private val getActorById = new GetActorById()(Integration, new SlickPgEngine(db)) test("Retrieving an actor by id from database") { val expectedResultElem = Some(Actor(49, "Pavel", "Marek")) diff --git a/slick/src/it/scala/za/co/absa/fadb/slick/SlickSingleResultFunctionWithStatusTest.scala b/slick/src/it/scala/za/co/absa/fadb/slick/SlickSingleResultFunctionWithStatusTest.scala index 44a4412c..3ec3e37c 100644 --- a/slick/src/it/scala/za/co/absa/fadb/slick/SlickSingleResultFunctionWithStatusTest.scala +++ b/slick/src/it/scala/za/co/absa/fadb/slick/SlickSingleResultFunctionWithStatusTest.scala @@ -39,10 +39,10 @@ class SlickSingleResultFunctionWithStatusTest extends AnyFunSuite with SlickTest override protected def slickConverter: GetResult[Int] = GetResult(r => r.<<) } - private val createActor = new CreateActor()(Runs, new SlickPgEngine(db)) + private val createActor = new CreateActor()(Integration, new SlickPgEngine(db)) test("Creating actor with status handling") { - val requestBody = CreateActorRequestBody("Pavel", "Marek") + val requestBody = CreateActorRequestBody("Separated", "TestUser") val result = createActor(requestBody).futureValue assert(result.isRight) } diff --git a/slick/src/it/scala/za/co/absa/fadb/slick/SlickTest.scala b/slick/src/it/scala/za/co/absa/fadb/slick/SlickTest.scala index 01547a48..669e97ed 100644 --- a/slick/src/it/scala/za/co/absa/fadb/slick/SlickTest.scala +++ b/slick/src/it/scala/za/co/absa/fadb/slick/SlickTest.scala @@ -24,7 +24,7 @@ trait SlickTest { case class GetActorsQueryParameters(firstName: Option[String], lastName: Option[String]) import za.co.absa.fadb.naming.implementations.SnakeCaseNaming.Implicits._ - object Runs extends DBSchema + object Integration extends DBSchema val db = Database.forConfig("postgrestestdb") }